diff --git a/README.md b/README.md
index 71c0b3e1..a28e90fb 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ You'll need gzip, git, curl, libssl develop libraries, python and gcc.
- *For Fedora/CentOS*: `yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"`
- *For FreeBSD*: `portinstall node, npm, git (optional)`
-Additionally, you'll need [node.js](http://nodejs.org) installed, Ideally the latest stable version, be careful of installing nodejs from apt.
+Additionally, you'll need [node.js](http://nodejs.org) installed, Ideally the latest stable version, we recommend installing/compiling nodejs from source (avoiding apt).
**As any user (we recommend creating a separate user called etherpad):**
@@ -74,6 +74,10 @@ You can initially modify the settings in `settings.json`. (If you need to handle
You should use a dedicated database such as "mysql", if you are planning on using etherpad-in a production environment, since the "dirtyDB" database driver is only for testing and/or development purposes.
+## Plugins and themes
+
+Etherpad is very customizable through plugins. Instructions for installing themes and plugins can be found in [the plugin wiki article](https://github.com/ether/etherpad-lite/wiki/Available-Plugins).
+
## Helpful resources
The [wiki](https://github.com/ether/etherpad-lite/wiki) is your one-stop resource for Tutorials and How-to's, really check it out! Also, feel free to improve these wiki pages.
diff --git a/settings.json.template b/settings.json.template
index 5868af6a..3f84af9b 100644
--- a/settings.json.template
+++ b/settings.json.template
@@ -74,19 +74,22 @@
/* This is the path to the Abiword executable. Setting it to null, disables abiword.
Abiword is needed to advanced import/export features of pads*/
"abiword" : null,
+
+ /* Allow import of file types other than the supported types: txt, doc, docx, rtf, odt, html & htm */
+ "allowUnknownFileEnds" : true,
/* This setting is used if you require authentication of all users.
Note: /admin always requires authentication. */
- "requireAuthentication": false,
+ "requireAuthentication" : false,
/* Require authorization by a module, or a user with is_admin set, see below. */
- "requireAuthorization": false,
+ "requireAuthorization" : false,
/*when you use NginX or another proxy/ load-balancer set this to true*/
- "trustProxy": false,
+ "trustProxy" : false,
/* Privacy: disable IP logging */
- "disableIPlogging": false,
+ "disableIPlogging" : false,
/* Users for basic authentication. is_admin = true gives access to /admin.
If you do not uncomment this, /admin will not be available! */
diff --git a/src/locales/de.json b/src/locales/de.json
index 05a9af79..25594da1 100644
--- a/src/locales/de.json
+++ b/src/locales/de.json
@@ -12,9 +12,9 @@
"pad.toolbar.bold.title": "Fett (Strg-B)",
"pad.toolbar.italic.title": "Kursiv (Strg-I)",
"pad.toolbar.underline.title": "Unterstrichen (Strg-U)",
- "pad.toolbar.strikethrough.title": "Durchgestrichen",
- "pad.toolbar.ol.title": "Nummerierte Liste",
- "pad.toolbar.ul.title": "Ungeordnete Liste",
+ "pad.toolbar.strikethrough.title": "Durchgestrichen (Strg+5)",
+ "pad.toolbar.ol.title": "Nummerierte Liste (Strg+Shift+N)",
+ "pad.toolbar.ul.title": "Ungeordnete Liste (Strg+Shift+L)",
"pad.toolbar.indent.title": "Einrücken (TAB)",
"pad.toolbar.unindent.title": "Ausrücken (Shift+TAB)",
"pad.toolbar.undo.title": "Rückgängig (Strg-Z)",
diff --git a/src/locales/it.json b/src/locales/it.json
index 8292c4f2..501733f8 100644
--- a/src/locales/it.json
+++ b/src/locales/it.json
@@ -4,7 +4,8 @@
"Beta16",
"Gianfranco",
"Muxator",
- "Vituzzu"
+ "Vituzzu",
+ "Macofe"
]
},
"index.newPad": "Nuovo Pad",
@@ -12,9 +13,9 @@
"pad.toolbar.bold.title": "Grassetto (Ctrl-B)",
"pad.toolbar.italic.title": "Corsivo (Ctrl-I)",
"pad.toolbar.underline.title": "Sottolineato (Ctrl-U)",
- "pad.toolbar.strikethrough.title": "Barrato",
- "pad.toolbar.ol.title": "Elenco numerato",
- "pad.toolbar.ul.title": "Elenco puntato",
+ "pad.toolbar.strikethrough.title": "Barrato (Ctrl+5)",
+ "pad.toolbar.ol.title": "Elenco numerato (Ctrl+Shift+N)",
+ "pad.toolbar.ul.title": "Elenco puntato (Ctrl+Shift+L)",
"pad.toolbar.indent.title": "Rientro (TAB)",
"pad.toolbar.unindent.title": "Riduci rientro (Shift+TAB)",
"pad.toolbar.undo.title": "Annulla (Ctrl-Z)",
diff --git a/src/locales/lb.json b/src/locales/lb.json
index 7f936906..841add75 100644
--- a/src/locales/lb.json
+++ b/src/locales/lb.json
@@ -6,8 +6,8 @@
]
},
"index.newPad": "Neie Pad",
- "pad.toolbar.ol.title": "Numeréiert Lëscht",
- "pad.toolbar.ul.title": "Net-numeréiert Lëscht",
+ "pad.toolbar.ol.title": "Numeréiert Lëscht (Ctrl+Shift+N)",
+ "pad.toolbar.ul.title": "Net-numeréiert Lëscht (Ctrl+Shift+L)",
"pad.toolbar.undo.title": "Réckgängeg (Ctrl-Z)",
"pad.toolbar.redo.title": "Widderhuelen (Ctrl-Y)",
"pad.toolbar.savedRevision.title": "Versioun späicheren",
diff --git a/src/locales/mk.json b/src/locales/mk.json
index 8aaf9917..aec40b27 100644
--- a/src/locales/mk.json
+++ b/src/locales/mk.json
@@ -10,9 +10,9 @@
"pad.toolbar.bold.title": "Задебелено (Ctrl-B)",
"pad.toolbar.italic.title": "Косо (Ctrl-I)",
"pad.toolbar.underline.title": "Подвлечено (Ctrl-U)",
- "pad.toolbar.strikethrough.title": "Прецртано",
- "pad.toolbar.ol.title": "Подреден список",
- "pad.toolbar.ul.title": "Неподреден список",
+ "pad.toolbar.strikethrough.title": "Прецртано (Ctrl+5)",
+ "pad.toolbar.ol.title": "Подреден список (Ctrl+Shift+N)",
+ "pad.toolbar.ul.title": "Неподреден список (Ctrl+Shift+L)",
"pad.toolbar.indent.title": "Вовлекување (TAB)",
"pad.toolbar.unindent.title": "Отстап (Shift+TAB)",
"pad.toolbar.undo.title": "Врати (Ctrl-Z)",
diff --git a/src/locales/sv.json b/src/locales/sv.json
index 623def9a..ab6f3820 100644
--- a/src/locales/sv.json
+++ b/src/locales/sv.json
@@ -11,9 +11,9 @@
"pad.toolbar.bold.title": "Fet (Ctrl-B)",
"pad.toolbar.italic.title": "Kursiv (Ctrl-I)",
"pad.toolbar.underline.title": "Understruken (Ctrl-U)",
- "pad.toolbar.strikethrough.title": "Genomstruken",
- "pad.toolbar.ol.title": "Numrerad lista",
- "pad.toolbar.ul.title": "Osorterad lista",
+ "pad.toolbar.strikethrough.title": "Genomstruken (Ctrl+5)",
+ "pad.toolbar.ol.title": "Numrerad lista (Ctrl+Shift+N)",
+ "pad.toolbar.ul.title": "Onumrerad lista (Ctrl+Shift+L)",
"pad.toolbar.indent.title": "Öka indrag (TABB)",
"pad.toolbar.unindent.title": "Minska indrag (Shift+TABB)",
"pad.toolbar.undo.title": "Ångra (Ctrl-Z)",
@@ -52,7 +52,7 @@
"pad.importExport.exportpdf": "PDF",
"pad.importExport.exportopen": "ODF (Open Document Format)",
"pad.importExport.exportdokuwiki": "DokuWiki",
- "pad.importExport.abiword.innerHTML": "Du kan endast importera från oformaterad text eller html-format. För mer avancerade importeringsfunktioner, var god installera abiword.",
+ "pad.importExport.abiword.innerHTML": "Du kan endast importera från oformaterad text eller HTML-format. För mer avancerade importeringsfunktioner, var god installera abiword.",
"pad.modals.connected": "Ansluten.",
"pad.modals.reconnecting": "Återansluter till ditt block...",
"pad.modals.forcereconnect": "Tvinga återanslutning",
@@ -60,7 +60,7 @@
"pad.modals.userdup.explanation": "Detta block verkar vara öppet i mer än ett fönster på denna dator.",
"pad.modals.userdup.advice": "Återanslut för att använda detta fönster istället.",
"pad.modals.unauth": "Inte godkänd",
- "pad.modals.unauth.explanation": "Din behörighet ändrades medan du visar denna sida. Försök att återansluta.",
+ "pad.modals.unauth.explanation": "Din behörighet ändrades medan du visade denna sida. Försök att återansluta.",
"pad.modals.looping.explanation": "Kommunikationsproblem med synkroniseringsservern har uppstått.",
"pad.modals.looping.cause": "Kanske du är ansluten via en inkompatibel brandvägg eller proxy.",
"pad.modals.initsocketfail": "Servern kan inte nås.",
@@ -69,7 +69,7 @@
"pad.modals.slowcommit.explanation": "Servern svarar inte.",
"pad.modals.slowcommit.cause": "Detta kan bero på problem med nätverksanslutningen.",
"pad.modals.badChangeset.explanation": "En redigering som du gjort klassificerades som otillåten av synkroniseringsservern.",
- "pad.modals.badChangeset.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänstadministratören om du anser att detta är ett fel. Försök ansluta igen för att fortsätta redigera.",
+ "pad.modals.badChangeset.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänsteadministratören om du upplever att detta är ett fel. Försök att ansluta igen för att fortsätta redigera.",
"pad.modals.corruptPad.explanation": "Blocket du försöker komma åt är skadat.",
"pad.modals.corruptPad.cause": "Detta kan bero på en felaktig konfiguration av servern eller något annat oväntad beteende. Var god kontakta tjänstadministratören.",
"pad.modals.deleted": "Raderad.",
@@ -84,7 +84,7 @@
"pad.chat": "Chatt",
"pad.chat.title": "Öppna chatten för detta block.",
"pad.chat.loadmessages": "Läs in fler meddelanden",
- "timeslider.pageTitle": "Tidsreglage för {{appTitle}}",
+ "timeslider.pageTitle": "{{appTitle}} tidsreglage",
"timeslider.toolbar.returnbutton": "Återvänd till blocket",
"timeslider.toolbar.authors": "Författare:",
"timeslider.toolbar.authorsList": "Inga författare",
diff --git a/src/locales/vi.json b/src/locales/vi.json
index 608e9645..3d5cb66d 100644
--- a/src/locales/vi.json
+++ b/src/locales/vi.json
@@ -3,7 +3,8 @@
"authors": [
"Baonguyen21022003",
"Minh Nguyen",
- "Tuankiet65"
+ "Tuankiet65",
+ "Max20091"
]
},
"index.newPad": "Tạo một Pad mới",
@@ -11,9 +12,9 @@
"pad.toolbar.bold.title": "In đậm (Ctrl-B)",
"pad.toolbar.italic.title": "In nghiêng (Ctrl-I)",
"pad.toolbar.underline.title": "Gạch chân (Ctrl-U)",
- "pad.toolbar.strikethrough.title": "Gạch ngang",
- "pad.toolbar.ol.title": "Danh sách Có Đánh số",
- "pad.toolbar.ul.title": "Danh sách Không Đánh số",
+ "pad.toolbar.strikethrough.title": "Gạch ngang (Ctrl+5)",
+ "pad.toolbar.ol.title": "Danh sách Có Đánh số (Ctrl+Shift+N)",
+ "pad.toolbar.ul.title": "Danh sách Không Đánh số (Ctrl+Shift+L)",
"pad.toolbar.indent.title": "Tăng lề (TAB)",
"pad.toolbar.unindent.title": "Giảm lề (Shift+TAB)",
"pad.toolbar.undo.title": "Hoàn tác (Ctrl-Z)",
diff --git a/src/locales/zh-hant.json b/src/locales/zh-hant.json
index 0707648a..3b084e3d 100644
--- a/src/locales/zh-hant.json
+++ b/src/locales/zh-hant.json
@@ -14,9 +14,9 @@
"pad.toolbar.bold.title": "粗體(Ctrl-B)",
"pad.toolbar.italic.title": "斜體(Ctrl-I)",
"pad.toolbar.underline.title": "底線(Ctrl-U)",
- "pad.toolbar.strikethrough.title": "刪除線",
- "pad.toolbar.ol.title": "有序清單",
- "pad.toolbar.ul.title": "無序清單",
+ "pad.toolbar.strikethrough.title": "刪除線(Ctrl+5)",
+ "pad.toolbar.ol.title": "有序清單(Ctrl+Shift+N)",
+ "pad.toolbar.ul.title": "無序清單(Ctrl+Shift+L)",
"pad.toolbar.indent.title": "縮排(TAB)",
"pad.toolbar.unindent.title": "凸排(Shift+TAB)",
"pad.toolbar.undo.title": "撤銷(Ctrl-Z)",
@@ -94,7 +94,7 @@
"timeslider.toolbar.exportlink.title": "匯出",
"timeslider.exportCurrent": "匯出當前版本為:",
"timeslider.version": "版本{{version}}",
- "timeslider.saved": "{{year}}年{{month}}月{{day}}日儲存",
+ "timeslider.saved": "{{year}}年{{month}}{{day}}日儲存",
"timeslider.dateformat": "{{year}}年{{month}}月{{day}}日 {{hours}}:{{minutes}}:{{seconds}}",
"timeslider.month.january": "1月",
"timeslider.month.february": "2月",
diff --git a/src/node/db/API.js b/src/node/db/API.js
index 4a912368..07d3703c 100644
--- a/src/node/db/API.js
+++ b/src/node/db/API.js
@@ -575,6 +575,117 @@ exports.deletePad = function(padID, callback)
pad.remove(callback);
});
}
+/**
+ restoreRevision(padID, [rev]) Restores revision from past as new changeset
+
+ Example returns:
+
+ {code:0, message:"ok", data:null}
+ {code: 1, message:"padID does not exist", data: null}
+ */
+exports.restoreRevision = function (padID, rev, callback)
+{
+ var Changeset = require("ep_etherpad-lite/static/js/Changeset");
+ var padMessage = require("ep_etherpad-lite/node/handler/PadMessageHandler.js");
+
+ //check if rev is a number
+ if (rev !== undefined && typeof rev != "number")
+ {
+ //try to parse the number
+ if (!isNaN(parseInt(rev)))
+ {
+ rev = parseInt(rev);
+ }
+ else
+ {
+ callback(new customError("rev is not a number", "apierror"));
+ return;
+ }
+ }
+
+ //ensure this is not a negativ number
+ if (rev !== undefined && rev < 0)
+ {
+ callback(new customError("rev is a negativ number", "apierror"));
+ return;
+ }
+
+ //ensure this is not a float value
+ if (rev !== undefined && !is_int(rev))
+ {
+ callback(new customError("rev is a float value", "apierror"));
+ return;
+ }
+
+ //get the pad
+ getPadSafe(padID, true, function (err, pad)
+ {
+ if (ERR(err, callback)) return;
+
+
+ //check if this is a valid revision
+ if (rev > pad.getHeadRevisionNumber())
+ {
+ callback(new customError("rev is higher than the head revision of the pad", "apierror"));
+ return;
+ }
+
+ pad.getInternalRevisionAText(rev, function (err, atext)
+ {
+ if (ERR(err, callback)) return;
+
+ var oldText = pad.text();
+ atext.text += "\n";
+ function eachAttribRun(attribs, func)
+ {
+ var attribsIter = Changeset.opIterator(attribs);
+ var textIndex = 0;
+ var newTextStart = 0;
+ var newTextEnd = atext.text.length;
+ while (attribsIter.hasNext())
+ {
+ var op = attribsIter.next();
+ var nextIndex = textIndex + op.chars;
+ if (!(nextIndex <= newTextStart || textIndex >= newTextEnd))
+ {
+ func(Math.max(newTextStart, textIndex), Math.min(newTextEnd, nextIndex), op.attribs);
+ }
+ textIndex = nextIndex;
+ }
+ }
+
+ // create a new changeset with a helper builder object
+ var builder = Changeset.builder(oldText.length);
+
+ // assemble each line into the builder
+ eachAttribRun(atext.attribs, function (start, end, attribs)
+ {
+ builder.insert(atext.text.substring(start, end), attribs);
+ });
+
+ var lastNewlinePos = oldText.lastIndexOf('\n');
+ if (lastNewlinePos < 0)
+ {
+ builder.remove(oldText.length - 1, 0);
+ } else
+ {
+ builder.remove(lastNewlinePos, oldText.match(/\n/g).length - 1);
+ builder.remove(oldText.length - lastNewlinePos - 1, 0);
+ }
+
+ var changeset = builder.toString();
+
+ //append the changeset
+ pad.appendRevision(changeset);
+ //
+ padMessage.updatePadClients(pad, function ()
+ {
+ });
+ callback(null, null);
+ });
+
+ });
+};
/**
copyPad(sourceID, destinationID[, force=false]) copies a pad. If force is true,
diff --git a/src/node/db/SessionManager.js b/src/node/db/SessionManager.js
index 71315adc..f8000e47 100644
--- a/src/node/db/SessionManager.js
+++ b/src/node/db/SessionManager.js
@@ -351,7 +351,15 @@ function listSessionsWithDBKey (dbkey, callback)
{
exports.getSessionInfo(sessionID, function(err, sessionInfo)
{
- if(ERR(err, callback)) return;
+ if (err == "apierror: sessionID does not exist")
+ {
+ console.warn("Found bad session " + sessionID + " in " + dbkey + ".");
+ }
+ else if(ERR(err, callback))
+ {
+ return;
+ }
+
sessions[sessionID] = sessionInfo;
callback();
});
diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js
index 273a58a6..9adc2418 100644
--- a/src/node/handler/APIHandler.js
+++ b/src/node/handler/APIHandler.js
@@ -345,10 +345,56 @@ var version =
, "getChatHistory" : ["padID", "start", "end"]
, "getChatHead" : ["padID"]
}
+, "1.2.11":
+ { "createGroup" : []
+ , "createGroupIfNotExistsFor" : ["groupMapper"]
+ , "deleteGroup" : ["groupID"]
+ , "listPads" : ["groupID"]
+ , "listAllPads" : []
+ , "createDiffHTML" : ["padID", "startRev", "endRev"]
+ , "createPad" : ["padID", "text"]
+ , "createGroupPad" : ["groupID", "padName", "text"]
+ , "createAuthor" : ["name"]
+ , "createAuthorIfNotExistsFor": ["authorMapper" , "name"]
+ , "listPadsOfAuthor" : ["authorID"]
+ , "createSession" : ["groupID", "authorID", "validUntil"]
+ , "deleteSession" : ["sessionID"]
+ , "getSessionInfo" : ["sessionID"]
+ , "listSessionsOfGroup" : ["groupID"]
+ , "listSessionsOfAuthor" : ["authorID"]
+ , "getText" : ["padID", "rev"]
+ , "setText" : ["padID", "text"]
+ , "getHTML" : ["padID", "rev"]
+ , "setHTML" : ["padID", "html"]
+ , "getAttributePool" : ["padID"]
+ , "getRevisionsCount" : ["padID"]
+ , "getRevisionChangeset" : ["padID", "rev"]
+ , "getLastEdited" : ["padID"]
+ , "deletePad" : ["padID"]
+ , "copyPad" : ["sourceID", "destinationID", "force"]
+ , "movePad" : ["sourceID", "destinationID", "force"]
+ , "getReadOnlyID" : ["padID"]
+ , "getPadID" : ["roID"]
+ , "setPublicStatus" : ["padID", "publicStatus"]
+ , "getPublicStatus" : ["padID"]
+ , "setPassword" : ["padID", "password"]
+ , "isPasswordProtected" : ["padID"]
+ , "listAuthorsOfPad" : ["padID"]
+ , "padUsersCount" : ["padID"]
+ , "getAuthorName" : ["authorID"]
+ , "padUsers" : ["padID"]
+ , "sendClientsMessage" : ["padID", "msg"]
+ , "listAllGroups" : []
+ , "checkToken" : []
+ , "getChatHistory" : ["padID"]
+ , "getChatHistory" : ["padID", "start", "end"]
+ , "getChatHead" : ["padID"]
+ , "restoreRevision" : ["padID", "rev"]
+ }
};
// set the latest available API version here
-exports.latestApiVersion = '1.2.10';
+exports.latestApiVersion = '1.2.11';
// exports the versions so it can be used by the new Swagger endpoint
exports.version = version;
diff --git a/src/node/handler/ImportHandler.js b/src/node/handler/ImportHandler.js
index 60fa5ffb..8e724671 100644
--- a/src/node/handler/ImportHandler.js
+++ b/src/node/handler/ImportHandler.js
@@ -92,9 +92,14 @@ exports.doImport = function(req, res, padId)
}
//we need to rename this file with a .txt ending
else {
- var oldSrcFile = srcFile;
- srcFile = path.join(path.dirname(srcFile),path.basename(srcFile, fileEnding)+".txt");
- fs.rename(oldSrcFile, srcFile, callback);
+ if(settings.allowUnknownFileEnds === true){
+ var oldSrcFile = srcFile;
+ srcFile = path.join(path.dirname(srcFile),path.basename(srcFile, fileEnding)+".txt");
+ fs.rename(oldSrcFile, srcFile, callback);
+ }else{
+ console.warn("Not allowing unknown file type to be imported", fileEnding);
+ callback("uploadFailed");
+ }
}
},
function(callback){
diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js
index e1ac994e..36da4842 100644
--- a/src/node/handler/PadMessageHandler.js
+++ b/src/node/handler/PadMessageHandler.js
@@ -37,6 +37,7 @@ var _ = require('underscore');
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
var channels = require("channels");
var stats = require('../stats');
+var remoteAddress = require("../utils/RemoteAddress").remoteAddress;
/**
* A associative array that saves informations about a session
@@ -115,14 +116,16 @@ exports.handleDisconnect = function(client)
//if this connection was already etablished with a handshake, send a disconnect message to the others
if(session && session.author)
{
- client.get('remoteAddress', function(er, ip) {
- //Anonymize the IP address if IP logging is disabled
- if(settings.disableIPlogging) {
- ip = 'ANONYMOUS';
- }
- accessLogger.info('[LEAVE] Pad "'+session.padId+'": Author "'+session.author+'" on client '+client.id+' with IP "'+ip+'" left the pad')
- })
+ // Get the IP address from our persistant object
+ var ip = remoteAddress[client.id];
+
+ // Anonymize the IP address if IP logging is disabled
+ if(settings.disableIPlogging) {
+ ip = 'ANONYMOUS';
+ }
+
+ accessLogger.info('[LEAVE] Pad "'+session.padId+'": Author "'+session.author+'" on client '+client.id+' with IP "'+ip+'" left the pad')
//get the author color out of the db
authorManager.getAuthorColorId(session.author, function(err, color)
@@ -753,7 +756,13 @@ function handleUserChanges(data, cb)
exports.updatePadClients = function(pad, callback)
{
//skip this step if noone is on this pad
- var roomClients = socketio.sockets.clients(pad.id);
+ var roomClients = [], room = socketio.sockets.adapter.rooms[pad.id];
+ if (room) {
+ for (var id in room) {
+ roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
+ }
+ }
+
if(roomClients.length==0)
return callback();
@@ -766,10 +775,8 @@ exports.updatePadClients = function(pad, callback)
var revCache = {};
//go trough all sessions on this pad
- async.forEach(roomClients, function(client, callback)
- {
+ async.forEach(roomClients, function(client, callback){
var sid = client.id;
-
//https://github.com/caolan/async#whilst
//send them all new changesets
async.whilst(
@@ -1015,7 +1022,13 @@ function handleClientReady(client, message)
return callback();
//Check if this author is already on the pad, if yes, kick the other sessions!
- var roomClients = socketio.sockets.clients(padIds.padId);
+ var roomClients = [], room = socketio.sockets.adapter.rooms[pad.id];
+ if (room) {
+ for (var id in room) {
+ roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
+ }
+ }
+
for(var i = 0; i < roomClients.length; i++) {
var sinfo = sessioninfos[roomClients[i].id];
if(sinfo && sinfo.author == author) {
@@ -1032,19 +1045,19 @@ function handleClientReady(client, message)
sessioninfos[client.id].readonly = padIds.readonly;
//Log creation/(re-)entering of a pad
- client.get('remoteAddress', function(er, ip) {
- //Anonymize the IP address if IP logging is disabled
- if(settings.disableIPlogging) {
- ip = 'ANONYMOUS';
- }
+ var ip = remoteAddress[client.id];
- if(pad.head > 0) {
- accessLogger.info('[ENTER] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" entered the pad');
- }
- else if(pad.head == 0) {
- accessLogger.info('[CREATE] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" created the pad');
- }
- })
+ //Anonymize the IP address if IP logging is disabled
+ if(settings.disableIPlogging) {
+ ip = 'ANONYMOUS';
+ }
+
+ if(pad.head > 0) {
+ accessLogger.info('[ENTER] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" entered the pad');
+ }
+ else if(pad.head == 0) {
+ accessLogger.info('[CREATE] Pad "'+padIds.padId+'": Client '+client.id+' with IP "'+ip+'" created the pad');
+ }
//If this is a reconnect, we don't have to send the client the ClientVars again
if(message.reconnect == true)
@@ -1165,7 +1178,14 @@ function handleClientReady(client, message)
client.broadcast.to(padIds.padId).json.send(messageToTheOtherUsers);
//Run trough all sessions of this pad
- async.forEach(socketio.sockets.clients(padIds.padId), function(roomClient, callback)
+ var roomClients = [], room = socketio.sockets.adapter.rooms[pad.id];
+ if (room) {
+ for (var id in room) {
+ roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
+ }
+ }
+
+ async.forEach(roomClients, function(roomClient, callback)
{
var author;
diff --git a/src/node/handler/SocketIORouter.js b/src/node/handler/SocketIORouter.js
index b3e046d2..0a7361f4 100644
--- a/src/node/handler/SocketIORouter.js
+++ b/src/node/handler/SocketIORouter.js
@@ -24,6 +24,7 @@ var log4js = require('log4js');
var messageLogger = log4js.getLogger("message");
var securityManager = require("../db/SecurityManager");
var readOnlyManager = require("../db/ReadOnlyManager");
+var remoteAddress = require("../utils/RemoteAddress").remoteAddress;
var settings = require('../utils/Settings');
/**
@@ -56,11 +57,15 @@ exports.setSocketIO = function(_socket) {
socket.sockets.on('connection', function(client)
{
+
+ // Broken: See http://stackoverflow.com/questions/4647348/send-message-to-specific-client-with-socket-io-and-node-js
+ // Fixed by having a persistant object, ideally this would actually be in the database layer
+ // TODO move to database layer
if(settings.trustProxy && client.handshake.headers['x-forwarded-for'] !== undefined){
- client.set('remoteAddress', client.handshake.headers['x-forwarded-for']);
+ remoteAddress[client.id] = client.handshake.headers['x-forwarded-for'];
}
else{
- client.set('remoteAddress', client.handshake.address.address);
+ remoteAddress[client.id] = client.handshake.address;
}
var clientAuthorized = false;
diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.js
index 524bab3d..e88a3f4c 100644
--- a/src/node/hooks/express/socketio.js
+++ b/src/node/hooks/express/socketio.js
@@ -1,10 +1,17 @@
var log4js = require('log4js');
-var socketio = require('socket.io');
var settings = require('../../utils/Settings');
var socketIORouter = require("../../handler/SocketIORouter");
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
var webaccess = require("ep_etherpad-lite/node/hooks/express/webaccess");
+// there shouldn't be a browser that isn't compatible to all
+// transports in this list at once
+// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
+
+var socketio = require('socket.io')({
+ transports: settings.socketTransportProtocols
+});
+
var padMessageHandler = require("../../handler/PadMessageHandler");
var connect = require('connect');
@@ -16,7 +23,9 @@ exports.expressCreateServer = function (hook_name, args, cb) {
/* Require an express session cookie to be present, and load the
* session. See http://www.danielbaulig.de/socket-ioexpress for more
* info */
- io.set('authorization', function (data, accept) {
+
+ io.use(function(socket, accept) {
+ var data = socket.request;
if (!data.headers.cookie) return accept('No session cookie transmitted.', false);
// Use connect's cookie parser, because it knows how to parse signed cookies
@@ -36,35 +45,17 @@ exports.expressCreateServer = function (hook_name, args, cb) {
});
});
- // there shouldn't be a browser that isn't compatible to all
- // transports in this list at once
- // e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
- io.set('transports', settings.socketTransportProtocols );
-
- var socketIOLogger = log4js.getLogger("socket.io");
- io.set('logger', {
- debug: function (str)
- {
- socketIOLogger.debug.apply(socketIOLogger, arguments);
- },
- info: function (str)
- {
- socketIOLogger.info.apply(socketIOLogger, arguments);
- },
- warn: function (str)
- {
- socketIOLogger.warn.apply(socketIOLogger, arguments);
- },
- error: function (str)
- {
- socketIOLogger.error.apply(socketIOLogger, arguments);
- },
- });
+ // var socketIOLogger = log4js.getLogger("socket.io");
+ // Debug logging now has to be set at an environment level, this is stupid.
+ // https://github.com/Automattic/socket.io/wiki/Migrating-to-1.0
+ // This debug logging environment is set in Settings.js
//minify socket.io javascript
- if(settings.minify)
- io.enable('browser client minification');
-
+ // Due to a shitty decision by the SocketIO team minification is
+ // no longer available, details available at:
+ // http://stackoverflow.com/questions/23981741/minify-socket-io-socket-io-js-with-1-0
+ // if(settings.minify) io.enable('browser client minification');
+
//Initalize the Socket.IO Router
socketIORouter.setSocketIO(io);
socketIORouter.addComponent("pad", padMessageHandler);
diff --git a/src/node/utils/RemoteAddress.js b/src/node/utils/RemoteAddress.js
new file mode 100644
index 00000000..86a4a5b2
--- /dev/null
+++ b/src/node/utils/RemoteAddress.js
@@ -0,0 +1 @@
+exports.remoteAddress = {};
diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js
index c455617b..af7ede81 100644
--- a/src/node/utils/Settings.js
+++ b/src/node/utils/Settings.js
@@ -129,6 +129,11 @@ exports.minify = true;
*/
exports.abiword = null;
+/**
+ * Should we support none natively supported file types on import?
+ */
+exports.allowUnknownFileEnds = true;
+
/**
* The log level of log4js
*/
@@ -228,6 +233,7 @@ exports.reloadSettings = function reloadSettings() {
log4js.configure(exports.logconfig);//Configure the logging appenders
log4js.setGlobalLogLevel(exports.loglevel);//set loglevel
+ process.env['DEBUG'] = 'socket.io:' + exports.loglevel; // Used by SocketIO for Debug
log4js.replaceConsole();
if(!exports.sessionKey){ // If the secretKey isn't set we also create yet another unique value here
diff --git a/src/package.json b/src/package.json
index 7cabf6e6..4b0ae82b 100644
--- a/src/package.json
+++ b/src/package.json
@@ -15,9 +15,9 @@
"request" : "2.9.100",
"require-kernel" : "1.0.5",
"resolve" : ">=1.0.0",
- "socket.io" : "0.9.x",
+ "socket.io" : ">=1.2.0",
"ueberDB" : ">=0.2.9",
- "express" : "3.1.0",
+ "express" : ">3.1.0 <3.9.0",
"async" : "0.1.x",
"connect" : "2.7.x",
"clean-css" : "0.3.2",
@@ -31,13 +31,13 @@
"ejs" : "0.6.1",
"graceful-fs" : "1.1.5",
"slide" : "1.1.3",
- "semver" : "1.0.13",
+ "semver" : ">2.3.0",
"security" : "1.0.0",
"tinycon" : "0.0.1",
"underscore" : "1.5.1",
"unorm" : "1.0.0",
"languages4translatewiki" : "0.1.3",
- "swagger-node-express" : "1.2.3",
+ "swagger-node-express" : ">=2.1.0",
"channels" : "0.0.x",
"jsonminify" : "0.2.2",
"measured" : "0.1.3"
diff --git a/src/static/css/fontawesome-etherpad.css b/src/static/css/fontawesome-etherpad.css
deleted file mode 100644
index 13f28f2b..00000000
--- a/src/static/css/fontawesome-etherpad.css
+++ /dev/null
@@ -1,76 +0,0 @@
-@font-face {
- font-family: 'fontawesome-etherpad';
- src: url('../font/fontawesome-etherpad.eot?81419457');
- src: url('../font/fontawesome-etherpad.eot?81419457#iefix') format('embedded-opentype'),
- url('../font/fontawesome-etherpad.woff?81419457') format('woff'),
- url('../font/fontawesome-etherpad.ttf?81419457') format('truetype'),
- url('../font/fontawesome-etherpad.svg?81419457#fontawesome-etherpad') format('svg');
- font-weight: normal;
- font-style: normal;
-}
-/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
-/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
-/*
-@media screen and (-webkit-min-device-pixel-ratio:0) {
- @font-face {
- font-family: 'fontawesome-etherpad';
- src: url('../font/fontawesome-etherpad.svg?81419457#fontawesome-etherpad') format('svg');
- }
-}
-*/
-
- [class^="icon-"]:before, [class*=" icon-"]:before {
- font-family: "fontawesome-etherpad";
- font-style: normal;
- font-weight: normal;
- speak: none;
-
- display: inline-block;
- text-decoration: inherit;
- width: 1em;
- margin-right: .2em;
- text-align: center;
- /* opacity: .8; */
-
- /* For safety - reset parent styles, that can break glyph codes*/
- font-variant: normal;
- text-transform: none;
-
- /* fix buttons height, for twitter bootstrap */
- line-height: 1em;
-
- /* Animation center compensation - margins should be symmetric */
- /* remove if not needed */
- margin-left: .2em;
-
- /* you can be more comfortable with increased icons size */
- /* font-size: 120%; */
-
- /* Uncomment for 3D effect */
- /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
-}
-
-.icon-users:before { content: '\e800'; } /* '' */
-.icon-star:before { content: '\e801'; } /* '' */
-.icon-cog:before { content: '\e802'; } /* '' */
-.icon-bold:before { content: '\e803'; } /* '' */
-.icon-italic:before { content: '\e804'; } /* '' */
-.icon-indent-left:before { content: '\e805'; } /* '' */
-.icon-indent-right:before { content: '\e806'; } /* '' */
-.icon-list-bullet:before { content: '\e807'; } /* '' */
-.icon-list-numbered:before { content: '\e808'; } /* '' */
-.icon-strike:before { content: '\e809'; } /* '' */
-.icon-underline:before { content: '\e80a'; } /* '' */
-.icon-cw:before { content: '\e80b'; } /* '' */
-.icon-ccw:before { content: '\e80c'; } /* '' */
-.icon-clock:before { content: '\e80d'; } /* '' */
-.icon-eye-off:before { content: '\e80e'; } /* '' */
-.icon-eye:before { content: '\e80f'; } /* '' */
-.icon-play:before { content: '\e810'; } /* '' */
-.icon-fast-bw:before { content: '\e811'; } /* '' */
-.icon-fast-fw:before { content: '\e812'; } /* '' */
-.icon-pause:before { content: '\e813'; } /* '' */
-.icon-glass:before { content: '\e814'; } /* '' */
-.icon-code:before { content: '\e815'; } /* '' */
-.icon-exchange:before { content: '\e816'; } /* '' */
-.icon-chat:before { content: '\e817'; } /* '' */
\ No newline at end of file
diff --git a/src/static/css/pad.css b/src/static/css/pad.css
index 599b9fd4..fd99cf45 100644
--- a/src/static/css/pad.css
+++ b/src/static/css/pad.css
@@ -59,7 +59,7 @@ a img {
height: 32px;
}
.toolbar ul {
- position: relative;
+ position: absolute;
list-style: none;
padding-right: 3px;
padding-left: 1px;
@@ -67,9 +67,6 @@ a img {
overflow: hidden;
float: left
}
-.toolbar ul.menu_right {
- float: right
-}
.toolbar ul li {
float: left;
margin-left: 2px;
@@ -84,6 +81,7 @@ a img {
visibility: hidden;
width: 0px;
padding: 5px;
+ height:20px;
}
.toolbar ul li a:hover {
text-decoration: none;
@@ -164,6 +162,15 @@ a img {
border: 1px solid #ccc;
outline: none;
}
+.toolbar ul.menu_left {
+ left:0px;
+ right:250px;
+}
+
+.toolbar ul.menu_right {
+ right:0px;
+}
+
li[data-key=showusers] > a {
min-width: 30px;
text-align: left;
@@ -175,6 +182,9 @@ li[data-key=showusers] > a #online_count {
top: 2px;
padding-left: 2px;
}
+#editbar{
+ display:none;
+}
#editorcontainer {
position: absolute;
top: 37px; /* + 1px border */
@@ -214,6 +224,41 @@ li[data-key=showusers] > a #online_count {
padding:10px;
}
+.loadingAnimation{
+ -webkit-animation: loadingAnimation 2s infinite linear;
+ animation: loadingAnimation 2s infinite linear;
+ font-family: "fontawesome-etherpad";
+ font-size:24px;
+ z-index:150;
+ width:25px;
+ height:25px;
+}
+
+.loadingAnimation:before{
+ content: "\e80e";
+}
+
+@-webkit-keyframes loadingAnimation {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg);
+ }
+}
+@keyframes loadingAnimation {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 100% {
+ -webkit-transform: rotate(359deg);
+ transform: rotate(359deg);
+ }
+}
+
#editorcontainerbox {
position: absolute;
bottom: 0;
@@ -601,38 +646,49 @@ table#otheruserstable {
margin-top: 4px;
background-repeat: no-repeat;
padding-left: 25px;
- background-image: url("../../static/img/etherpad_lite_icons.png");
color: #333;
text-decoration: none;
padding-bottom:2px;
+ display:inline;
+ padding-left:5px;
+ font-family: "Arial";
}
-#exporthtml {
- background-position: 0px -299px
+.exportlink{
+ font-family: "fontawesome-etherpad";
+ display:block;
+ margin:5px;
+ color:#666;
}
-#exportplain {
- background-position: 0px -395px
+#exporthtmla:before {
+ content: "\e826";
}
-#exportword {
- background-position: 0px -275px
+#exportplaina:before {
+ content: "\e802";
}
-#exportpdf {
- background-position: 0px -371px
+#exportworda:before {
+ content: "\e804";
}
-#exportopen {
- background-position: 0px -347px
+#exportpdfa:before {
+ content: "\e803";
}
-#exportdokuwiki {
- background-position: 0px -459px
+#exportopena:before {
+ content: "\e805";
+}
+#exportdokuwikia:before {
+ content: "\e805";
}
/* hidden element */
#importstatusball,
-#importarrow,
#importmessagesuccess,
#importmessageabiword {
display: none;
}
+.throbbold{
+ font-weight:bold;
+}
+
#importmessageabiword {
color: #900;
font-size: small;
@@ -679,58 +735,58 @@ table#otheruserstable {
color: #666;
}
.buttonicon-bold:before {
- content: "\e803";
+ content: "\e81c";
}
.buttonicon-italic:before {
- content: "\e804";
+ content: "\e81d";
}
.buttonicon-underline:before {
- content: "\e80a";
-}
-.buttonicon-strikethrough:before {
- content: "\e809";
-}
-.buttonicon-insertorderedlist:before {
- content: "\e808";
-}
-.buttonicon-insertunorderedlist:before {
- content: "\e807";
-}
-.buttonicon-indent:before {
- content: "\e806";
-}
-.buttonicon-outdent:before {
- content: "\e805";
-}
-.buttonicon-undo:before {
- content: "\e80c";
-}
-.buttonicon-redo:before {
- content: "\e80b";
-}
-.buttonicon-clearauthorship:before {
- content: "\e80e";
-}
-.buttonicon-settings:before {
- content: "\e802";
-}
-.buttonicon-import_export:before {
- content: "\e816";
-}
-.buttonicon-embed:before {
- content: "\e815";
-}
-.buttonicon-history:before {
- content: "\e80d";
-}
-.buttonicon-chat:before {
content: "\e817";
}
+.buttonicon-strikethrough:before {
+ content: "\e818";
+}
+.buttonicon-insertorderedlist:before {
+ content: "\e816";
+}
+.buttonicon-insertunorderedlist:before {
+ content: "\e815";
+}
+.buttonicon-indent:before {
+ content: "\e814";
+}
+.buttonicon-outdent:before {
+ content: "\e813";
+}
+.buttonicon-undo:before {
+ content: "\e823";
+}
+.buttonicon-redo:before {
+ content: "\e824";
+}
+.buttonicon-clearauthorship:before {
+ content: "\e80d";
+}
+.buttonicon-settings:before {
+ content: "\e833";
+}
+.buttonicon-import_export:before {
+ content: "\e834";
+}
+.buttonicon-embed:before {
+ content: "\e827";
+}
+.buttonicon-history:before {
+ content: "\e837";
+}
+.buttonicon-chat:before {
+ content: "\e829";
+}
.buttonicon-showusers:before {
- content: "\e800";
+ content: "\e808";
}
.buttonicon-savedRevision:before {
- content: "\e801";
+ content: "\e835";
}
#focusprotector {
z-index: 100;
@@ -843,12 +899,16 @@ input[type=checkbox] {
width: 185px !important;
}
@media screen and (max-width: 600px) {
- .toolbar ul li.separator {
- display: none;
- }
- .toolbar ul li a {
- padding: 4px 1px
- }
+ .toolbar ul li.separator {
+ display: none;
+ }
+ .toolbar ul li a {
+ padding: 4px 1px
+ }
+ .toolbar ul.menu_left {
+ left:0px;
+ right:150px;
+ }
}
@media all and (max-width: 400px){
#gritter-notice-wrapper{
@@ -894,9 +954,13 @@ input[type=checkbox] {
#editbar {
height: 62px;
}
+ .toolbar ul.menu_left {
+ left:0px;
+ right:100px;
+ }
+
.toolbar ul.menu_right {
- float: left;
- margin-top:2px;
+ right:0px;
}
.popup {
width:100%;
@@ -917,6 +981,9 @@ input[type=checkbox] {
#editorcontainer {
margin-bottom: 33px
}
+ .toolbar ul.menu_left {
+ right:0px;
+ }
.toolbar ul.menu_right {
background: #f7f7f7;
background: -webkit-linear-gradient(#f7f7f7, #f1f1f1 80%);
@@ -1075,5 +1142,43 @@ input[type=checkbox] {
.gritter-light .gritter-title {
text-shadow: none;
}
+/* End of gritter stuff */
+
+@font-face {
+ font-family: "fontawesome-etherpad";
+ src:url("../font/fontawesome-etherpad.eot");
+ src:url("../font/fontawesome-etherpad.eot?#iefix") format("embedded-opentype"),
+ url("../font/fontawesome-etherpad.woff") format("woff"),
+ url("../font/fontawesome-etherpad.ttf") format("truetype"),
+ url("../font/fontawesome-etherpad.svg#fontawesome-etherpad") format("svg");
+ font-weight: normal;
+ font-style: normal;
+
+}
+
+[data-icon]:before {
+ font-family: "fontawesome-etherpad" !important;
+ content: attr(data-icon);
+ font-style: normal !important;
+ font-weight: normal !important;
+ font-variant: normal !important;
+ text-transform: none !important;
+ speak: none;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+[class^="icon-"]:before,
+[class*=" icon-"]:before {
+ font-family: "fontawesome-etherpad" !important;
+ font-style: normal !important;
+ font-weight: normal !important;
+ font-variant: normal !important;
+ text-transform: none !important;
+ speak: none;
+ line-height: 1;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
-/* End of gritter stuff */
\ No newline at end of file
diff --git a/src/static/css/timeslider.css b/src/static/css/timeslider.css
index 6608df3e..f4329a5e 100644
--- a/src/static/css/timeslider.css
+++ b/src/static/css/timeslider.css
@@ -14,14 +14,14 @@
top: 0;
}
#timeslider-left {
- background-image: url(../../static/img/timeslider_left.png);
+ background-color:#fff;
height: 63px;
left: 0;
position: absolute;
width: 134px;
}
#timeslider-right {
- background-image: url(../../static/img/timeslider_right.png);
+ background-color:#fff;
height: 63px;
position: absolute;
right: 0;
@@ -29,7 +29,6 @@
width: 155px;
}
#timeslider {
- background-image: url(../../static/img/timeslider_background.png);
height: 63px;
margin: 0 9px;
-webkit-touch-callout: none;
@@ -50,7 +49,7 @@
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
- background-image: url(../../static/img/crushed_current_location.png);
+ background-color: #666;
cursor: pointer;
height: 61px;
left: 0;
@@ -63,66 +62,97 @@
-moz-user-select: none;
user-select: none;
cursor: pointer;
- height: 35px;
+ height: 60px;
margin-left: 5px;
margin-right: 150px;
position: relative;
- top: 20px;
+ top: 0px;
}
+
#playpause_button,
#playpause_button_icon {
- height: 47px;
+ height: 44px;
position: absolute;
- width: 47px;
+ width: 44px;
+ text-align:center;
+ vertical-align:middle;
}
#playpause_button {
- background-image: url(../../static/img/crushed_button_undepressed.png);
right: 77px;
top: 9px;
+ height:50px;
+ height:50px;
+ background: background-linear-gradient( #F7F7F7, #F1F1F1 80%) repeat scroll 0 0 transparent;
+ border-radius:24px;
+ cursor:hand;
}
+#playpause_button_icon:before {
+ line-height:44px;
+ padding-left:2px;
+ font-family: fontawesome-etherpad;
+ content: "\e82c";
+ font-size:24px;
+ color:#666;
+}
+
#playpause_button_icon {
- background-image: url(../../static/img/play.png);
left: 0;
top: 0;
+ border-radius:48px;
+ border: solid 1px #666;
}
-.pause#playpause_button_icon {
- background-image: url(../../static/img/pause.png)
+.pause:before {
+ line-height:44px;
+ padding-left:2px;
+ font-family: fontawesome-etherpad;
+ content: "\e82e" !important;
+ font-size:24px;
+ color:#666;
+ padding-left:0 !important;
}
#leftstar,
#rightstar,
#leftstep,
#rightstep {
- background: url(../../static/img/stepper_buttons.png) 0 0 no-repeat;
- height: 21px;
+ background-color: white;
overflow: hidden;
position: absolute;
}
-#leftstar {
- background-position: 0 -44px;
- right: 34px;
- top: 8px;
- width: 30px;
+
+.stepper{
+ font-family: fontawesome-etherpad;
+ border-radius:2px;
+ border: #666 solid 1px;
+ line-height:18px;
+ text-align:center;
+ height:22px;
+ color:#666;
}
-#rightstar {
- background-position: -29px -44px;
- right: 5px;
- top: 8px;
- width: 29px;
+
+stepper:active{
+ color:#000;
}
+
#leftstep {
- background-position: 0 -22px;
- right: 34px;
+ right: 38px;
top: 20px;
- width: 30px;
+ width: 25px;
}
+#leftstep:before{
+ content: '\e821';
+ vertical-align:middle;
+}
+#rightstep:before{
+ content: "\e822";
+ vertical-align:middle;
+}
+
#rightstep {
- background-position: -29px -22px;
- right: 5px;
+ right: 12px;
top: 20px;
- width: 30px;
+ width: 25px;
}
#timeslider .star {
- background-image: url(../../static/img/star.png);
cursor: pointer;
height: 16px;
position: absolute;
@@ -130,7 +160,9 @@
width: 15px;
}
#timeslider #timer {
- color: #fff;
+ background: linear-gradient(#F7F7F7, #F1F1F1 80%) repeat scroll 0% 0% transparent;
+ padding:2px;
+ border-radius:2px;
font-family: Arial, sans-serif;
font-size: 11px;
left: 7px;
@@ -291,16 +323,3 @@ OL {
.list-number6 {
list-style-type: lower-roman
}
-/* IE 6/7 fixes */
-* HTML #ui-slider-handle {
- background-image: url(../../static/img/current_location.gif)
-}
-* HTML #timeslider .star {
- background-image: url(../../static/img/star.gif)
-}
-* HTML #playpause_button_icon {
- background-image: url(../../static/img/play.gif)
-}
-* HTML .pause#playpause_button_icon {
- background-image: url(../../static/img/pause.gif)
-}
diff --git a/src/static/font/config.json b/src/static/font/config.json
new file mode 100644
index 00000000..34231cca
--- /dev/null
+++ b/src/static/font/config.json
@@ -0,0 +1,346 @@
+{
+ "name": "fontawesome-etherpad",
+ "css_prefix_text": "icon-",
+ "css_use_suffix": false,
+ "hinting": true,
+ "units_per_em": 1000,
+ "ascent": 850,
+ "glyphs": [
+ {
+ "uid": "bf882b30900da12fca090d9796bc3030",
+ "css": "mail",
+ "code": 59402,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "474656633f79ea2f1dad59ff63f6bf07",
+ "css": "star",
+ "code": 59446,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "d17030afaecc1e1c22349b99f3c4992a",
+ "css": "star-empty",
+ "code": 59445,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "8b80d36d4ef43889db10bc1f0dc9a862",
+ "css": "user",
+ "code": 59401,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "31972e4e9d080eaa796290349ae6c1fd",
+ "css": "users",
+ "code": 59400,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "0f99ab40ab0b4d64a74f2d0deeb03e42",
+ "css": "videocam",
+ "code": 59403,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "381da2c2f7fd51f8de877c044d7f439d",
+ "css": "picture",
+ "code": 59404,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "7fd683b2c518ceb9e5fa6757f2276faa",
+ "css": "eye-off",
+ "code": 59405,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "7034e4d22866af82bef811f52fb1ba46",
+ "css": "code",
+ "code": 59431,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "7277ded7695b2a307a5f9d50097bb64c",
+ "css": "print",
+ "code": 59393,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "dcedf50ab1ede3283d7a6c70e2fe32f3",
+ "css": "chat",
+ "code": 59432,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "9c1376672bb4f1ed616fdd78a23667e9",
+ "css": "comment-empty",
+ "code": 59433,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "f48ae54adfb27d8ada53d0fd9e34ee10",
+ "css": "trash-empty",
+ "code": 59434,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "1b5a5d7b7e3c71437f5a26befdd045ed",
+ "css": "doc",
+ "code": 59394,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "9daa1fdf0838118518a7e22715e83abc",
+ "css": "file-pdf",
+ "code": 59395,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "310ffd629da85142bc8669f010556f2d",
+ "css": "file-word",
+ "code": 59396,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "f761c3bbe16ba2d332914ecb28e7a042",
+ "css": "file-excel",
+ "code": 59397,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "edcd4022de8d8df266ef7c42d2658ca5",
+ "css": "file-powerpoint",
+ "code": 59398,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "3c961c1a8d874815856fc6637dc5a13c",
+ "css": "file-image",
+ "code": 59399,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "26613a2e6bc41593c54bead46f8c8ee3",
+ "css": "file-code",
+ "code": 59430,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "e99461abfef3923546da8d745372c995",
+ "css": "cog",
+ "code": 59443,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "19c50c52858a81de58f9db488aba77bc",
+ "css": "mic",
+ "code": 59435,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "598a5f2bcf3521d1615de8e1881ccd17",
+ "css": "clock",
+ "code": 59447,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "bc71f4c6e53394d5ba46b063040014f1",
+ "css": "cw",
+ "code": 59428,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "f9c3205df26e7778abac86183aefdc99",
+ "css": "ccw",
+ "code": 59427,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "a73c5deb486c8d66249811642e5d719a",
+ "css": "arrows-cw",
+ "code": 59429,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "6020aff067fc3c119cdd75daa5249220",
+ "css": "exchange",
+ "code": 59444,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "ce06b5805120d0c2f8d60cd3f1a4fdb5",
+ "css": "play",
+ "code": 59436,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "b624a1e512819d410ddbee84e6918b9d",
+ "css": "stop",
+ "code": 59437,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "0b28050bac9d3facf2f0226db643ece0",
+ "css": "pause",
+ "code": 59438,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "c47efa0e3e74f6ba4c2562c1258fff1f",
+ "css": "to-end",
+ "code": 59426,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "12052b30d23a1a70d6b32962d5464cae",
+ "css": "to-start",
+ "code": 59425,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "f9cbf7508cd04145ade2800169959eef",
+ "css": "font",
+ "code": 59419,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "02cca871bb69da75e8ee286b7055832c",
+ "css": "bold",
+ "code": 59420,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "a8cb1c217f02b073db3670c061cc54d2",
+ "css": "italic",
+ "code": 59421,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "0c708edd8fae2376b3370aa56d40cf9e",
+ "css": "header",
+ "code": 59422,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "c009d417f87d6a27bb5a1cefd30b6cbd",
+ "css": "text-height",
+ "code": 59423,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "13a971bcccd2dda26d4d4eccd8593f8a",
+ "css": "text-width",
+ "code": 59424,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "f4f0e849b805be1f6d76b65581cb3b8b",
+ "css": "align-left",
+ "code": 59392,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "ae6336c46d73af999fe7460c089abb4d",
+ "css": "align-center",
+ "code": 59407,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "e1e7306b47c3c5e6faecce9d32571381",
+ "css": "align-right",
+ "code": 59408,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "25a81737628d1e654a30ad412d7d6dd7",
+ "css": "align-justify",
+ "code": 59409,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "48b87105bd38c20315f1b705b8c7b38c",
+ "css": "list",
+ "code": 59410,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "594e9271c08ff732c04b3bf3117b9040",
+ "css": "indent-left",
+ "code": 59411,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "4d2dfc45d8176b1f26aed973fa84a91e",
+ "css": "indent-right",
+ "code": 59412,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "a2a74f5e7b7d9ba054897d8c795a326a",
+ "css": "list-bullet",
+ "code": 59413,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "f6766a8b042c2453a4e153af03294383",
+ "css": "list-numbered",
+ "code": 59414,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "61c242c9e2134d5864d7fdd57b3c9289",
+ "css": "strike",
+ "code": 59416,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "d4a4a38a40b728f46dad1de4ac950231",
+ "css": "underline",
+ "code": 59415,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "4e88371fb8857dacc1f66afe6314e426",
+ "css": "superscript",
+ "code": 59417,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "3d1c929dbc966992185ce749548c1b2c",
+ "css": "subscript",
+ "code": 59418,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "9396b2d8849e0213a0f11c5fd7fcc522",
+ "css": "tasks",
+ "code": 59442,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "0bda4bc779d4c32623dec2e43bd67ee8",
+ "css": "gauge",
+ "code": 59439,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "cda0cdcfd38f5f1d9255e722dad42012",
+ "css": "spinner",
+ "code": 59406,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "fa9a0b7e788c2d78e24cef1de6b70e80",
+ "css": "brush",
+ "code": 59440,
+ "src": "fontawesome"
+ },
+ {
+ "uid": "be13b8c668eb18839d5d53107725f1de",
+ "css": "slideshare",
+ "code": 59441,
+ "src": "fontawesome"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/static/font/fontawesome-etherpad.eot b/src/static/font/fontawesome-etherpad.eot
index 9a24fc67..fb651686 100644
Binary files a/src/static/font/fontawesome-etherpad.eot and b/src/static/font/fontawesome-etherpad.eot differ
diff --git a/src/static/font/fontawesome-etherpad.svg b/src/static/font/fontawesome-etherpad.svg
index ba49c31c..4033c4d1 100644
--- a/src/static/font/fontawesome-etherpad.svg
+++ b/src/static/font/fontawesome-etherpad.svg
@@ -6,30 +6,62 @@
You haven't installed any plugins yet.
-
Fetching installed plugins...