From 5d416579ee3a0943ee258625cc0de4c7a56e49e3 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 22 Jan 2013 22:33:51 +0000 Subject: [PATCH 01/22] bring in some padDiff stuff that doesnt suck --- src/node/db/API.js | 81 ++++++++++++++++++++++++++++++++++ src/node/handler/APIHandler.js | 38 ++++++++++++++++ src/node/utils/padDiff.js | 72 ++++++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 src/node/utils/padDiff.js diff --git a/src/node/db/API.js b/src/node/db/API.js index 9cad415d..9cecdbd3 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -568,6 +568,87 @@ exports.checkToken = function(callback) } +/** +createDiff(padID, startRev, endRev) returns an object of diffs from 2 points in a pad + +Example returns: + +TODO {"code":0,"message":"ok","data":null} +TODO {"code":4,"message":"no or wrong API Key","data":null} +*/ +exports.createDiff = function(padID, startRev, endRev, callback){ + //check if rev is a number + if(startRev !== undefined && typeof startRev != "number") + { + //try to parse the number + if(!isNaN(parseInt(startRev))) + { + startRev = parseInt(startRev, 10); + } + else + { + callback({stop: "startRev is not a number"}); + return; + } + } + + //check if rev is a number + if(endRev !== undefined && typeof endRev != "number") + { + //try to parse the number + if(!isNaN(parseInt(endRev))) + { + endRev = parseInt(endRev, 10); + } + else + { + callback({stop: "endRev is not a number"}); + return; + } + } + + //get the pad + getPadSafe(padID, true, function(err, pad) + { + if(err){ + return callback(err); + } + + try { + var padDiff = new PadDiff(pad, startRev, endRev); + } catch(e) { + return callback({stop:e.message}); + } + + var html, authors; + + async.series([ + function(callback){ + padDiff.getHtml(function(err, _html){ + if(err){ + return callback(err); + } + + html = _html; + callback(); + }); + }, + function(callback){ + padDiff.getAuthors(function(err, _authors){ + if(err){ + return callback(err); + } + + authors = _authors; + callback(); + }); + } + ], function(err){ + callback(err, {html: html, authors: authors}) + }); + }); +} + /******************************/ /** INTERNAL HELPER FUNCTIONS */ /******************************/ diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index ae93e933..ec7e9f8d 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -24,6 +24,7 @@ var fs = require("fs"); var api = require("../db/API"); var padManager = require("../db/PadManager"); var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; +var padDiff = require("../utils/padDiff"); //ensure we have an apikey var apikey = null; @@ -174,6 +175,43 @@ var version = , "listAllGroups" : [] , "checkToken" : [] } +, "1.2.2": + { "createGroup" : [] + , "createGroupIfNotExistsFor" : ["groupMapper"] + , "deleteGroup" : ["groupID"] + , "listPads" : ["groupID"] + , "listAllPads" : [] + , "createDiff" : ["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"] + , "getRevisionsCount" : ["padID"] + , "getLastEdited" : ["padID"] + , "deletePad" : ["padID"] + , "getReadOnlyID" : ["padID"] + , "setPublicStatus" : ["padID", "publicStatus"] + , "getPublicStatus" : ["padID"] + , "setPassword" : ["padID", "password"] + , "isPasswordProtected" : ["padID"] + , "listAuthorsOfPad" : ["padID"] + , "padUsersCount" : ["padID"] + , "getAuthorName" : ["authorID"] + , "padUsers" : ["padID"] + , "sendClientsMessage" : ["padID", "msg"] + , "listAllGroups" : [] + , "checkToken" : [] + } }; /** diff --git a/src/node/utils/padDiff.js b/src/node/utils/padDiff.js new file mode 100644 index 00000000..15957b82 --- /dev/null +++ b/src/node/utils/padDiff.js @@ -0,0 +1,72 @@ +exports.createDiff = function(padID, startRev, endRev, callback){ + //check if rev is a number + if(startRev !== undefined && typeof startRev != "number") + { + //try to parse the number + if(!isNaN(parseInt(startRev))) + { + startRev = parseInt(startRev, 10); + } + else + { + callback({stop: "startRev is not a number"}); + return; + } + } + + //check if rev is a number + if(endRev !== undefined && typeof endRev != "number") + { + //try to parse the number + if(!isNaN(parseInt(endRev))) + { + endRev = parseInt(endRev, 10); + } + else + { + callback({stop: "endRev is not a number"}); + return; + } + } + + //get the pad + getPadSafe(padID, true, function(err, pad) + { + if(err){ + return callback(err); + } + + try { + var padDiff = new PadDiff(pad, startRev, endRev); + } catch(e) { + return callback({stop:e.message}); + } + + var html, authors; + + async.series([ + function(callback){ + padDiff.getHtml(function(err, _html){ + if(err){ + return callback(err); + } + + html = _html; + callback(); + }); + }, + function(callback){ + padDiff.getAuthors(function(err, _authors){ + if(err){ + return callback(err); + } + + authors = _authors; + callback(); + }); + } + ], function(err){ + callback(err, {html: html, authors: authors}) + }); + }); +} From 205d9832253b9d62e7726178e2d6c5a14c3f64ac Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 22 Jan 2013 22:48:05 +0000 Subject: [PATCH 02/22] make it crash --- src/node/db/API.js | 1 + src/node/handler/APIHandler.js | 1 - src/node/utils/padDiff.js | 1 + 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 9cecdbd3..72ca1632 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -30,6 +30,7 @@ var async = require("async"); var exportHtml = require("../utils/ExportHtml"); var importHtml = require("../utils/ImportHtml"); var cleanText = require("./Pad").cleanText; +var padDiff = require("../utils/padDiff"); /**********************/ /**GROUP FUNCTIONS*****/ diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index ec7e9f8d..31b4b187 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -24,7 +24,6 @@ var fs = require("fs"); var api = require("../db/API"); var padManager = require("../db/PadManager"); var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; -var padDiff = require("../utils/padDiff"); //ensure we have an apikey var apikey = null; diff --git a/src/node/utils/padDiff.js b/src/node/utils/padDiff.js index 15957b82..230668eb 100644 --- a/src/node/utils/padDiff.js +++ b/src/node/utils/padDiff.js @@ -1,4 +1,5 @@ exports.createDiff = function(padID, startRev, endRev, callback){ +console.warn("WTF"); //check if rev is a number if(startRev !== undefined && typeof startRev != "number") { From d21585b8807b831e51a689bab6769d0ebfc1544b Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 22 Jan 2013 23:06:52 +0000 Subject: [PATCH 03/22] mheh --- src/node/db/API.js | 8 ++++++-- src/node/utils/padDiff.js | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 72ca1632..50c4a6c5 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -30,7 +30,7 @@ var async = require("async"); var exportHtml = require("../utils/ExportHtml"); var importHtml = require("../utils/ImportHtml"); var cleanText = require("./Pad").cleanText; -var padDiff = require("../utils/padDiff"); +var PadDiff = require("../utils/padDiff"); /**********************/ /**GROUP FUNCTIONS*****/ @@ -611,16 +611,19 @@ exports.createDiff = function(padID, startRev, endRev, callback){ //get the pad getPadSafe(padID, true, function(err, pad) { +console.warn(padID); if(err){ return callback(err); } try { +console.warn(pad); var padDiff = new PadDiff(pad, startRev, endRev); +console.warn("AFTER"); } catch(e) { return callback({stop:e.message}); } - +/* var html, authors; async.series([ @@ -647,6 +650,7 @@ exports.createDiff = function(padID, startRev, endRev, callback){ ], function(err){ callback(err, {html: html, authors: authors}) }); + */ }); } diff --git a/src/node/utils/padDiff.js b/src/node/utils/padDiff.js index 230668eb..645c2e2d 100644 --- a/src/node/utils/padDiff.js +++ b/src/node/utils/padDiff.js @@ -1,5 +1,6 @@ exports.createDiff = function(padID, startRev, endRev, callback){ console.warn("WTF"); + //check if rev is a number if(startRev !== undefined && typeof startRev != "number") { From 3fb2f02875bfd0da7097a3fa021c7959bde1811b Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 22 Jan 2013 23:16:49 +0000 Subject: [PATCH 04/22] semi working --- src/node/db/API.js | 6 +- src/node/utils/padDiff.js | 596 ++++++++++++++++++++++++++++++++++---- 2 files changed, 539 insertions(+), 63 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 50c4a6c5..2c8b91ab 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -611,19 +611,16 @@ exports.createDiff = function(padID, startRev, endRev, callback){ //get the pad getPadSafe(padID, true, function(err, pad) { -console.warn(padID); if(err){ return callback(err); } try { -console.warn(pad); var padDiff = new PadDiff(pad, startRev, endRev); -console.warn("AFTER"); } catch(e) { + // console.warn(e.stack); return callback({stop:e.message}); } -/* var html, authors; async.series([ @@ -650,7 +647,6 @@ console.warn("AFTER"); ], function(err){ callback(err, {html: html, authors: authors}) }); - */ }); } diff --git a/src/node/utils/padDiff.js b/src/node/utils/padDiff.js index 645c2e2d..f898cbe1 100644 --- a/src/node/utils/padDiff.js +++ b/src/node/utils/padDiff.js @@ -1,74 +1,554 @@ -exports.createDiff = function(padID, startRev, endRev, callback){ -console.warn("WTF"); - - //check if rev is a number - if(startRev !== undefined && typeof startRev != "number") +var Changeset = require("../../static/js/Changeset"); +var async = require("async"); +var exportHtml = require('./ExportHtml'); + +function PadDiff (pad, fromRev, toRev){ + //check parameters + if(!pad || !pad.id || !pad.atext || !pad.pool) { - //try to parse the number - if(!isNaN(parseInt(startRev))) - { - startRev = parseInt(startRev, 10); - } - else - { - callback({stop: "startRev is not a number"}); - return; - } + throw new Error('Invalid pad'); } - //check if rev is a number - if(endRev !== undefined && typeof endRev != "number") - { - //try to parse the number - if(!isNaN(parseInt(endRev))) - { - endRev = parseInt(endRev, 10); - } - else - { - callback({stop: "endRev is not a number"}); - return; - } + var range = pad.getValidRevisionRange(fromRev, toRev); + if(!range) { throw new Error('Invalid revision range.' + + ' startRev: ' + fromRev + + ' endRev: ' + toRev); } + + this._pad = pad; + this._fromRev = range.startRev; + this._toRev = range.endRev; + this._html = null; + this._authors = []; +} + +PadDiff.prototype._isClearAuthorship = function(changeset){ + //unpack + var unpacked = Changeset.unpack(changeset); + + //check if there is nothing in the charBank + if(unpacked.charBank !== "") + return false; + + //check if oldLength == newLength + if(unpacked.oldLen !== unpacked.newLen) + return false; + + //lets iterator over the operators + var iterator = Changeset.opIterator(unpacked.ops); + + //get the first operator, this should be a clear operator + var clearOperator = iterator.next(); + + //check if there is only one operator + if(iterator.hasNext() === true) + return false; + + //check if this operator doesn't change text + if(clearOperator.opcode !== "=") + return false; + + //check that this operator applys to the complete text + //if the text ends with a new line, its exactly one character less, else it has the same length + if(clearOperator.chars !== unpacked.oldLen-1 && clearOperator.chars !== unpacked.oldLen) + return false; + + var attributes = []; + Changeset.eachAttribNumber(changeset, function(attrNum){ + attributes.push(attrNum); + }); + + //check that this changeset uses only one attribute + if(attributes.length !== 1) + return false; + + var appliedAttribute = this._pad.pool.getAttrib(attributes[0]); + + //check if the applied attribute is an anonymous author attribute + if(appliedAttribute[0] !== "author" || appliedAttribute[1] !== "") + return false; + + return true; +} + +PadDiff.prototype._createClearAuthorship = function(rev, callback){ + var self = this; + this._pad.getInternalRevisionAText(rev, function(err, atext){ + if(err){ + return callback(err); + } + + //build clearAuthorship changeset + var builder = Changeset.builder(atext.text.length); + builder.keepText(atext.text, [['author','']], self._pad.pool); + var changeset = builder.toString(); + + callback(null, changeset); + }); +} + +PadDiff.prototype._createClearStartAtext = function(rev, callback){ + var self = this; + + //get the atext of this revision + this._pad.getInternalRevisionAText(rev, function(err, atext){ + if(err){ + return callback(err); + } + + //create the clearAuthorship changeset + self._createClearAuthorship(rev, function(err, changeset){ + if(err){ + return callback(err); + } + + //apply the clearAuthorship changeset + var newAText = Changeset.applyToAText(changeset, atext, self._pad.pool); + + callback(null, newAText); + }); + }); +} + +PadDiff.prototype._getChangesetsInBulk = function(startRev, count, callback) { + var self = this; + + //find out which revisions we need + var revisions = []; + for(var i=startRev;i<(startRev+count) && i<=this._pad.head;i++){ + revisions.push(i); } + + var changesets = [], authors = []; + + //get all needed revisions + async.forEach(revisions, function(rev, callback){ + self._pad.getRevision(rev, function(err, revision){ + if(err){ + return callback(err) + } + + var arrayNum = rev-startRev; + + changesets[arrayNum] = revision.changeset; + authors[arrayNum] = revision.meta.author; + + callback(); + }); + }, function(err){ + callback(err, changesets, authors); + }); +} - //get the pad - getPadSafe(padID, true, function(err, pad) - { - if(err){ - return callback(err); +PadDiff.prototype._addAuthors = function(authors) { + var self = this; + //add to array if not in the array + authors.forEach(function(author){ + if(self._authors.indexOf(author) == -1){ + self._authors.push(author); } + }); +} - try { - var padDiff = new PadDiff(pad, startRev, endRev); - } catch(e) { - return callback({stop:e.message}); - } +PadDiff.prototype._createDiffAtext = function(callback) { + var self = this; + var bulkSize = 100; + + //get the cleaned startAText + self._createClearStartAtext(self._fromRev, function(err, atext){ + if(err) { return callback(err); } + + var superChangeset = null; + + var rev = self._fromRev + 1; - var html, authors; - - async.series([ - function(callback){ - padDiff.getHtml(function(err, _html){ - if(err){ - return callback(err); + //async while loop + async.whilst( + //loop condition + function () { return rev <= self._toRev; }, + + //loop body + function (callback) { + //get the bulk + self._getChangesetsInBulk(rev,bulkSize,function(err, changesets, authors){ + var addedAuthors = []; + + //run trough all changesets + for(var i=0;i= curChar) { + curLineNextOp.chars -= (curChar - indexIntoLine); + done = true; + } else { + indexIntoLine += curLineNextOp.chars; + } + } + } + + while (numChars > 0) { + if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext())) { + curLine++; + curChar = 0; + curLineOpIterLine = curLine; + curLineNextOp.chars = 0; + curLineOpIter = Changeset.opIterator(alines_get(curLine)); + } + if (!curLineNextOp.chars) { + curLineOpIter.next(curLineNextOp); + } + var charsToUse = Math.min(numChars, curLineNextOp.chars); + func(charsToUse, curLineNextOp.attribs, charsToUse == curLineNextOp.chars && curLineNextOp.lines > 0); + numChars -= charsToUse; + curLineNextOp.chars -= charsToUse; + curChar += charsToUse; + } + + if ((!curLineNextOp.chars) && (!curLineOpIter.hasNext())) { + curLine++; + curChar = 0; + } + } + + function skip(N, L) { + if (L) { + curLine += L; + curChar = 0; + } else { + if (curLineOpIter && curLineOpIterLine == curLine) { + consumeAttribRuns(N, function () {}); + } else { + curChar += N; + } + } + } + + function nextText(numChars) { + var len = 0; + var assem = Changeset.stringAssembler(); + var firstString = lines_get(curLine).substring(curChar); + len += firstString.length; + assem.append(firstString); + + var lineNum = curLine + 1; + while (len < numChars) { + var nextString = lines_get(lineNum); + len += nextString.length; + assem.append(nextString); + lineNum++; + } + + return assem.toString().substring(0, numChars); + } + + function cachedStrFunc(func) { + var cache = {}; + return function (s) { + if (!cache[s]) { + cache[s] = func(s); + } + return cache[s]; + }; + } + + var attribKeys = []; + var attribValues = []; + + //iterate over all operators of this changeset + while (csIter.hasNext()) { + var csOp = csIter.next(); + + if (csOp.opcode == '=') { + var textBank = nextText(csOp.chars); + + // decide if this equal operator is an attribution change or not. We can see this by checkinf if attribs is set. + // If the text this operator applies to is only a star, than this is a false positive and should be ignored + if (csOp.attribs && textBank != "*") { + var deletedAttrib = apool.putAttrib(["removed", true]); + var authorAttrib = apool.putAttrib(["author", ""]);; + + attribKeys.length = 0; + attribValues.length = 0; + Changeset.eachAttribNumber(csOp.attribs, function (n) { + attribKeys.push(apool.getAttribKey(n)); + attribValues.push(apool.getAttribValue(n)); + + if(apool.getAttribKey(n) === "author"){ + authorAttrib = n; + }; + }); + + var undoBackToAttribs = cachedStrFunc(function (attribs) { + var backAttribs = []; + for (var i = 0; i < attribKeys.length; i++) { + var appliedKey = attribKeys[i]; + var appliedValue = attribValues[i]; + var oldValue = Changeset.attribsAttributeValue(attribs, appliedKey, apool); + if (appliedValue != oldValue) { + backAttribs.push([appliedKey, oldValue]); + } + } + return Changeset.makeAttribsString('=', backAttribs, apool); + }); + + var oldAttribsAddition = "*" + Changeset.numToString(deletedAttrib) + "*" + Changeset.numToString(authorAttrib); + + var textLeftToProcess = textBank; + + while(textLeftToProcess.length > 0){ + //process till the next line break or process only one line break + var lengthToProcess = textLeftToProcess.indexOf("\n"); + var lineBreak = false; + switch(lengthToProcess){ + case -1: + lengthToProcess=textLeftToProcess.length; + break; + case 0: + lineBreak = true; + lengthToProcess=1; + break; + } + + //get the text we want to procceed in this step + var processText = textLeftToProcess.substr(0, lengthToProcess); + textLeftToProcess = textLeftToProcess.substr(lengthToProcess); + + if(lineBreak){ + builder.keep(1, 1); //just skip linebreaks, don't do a insert + keep for a linebreak + + //consume the attributes of this linebreak + consumeAttribRuns(1, function(){}); + } else { + //add the old text via an insert, but add a deletion attribute + the author attribute of the author who deleted it + var textBankIndex = 0; + consumeAttribRuns(lengthToProcess, function (len, attribs, endsLine) { + //get the old attributes back + var attribs = (undoBackToAttribs(attribs) || "") + oldAttribsAddition; + + builder.insert(processText.substr(textBankIndex, len), attribs); + textBankIndex += len; + }); + + builder.keep(lengthToProcess, 0); + } + } + } else { + skip(csOp.chars, csOp.lines); + builder.keep(csOp.chars, csOp.lines); + } + } else if (csOp.opcode == '+') { + builder.keep(csOp.chars, csOp.lines); + } else if (csOp.opcode == '-') { + var textBank = nextText(csOp.chars); + var textBankIndex = 0; + + consumeAttribRuns(csOp.chars, function (len, attribs, endsLine) { + builder.insert(textBank.substr(textBankIndex, len), attribs + csOp.attribs); + textBankIndex += len; + }); + } + } + + return Changeset.checkRep(builder.toString()); +}; + +//export the constructor +module.exports = PadDiff; From f1b9c213eef910f7f4b94e40b526206aa9763b35 Mon Sep 17 00:00:00 2001 From: John McLear Date: Tue, 22 Jan 2013 23:37:53 +0000 Subject: [PATCH 05/22] and semi working --- src/node/db/Pad.js | 41 ++++++++++++++++++++++++++++++++++++ src/node/utils/ExportHtml.js | 2 +- src/node/utils/padDiff.js | 7 ++++-- 3 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index da1ce9e1..037886ea 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -213,6 +213,47 @@ Pad.prototype.getInternalRevisionAText = function getInternalRevisionAText(targe }); }; +Pad.prototype.getRevision = function getRevisionChangeset(revNum, callback) { + db.get("pad:"+this.id+":revs:"+revNum, callback); +}; + +Pad.prototype.getAllAuthorColors = function getAllAuthorColors(callback){ + var authors = this.getAllAuthors(); + var returnTable = {}; + var colorPalette = authorManager.getColorPalette(); + + async.forEach(authors, function(author, callback){ + authorManager.getAuthorColorId(author, function(err, colorId){ + if(err){ + return callback(err); + } + returnTable[author]=colorPalette[colorId]; + + callback(); + }); + }, function(err){ + callback(err, returnTable); + }); +}; + +Pad.prototype.getValidRevisionRange = function getValidRevisionRange(startRev, endRev) { + startRev = parseInt(startRev, 10); + var head = this.getHeadRevisionNumber(); + endRev = endRev ? parseInt(endRev, 10) : head; + if(isNaN(startRev) || startRev < 0 || startRev > head) { + startRev = null; + } + if(isNaN(endRev) || endRev < startRev) { + endRev = null; + } else if(endRev > head) { + endRev = head; + } + if(startRev !== null && endRev !== null) { + return { startRev: startRev , endRev: endRev } + } + return null; +}; + Pad.prototype.getKeyRevisionNumber = function getKeyRevisionNumber(revNum) { return Math.floor(revNum / 100) * 100; }; diff --git a/src/node/utils/ExportHtml.js b/src/node/utils/ExportHtml.js index 35403013..f385d470 100644 --- a/src/node/utils/ExportHtml.js +++ b/src/node/utils/ExportHtml.js @@ -92,7 +92,7 @@ function getPadHTML(pad, revNum, callback) exports.getPadHTML = getPadHTML; -function getHTMLFromAtext(pad, atext) +exports.getHTMLFromAtext = function(pad, atext) { var apool = pad.apool(); var textLines = atext.text.slice(0, -1).split('\n'); diff --git a/src/node/utils/padDiff.js b/src/node/utils/padDiff.js index f898cbe1..b1fa9277 100644 --- a/src/node/utils/padDiff.js +++ b/src/node/utils/padDiff.js @@ -244,14 +244,17 @@ PadDiff.prototype.getHtml = function(callback){ }, //get the authorColor table function(callback){ - self._pad.getAllAuthorColors(function(err, _authorColors){ + /* + self._pad.getAllAuthorColors(function(err, _authorColors){ // TODO if(err){ return callback(err); } authorColors = _authorColors; - callback(); }); + */ + authorColors = {}; + callback(); }, //convert the atext to html function(callback){ From 77403942eebdf9f6f103a858ceec72899d68574b Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 27 Jan 2013 03:08:21 +0000 Subject: [PATCH 06/22] fix make file issue --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4e870a45..c63bb0bf 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ out/doc/assets/%: doc/assets/% out/doc/%.html: doc/%.md mkdir -p $(@D) node tools/doc/generate.js --format=html --template=doc/template.html $< > $@ - cat $@ | sed 's/__VERSION__/${VERSION}/' > $@ + sed -i 's/__VERSION__/${VERSION}/' $@ clean: rm -rf out/ From 7432b7aff94775419333c955044e62635cabd6b6 Mon Sep 17 00:00:00 2001 From: mluto Date: Sun, 27 Jan 2013 11:02:15 +0100 Subject: [PATCH 07/22] Rewrote getParams() to be more dynamic and shorter --- src/static/js/pad.js | 103 ++++++++++++------------------------------- 1 file changed, 28 insertions(+), 75 deletions(-) diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 64d8b42b..9f0fba7f 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -101,86 +101,39 @@ function randomString() return "t." + randomstring; } +// This array represents all GET-parameters which can be used to change a setting. +// name: the parameter-name, eg `?noColors=true` => `noColors` +// checkVal: the callback is only executed when +// * the parameter was supplied and matches checkVal +// * the parameter was supplied and checkVal is null +// callback: the function to call when all above succeeds, `val` is the value supplied by the user +var paramSettings = [ + { name: "noColors", checkVal: "true", callback: function(val) { settings.noColors = true; $('#clearAuthorship').hide(); } }, + { name: "showControls", checkVal: "false", callback: function(val) { $('#editbar').hide(); $('#editorcontainer').css({"top":"0px"}); } }, + { name: "showChat", checkVal: "false", callback: function(val) { $('#chaticon').hide(); } }, + { name: "showLineNumbers", checkVal: "false", callback: function(val) { settings.LineNumbersDisabled = true; } }, + { name: "useMonospaceFont", checkVal: "true", callback: function(val) { settings.useMonospaceFontGlobal = true; } }, + // If the username is set as a parameter we should set a global value that we can call once we have initiated the pad. + { name: "userName", checkVal: null, callback: function(val) { settings.globalUserName = decodeURIComponent(val); } }, + // If the userColor is set as a parameter, set a global value to use once we have initiated the pad. + { name: "userColor", checkVal: null, callback: function(val) { settings.globalUserColor = decodeURIComponent(val); } }, + { name: "rtl", checkVal: "true", callback: function(val) { settings.rtlIsTrue = true } }, + { name: "alwaysShowChat", checkVal: "true", callback: function(val) { chat.stickToScreen(); } }, + { name: "lang", checkVal: null, callback: function(val) { window.html10n.localize([val, 'en']); } } +]; + function getParams() { var params = getUrlVars() - var showControls = params["showControls"]; - var showChat = params["showChat"]; - var userName = params["userName"]; - var userColor = params["userColor"]; - var showLineNumbers = params["showLineNumbers"]; - var useMonospaceFont = params["useMonospaceFont"]; - var IsnoColors = params["noColors"]; - var rtl = params["rtl"]; - var alwaysShowChat = params["alwaysShowChat"]; - var lang = params["lang"]; - - if(IsnoColors) + + for(var i = 0; i < paramSettings.length; i++) { - if(IsnoColors == "true") + var setting = paramSettings[i]; + var value = params[setting.name]; + + if(value && (value == setting.checkVal || setting.checkVal == null)) { - settings.noColors = true; - $('#clearAuthorship').hide(); - } - } - if(showControls) - { - if(showControls == "false") - { - $('#editbar').hide(); - $('#editorcontainer').css({"top":"0px"}); - } - } - if(showChat) - { - if(showChat == "false") - { - $('#chaticon').hide(); - } - } - if(showLineNumbers) - { - if(showLineNumbers == "false") - { - settings.LineNumbersDisabled = true; - } - } - if(useMonospaceFont) - { - if(useMonospaceFont == "true") - { - settings.useMonospaceFontGlobal = true; - } - } - if(userName) - { - // If the username is set as a parameter we should set a global value that we can call once we have initiated the pad. - settings.globalUserName = decodeURIComponent(userName); - } - if(userColor) - // If the userColor is set as a parameter, set a global value to use once we have initiated the pad. - { - settings.globalUserColor = decodeURIComponent(userColor); - } - if(rtl) - { - if(rtl == "true") - { - settings.rtlIsTrue = true - } - } - if(alwaysShowChat) - { - if(alwaysShowChat == "true") - { - chat.stickToScreen(); - } - } - if(lang) - { - if(lang !== "") - { - window.html10n.localize([lang, 'en']); + setting.callback(value); } } } From f4690dda9dec3ba9afce3f22b49f91a624d4fae4 Mon Sep 17 00:00:00 2001 From: Peter 'Pita' Martischka Date: Sun, 27 Jan 2013 15:40:05 +0000 Subject: [PATCH 08/22] fixed indent --- src/node/handler/APIHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 31b4b187..9d017b28 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -180,7 +180,7 @@ var version = , "deleteGroup" : ["groupID"] , "listPads" : ["groupID"] , "listAllPads" : [] - , "createDiff" : ["padID", "startRev", "endRev"] + , "createDiff" : ["padID", "startRev", "endRev"] , "createPad" : ["padID", "text"] , "createGroupPad" : ["groupID", "padName", "text"] , "createAuthor" : ["name"] From dcfb1b2ea4bd3ee8783c6a01aeebc8c760aa7a06 Mon Sep 17 00:00:00 2001 From: Peter 'Pita' Martischka Date: Sun, 27 Jan 2013 15:40:37 +0000 Subject: [PATCH 09/22] Added missing functions to create pad diffs --- src/static/js/Changeset.js | 118 +++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/src/static/js/Changeset.js b/src/static/js/Changeset.js index cfea4362..b1604212 100644 --- a/src/static/js/Changeset.js +++ b/src/static/js/Changeset.js @@ -2182,3 +2182,121 @@ exports.followAttributes = function (att1, att2, pool) { } return buf.toString(); }; + +exports.composeWithDeletions = function (cs1, cs2, pool) { + var unpacked1 = exports.unpack(cs1); + var unpacked2 = exports.unpack(cs2); + var len1 = unpacked1.oldLen; + var len2 = unpacked1.newLen; + exports.assert(len2 == unpacked2.oldLen, "mismatched composition"); + var len3 = unpacked2.newLen; + var bankIter1 = exports.stringIterator(unpacked1.charBank); + var bankIter2 = exports.stringIterator(unpacked2.charBank); + var bankAssem = exports.stringAssembler(); + + var newOps = exports.applyZip(unpacked1.ops, 0, unpacked2.ops, 0, function (op1, op2, opOut) { + var op1code = op1.opcode; + var op2code = op2.opcode; + if (op1code == '+' && op2code == '-') { + bankIter1.skip(Math.min(op1.chars, op2.chars)); + } + exports._slicerZipperFuncWithDeletions(op1, op2, opOut, pool); + if (opOut.opcode == '+') { + if (op2code == '+') { + bankAssem.append(bankIter2.take(opOut.chars)); + } else { + bankAssem.append(bankIter1.take(opOut.chars)); + } + } + }); + + return exports.pack(len1, len3, newOps, bankAssem.toString()); +}; + +// This function is 95% like _slicerZipperFunc, we just changed two lines to ensure it merges the attribs of deletions properly. +// This is necassary for correct paddiff. But to ensure these changes doesn't affect anything else, we've created a seperate function only used for paddiffs +exports._slicerZipperFuncWithDeletions= function (attOp, csOp, opOut, pool) { + // attOp is the op from the sequence that is being operated on, either an + // attribution string or the earlier of two exportss being composed. + // pool can be null if definitely not needed. + //print(csOp.toSource()+" "+attOp.toSource()+" "+opOut.toSource()); + if (attOp.opcode == '-') { + exports.copyOp(attOp, opOut); + attOp.opcode = ''; + } else if (!attOp.opcode) { + exports.copyOp(csOp, opOut); + csOp.opcode = ''; + } else { + switch (csOp.opcode) { + case '-': + { + if (csOp.chars <= attOp.chars) { + // delete or delete part + if (attOp.opcode == '=') { + opOut.opcode = '-'; + opOut.chars = csOp.chars; + opOut.lines = csOp.lines; + opOut.attribs = csOp.attribs; //changed by yammer + } + attOp.chars -= csOp.chars; + attOp.lines -= csOp.lines; + csOp.opcode = ''; + if (!attOp.chars) { + attOp.opcode = ''; + } + } else { + // delete and keep going + if (attOp.opcode == '=') { + opOut.opcode = '-'; + opOut.chars = attOp.chars; + opOut.lines = attOp.lines; + opOut.attribs = csOp.attribs; //changed by yammer + } + csOp.chars -= attOp.chars; + csOp.lines -= attOp.lines; + attOp.opcode = ''; + } + break; + } + case '+': + { + // insert + exports.copyOp(csOp, opOut); + csOp.opcode = ''; + break; + } + case '=': + { + if (csOp.chars <= attOp.chars) { + // keep or keep part + opOut.opcode = attOp.opcode; + opOut.chars = csOp.chars; + opOut.lines = csOp.lines; + opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool); + csOp.opcode = ''; + attOp.chars -= csOp.chars; + attOp.lines -= csOp.lines; + if (!attOp.chars) { + attOp.opcode = ''; + } + } else { + // keep and keep going + opOut.opcode = attOp.opcode; + opOut.chars = attOp.chars; + opOut.lines = attOp.lines; + opOut.attribs = exports.composeAttributes(attOp.attribs, csOp.attribs, attOp.opcode == '=', pool); + attOp.opcode = ''; + csOp.chars -= attOp.chars; + csOp.lines -= attOp.lines; + } + break; + } + case '': + { + exports.copyOp(attOp, opOut); + attOp.opcode = ''; + break; + } + } + } +}; From 6f743c6ee21dc96a286d2f52c3902bce11f7e19d Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 27 Jan 2013 16:45:01 +0000 Subject: [PATCH 10/22] make makefile work for darwin(mac) --- Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c63bb0bf..09dbf0f3 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ outdoc_files = $(addprefix out/,$(doc_sources:.md=.html)) docassets = $(addprefix out/,$(wildcard doc/assets/*)) VERSION = $(shell node -e "console.log( require('./src/package.json').version )") +UNAME := $(shell uname -s) docs: $(outdoc_files) $(docassets) @@ -14,7 +15,10 @@ out/doc/assets/%: doc/assets/% out/doc/%.html: doc/%.md mkdir -p $(@D) node tools/doc/generate.js --format=html --template=doc/template.html $< > $@ - sed -i 's/__VERSION__/${VERSION}/' $@ + ifeq ($(UNAME),Darwin) + sed -i '' 's/__VERSION__/${VERSION}/' $@ + else + sed -i 's/__VERSION__/${VERSION}/' $@ clean: rm -rf out/ From 07a267be7a372df4e2d7a899d4af5ba7b30057b8 Mon Sep 17 00:00:00 2001 From: Peter 'Pita' Martischka Date: Sun, 27 Jan 2013 16:45:09 +0000 Subject: [PATCH 11/22] Added colors to pad diff --- src/node/db/API.js | 1 - src/node/db/AuthorManager.js | 4 ++ src/node/db/Pad.js | 3 +- src/node/handler/PadMessageHandler.js | 2 +- src/node/utils/ExportHtml.js | 91 +++++++++++++++++++++++---- src/node/utils/padDiff.js | 9 +-- 6 files changed, 89 insertions(+), 21 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index 2c8b91ab..ef341bef 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -618,7 +618,6 @@ exports.createDiff = function(padID, startRev, endRev, callback){ try { var padDiff = new PadDiff(pad, startRev, endRev); } catch(e) { - // console.warn(e.stack); return callback({stop:e.message}); } var html, authors; diff --git a/src/node/db/AuthorManager.js b/src/node/db/AuthorManager.js index 28b2dd91..667e0605 100644 --- a/src/node/db/AuthorManager.js +++ b/src/node/db/AuthorManager.js @@ -24,6 +24,10 @@ var db = require("./DB").db; var async = require("async"); var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; +exports.getColorPalette = function(){ + return ["#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1", "#ff8f8f", "#ffe38f", "#c7ff8f", "#8fffab", "#8fffff", "#8fabff", "#c78fff", "#ff8fe3", "#d97979", "#d9c179", "#a9d979", "#79d991", "#79d9d9", "#7991d9", "#a979d9", "#d979c1", "#d9a9a9", "#d9cda9", "#c1d9a9", "#a9d9b5", "#a9d9d9", "#a9b5d9", "#c1a9d9", "#d9a9cd", "#4c9c82", "#12d1ad", "#2d8e80", "#7485c3", "#a091c7", "#3185ab", "#6818b4", "#e6e76d", "#a42c64", "#f386e5", "#4ecc0c", "#c0c236", "#693224", "#b5de6a", "#9b88fd", "#358f9b", "#496d2f", "#e267fe", "#d23056", "#1a1a64", "#5aa335", "#d722bb", "#86dc6c", "#b5a714", "#955b6a", "#9f2985", "#4b81c8", "#3d6a5b", "#434e16", "#d16084", "#af6a0e", "#8c8bd8"]; +}; + /** * Checks if the author exists */ diff --git a/src/node/db/Pad.js b/src/node/db/Pad.js index 037886ea..4701e82a 100644 --- a/src/node/db/Pad.js +++ b/src/node/db/Pad.js @@ -227,7 +227,8 @@ Pad.prototype.getAllAuthorColors = function getAllAuthorColors(callback){ if(err){ return callback(err); } - returnTable[author]=colorPalette[colorId]; + //colorId might be a hex color or an number out of the palette + returnTable[author]=colorPalette[colorId] || colorId; callback(); }); diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js index 434c25ad..24f72c79 100644 --- a/src/node/handler/PadMessageHandler.js +++ b/src/node/handler/PadMessageHandler.js @@ -1028,7 +1028,7 @@ function handleClientReady(client, message) "globalPadId": message.padId, "time": currentTime, }, - "colorPalette": ["#ffc7c7", "#fff1c7", "#e3ffc7", "#c7ffd5", "#c7ffff", "#c7d5ff", "#e3c7ff", "#ffc7f1", "#ff8f8f", "#ffe38f", "#c7ff8f", "#8fffab", "#8fffff", "#8fabff", "#c78fff", "#ff8fe3", "#d97979", "#d9c179", "#a9d979", "#79d991", "#79d9d9", "#7991d9", "#a979d9", "#d979c1", "#d9a9a9", "#d9cda9", "#c1d9a9", "#a9d9b5", "#a9d9d9", "#a9b5d9", "#c1a9d9", "#d9a9cd", "#4c9c82", "#12d1ad", "#2d8e80", "#7485c3", "#a091c7", "#3185ab", "#6818b4", "#e6e76d", "#a42c64", "#f386e5", "#4ecc0c", "#c0c236", "#693224", "#b5de6a", "#9b88fd", "#358f9b", "#496d2f", "#e267fe", "#d23056", "#1a1a64", "#5aa335", "#d722bb", "#86dc6c", "#b5a714", "#955b6a", "#9f2985", "#4b81c8", "#3d6a5b", "#434e16", "#d16084", "#af6a0e", "#8c8bd8"], + "colorPalette": authorManager.getColorPalette(), "clientIp": "127.0.0.1", "userIsGuest": true, "userColor": authorColorId, diff --git a/src/node/utils/ExportHtml.js b/src/node/utils/ExportHtml.js index f385d470..d9ba3df4 100644 --- a/src/node/utils/ExportHtml.js +++ b/src/node/utils/ExportHtml.js @@ -1,12 +1,12 @@ /** * Copyright 2009 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS-IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -92,7 +92,7 @@ function getPadHTML(pad, revNum, callback) exports.getPadHTML = getPadHTML; -exports.getHTMLFromAtext = function(pad, atext) +exports.getHTMLFromAtext = function(pad, atext, authorColors) { var apool = pad.apool(); var textLines = atext.text.slice(0, -1).split('\n'); @@ -101,6 +101,42 @@ exports.getHTMLFromAtext = function(pad, atext) var tags = ['h1', 'h2', 'strong', 'em', 'u', 's']; var props = ['heading1', 'heading2', 'bold', 'italic', 'underline', 'strikethrough']; var anumMap = {}; + var css = ""; + + var stripDotFromAuthorID = function(id){ + return id.replace(/\./g,'_'); + }; + + if(authorColors){ + css+=""; + } props.forEach(function (propName, i) { @@ -125,22 +161,53 @@ exports.getHTMLFromAtext = function(pad, atext) // Just bold Bold and italics Just italics var taker = Changeset.stringIterator(text); var assem = Changeset.stringAssembler(); - var openTags = []; + + function getSpanClassFor(i){ + //return if author colors are disabled + if (!authorColors) return false; + + var property = props[i]; + + if(property.substr(0,6) === "author"){ + return stripDotFromAuthorID(property); + } + + if(property === "removed"){ + return "removed"; + } + + return false; + } + function emitOpenTag(i) { openTags.unshift(i); - assem.append('<'); - assem.append(tags[i]); - assem.append('>'); + var spanClass = getSpanClassFor(i); + + if(spanClass){ + assem.append(''); + } else { + assem.append('<'); + assem.append(tags[i]); + assem.append('>'); + } } function emitCloseTag(i) { openTags.shift(); - assem.append(''); + var spanClass = getSpanClassFor(i); + + if(spanClass){ + assem.append(''); + } else { + assem.append(''); + } } function orderdCloseTags(tags2close) @@ -303,7 +370,7 @@ exports.getHTMLFromAtext = function(pad, atext) return _processSpaces(assem.toString()); } // end getLineHTML - var pieces = []; + var pieces = [css]; // Need to deal with constraints imposed on HTML lists; can // only gain one level of nesting at once, can't change type diff --git a/src/node/utils/padDiff.js b/src/node/utils/padDiff.js index b1fa9277..1b3cf58f 100644 --- a/src/node/utils/padDiff.js +++ b/src/node/utils/padDiff.js @@ -244,17 +244,14 @@ PadDiff.prototype.getHtml = function(callback){ }, //get the authorColor table function(callback){ - /* - self._pad.getAllAuthorColors(function(err, _authorColors){ // TODO + self._pad.getAllAuthorColors(function(err, _authorColors){ if(err){ return callback(err); } authorColors = _authorColors; + callback(); }); - */ - authorColors = {}; - callback(); }, //convert the atext to html function(callback){ @@ -265,7 +262,7 @@ PadDiff.prototype.getHtml = function(callback){ ], function(err){ callback(err, html); }); -} +}; PadDiff.prototype.getAuthors = function(callback){ var self = this; From d478ae23863f85dd1918e4b9494a717592bd60fd Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 27 Jan 2013 16:59:52 +0000 Subject: [PATCH 12/22] take two at fixin Mac issue --- Makefile | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 09dbf0f3..b656d5d9 100644 --- a/Makefile +++ b/Makefile @@ -15,10 +15,11 @@ out/doc/assets/%: doc/assets/% out/doc/%.html: doc/%.md mkdir -p $(@D) node tools/doc/generate.js --format=html --template=doc/template.html $< > $@ - ifeq ($(UNAME),Darwin) - sed -i '' 's/__VERSION__/${VERSION}/' $@ - else - sed -i 's/__VERSION__/${VERSION}/' $@ +ifeq ($(UNAME),Darwin) + sed -i '' 's/__VERSION__/${VERSION}/' $@ +else + sed -i 's/__VERSION__/${VERSION}/' $@ +endif clean: rm -rf out/ From 878fd7631c2f4df82620fa3b8642ba856519d584 Mon Sep 17 00:00:00 2001 From: Peter 'Pita' Martischka Date: Sun, 27 Jan 2013 17:25:50 +0000 Subject: [PATCH 13/22] Fixed HTML export --- src/node/utils/ExportHtml.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node/utils/ExportHtml.js b/src/node/utils/ExportHtml.js index d9ba3df4..06919488 100644 --- a/src/node/utils/ExportHtml.js +++ b/src/node/utils/ExportHtml.js @@ -91,8 +91,9 @@ function getPadHTML(pad, revNum, callback) } exports.getPadHTML = getPadHTML; +exports.getHTMLFromAtext = getHTMLFromAtext; -exports.getHTMLFromAtext = function(pad, atext, authorColors) +function getHTMLFromAtext(pad, atext, authorColors) { var apool = pad.apool(); var textLines = atext.text.slice(0, -1).split('\n'); From ed5644d4e5280c73db9a1862fd96dda3a5e8b132 Mon Sep 17 00:00:00 2001 From: John McLear Date: Sun, 27 Jan 2013 17:51:40 +0000 Subject: [PATCH 14/22] docs --- src/node/db/API.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index ef341bef..0eb404e4 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -574,8 +574,8 @@ createDiff(padID, startRev, endRev) returns an object of diffs from 2 points in Example returns: -TODO {"code":0,"message":"ok","data":null} -TODO {"code":4,"message":"no or wrong API Key","data":null} +{"code":0,"message":"ok","data":{"html":"Welcome to Etherpad Lite!

This pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!

Get involved with Etherpad at http://etherpad.org
aw

","authors":["a.HKIv23mEbachFYfH",""]}} +{"code":4,"message":"no or wrong API Key","data":null} */ exports.createDiff = function(padID, startRev, endRev, callback){ //check if rev is a number From 75b861e93b4c6a6456fab4a824b14a0ae54e3b2c Mon Sep 17 00:00:00 2001 From: Siebrand Mazeland Date: Sun, 27 Jan 2013 19:41:00 +0000 Subject: [PATCH 15/22] Localisation updates from http://translatewiki.net. --- src/locales/ast.json | 3 +++ src/locales/az.json | 12 +++++++++- src/locales/da.json | 1 + src/locales/de.json | 2 ++ src/locales/es.json | 1 + src/locales/fi.json | 4 +++- src/locales/it.json | 1 + src/locales/ml.json | 16 ++++++------- src/locales/nl.json | 2 ++ src/locales/oc.json | 33 +++++++++++++++++++++---- src/locales/pl.json | 1 + src/locales/ps.json | 52 +++++++++++++++++++++++++++++++++++++++- src/locales/pt-br.json | 1 + src/locales/ru.json | 26 +++++++++++++++++++- src/locales/sl.json | 1 + src/locales/uk.json | 1 + src/locales/zh-hant.json | 1 + 17 files changed, 141 insertions(+), 17 deletions(-) diff --git a/src/locales/ast.json b/src/locales/ast.json index 1437d869..7beb706a 100644 --- a/src/locales/ast.json +++ b/src/locales/ast.json @@ -78,6 +78,7 @@ "pad.share.emebdcode": "Incrustar URL", "pad.chat": "Chat", "pad.chat.title": "Abrir el chat d'esti bloc.", + "pad.chat.loadmessages": "Cargar m\u00e1s mensaxes", "timeslider.pageTitle": "Eslizador de tiempu de {{appTitle}}", "timeslider.toolbar.returnbutton": "Tornar al bloc", "timeslider.toolbar.authors": "Autores:", @@ -99,6 +100,8 @@ "timeslider.month.october": "d'ochobre", "timeslider.month.november": "de payares", "timeslider.month.december": "d'avientu", + "timeslider.unnamedauthor": "{{num}} autor an\u00f3nimu", + "timeslider.unnamedauthors": "{{num}} autores an\u00f3nimos", "pad.savedrevs.marked": "Esta revisi\u00f3n marcose como revisi\u00f3n guardada", "pad.userlist.entername": "Escribi'l to nome", "pad.userlist.unnamed": "ensin nome", diff --git a/src/locales/az.json b/src/locales/az.json index 1e6439fd..95c65798 100644 --- a/src/locales/az.json +++ b/src/locales/az.json @@ -50,17 +50,21 @@ "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (A\u00e7\u0131q S\u0259n\u0259d Format\u0131)", "pad.importExport.exportdokuwiki": "DokuWiki", + "pad.importExport.abiword.innerHTML": "Siz yaln\u0131z adi m\u0259tnd\u0259n v\u0259 ya HTML-d\u0259n idxal ed\u0259 bil\u0259rsiniz. \u0130dxal\u0131n daha m\u00fcr\u0259kk\u0259b funksiyalar\u0131 \u00fc\u00e7\u00fcn, z\u0259hm\u0259t olmasa, AbiWord-i qura\u015fd\u0131r\u0131n<\/a>.", "pad.modals.connected": "Ba\u011fland\u0131.", "pad.modals.reconnecting": "Sizin pad yenid\u0259n qo\u015fulur..", "pad.modals.forcereconnect": "M\u0259cbur t\u0259krar\u0259n ba\u011flan", "pad.modals.userdup": "Ba\u015fqa p\u0259nc\u0259r\u0259d\u0259 art\u0131q a\u00e7\u0131qd\u0131r", + "pad.modals.userdup.explanation": "S\u0259n\u0259d, ola bilsin ki, bu kompyuterd\u0259, brauzerin bir ne\u00e7\u0259 p\u0259nc\u0259r\u0259sind\u0259 a\u00e7\u0131lm\u0131\u015fd\u0131r.", "pad.modals.userdup.advice": "Bu p\u0259nc\u0259r\u0259d\u0259n istifad\u0259yl\u0259 yenid\u0259n qo\u015fulun.", "pad.modals.unauth": "\u0130caz\u0259li deyil", "pad.modals.unauth.explanation": "Bu s\u0259hif\u0259y\u0259 baxd\u0131\u011f\u0131n\u0131z vaxt sizin icaz\u0259niz d\u0259yi\u015filib. B\u0259rpa etm\u0259k \u00fc\u015f\u00fcn yenid\u0259n c\u0259hd edin.", "pad.modals.looping": "\u018flaq\u0259 k\u0259sildi.", "pad.modals.looping.explanation": "Sinxronla\u015fd\u0131rma serveri il\u0259 kommunikasiya x\u0259tas\u0131 var.", + "pad.modals.looping.cause": "Ola bilsin ki, siz uy\u011fun olmayan fayrvol v\u0259 ya proksi vasit\u0259si il\u0259 qo\u015fulma\u011fa c\u0259hd g\u00f6st\u0259rirsiniz.", "pad.modals.initsocketfail": "Server \u0259l\u00e7atmazd\u0131r.", "pad.modals.initsocketfail.explanation": "Sinxronla\u015fd\u0131rma serverin\u0259 qo\u015fulma m\u00fcmk\u00fcns\u00fczd\u00fcr.", + "pad.modals.initsocketfail.cause": "Ehtimal ki, bu problem sizin brauzerinizl\u0259 v\u0259 ya internet-birl\u0259\u015fm\u0259nizl\u0259 \u0259laq\u0259d\u0259rdir.", "pad.modals.slowcommit": "\u018flaq\u0259 k\u0259sildi.", "pad.modals.slowcommit.explanation": "Server cavab vermir.", "pad.modals.slowcommit.cause": "Bu \u015f\u0259b\u0259k\u0259 ba\u011flant\u0131s\u0131nda probleml\u0259r yarana bil\u0259r.", @@ -75,6 +79,7 @@ "pad.share.emebdcode": "URL-ni yay\u0131mla", "pad.chat": "S\u00f6hb\u0259t", "pad.chat.title": "Bu pad \u00fc\u00e7\u00fcn chat a\u00e7\u0131n.", + "pad.chat.loadmessages": "Daha \u00e7ox mesaj y\u00fckl\u0259", "timeslider.pageTitle": "{{appTitle}} Vaxt c\u0259dv\u0259li", "timeslider.toolbar.returnbutton": "Pad-a qay\u0131t", "timeslider.toolbar.authors": "M\u00fc\u0259llifl\u0259r:", @@ -96,6 +101,9 @@ "timeslider.month.october": "Oktyabr", "timeslider.month.november": "Noyabr", "timeslider.month.december": "Dekabr", + "timeslider.unnamedauthor": "{{num}} ads\u0131z m\u00fc\u0259llif", + "timeslider.unnamedauthors": "{{num}} ads\u0131z m\u00fc\u0259llifl\u0259r", + "pad.savedrevs.marked": "Bu versiya indi yadda\u015fa saxlanm\u0131\u015f kimi ni\u015fanland\u0131", "pad.userlist.entername": "Ad\u0131n\u0131z\u0131 daxil et", "pad.userlist.unnamed": "ads\u0131z", "pad.userlist.guest": "Qonaq", @@ -104,8 +112,10 @@ "pad.editbar.clearcolors": "B\u00fct\u00fcn s\u0259n\u0259dl\u0259rd\u0259 m\u00fc\u0259lliflik r\u0259ngl\u0259rini t\u0259mizl\u0259?", "pad.impexp.importbutton": "\u0130ndi idxal edin", "pad.impexp.importing": "\u0130dxal...", + "pad.impexp.confirmimport": "Fayl\u0131n idxal\u0131 cari m\u0259tni yenil\u0259y\u0259c\u0259k. Siz \u0259minsinizmi ki, davam etm\u0259k ist\u0259yirsiniz?", "pad.impexp.convertFailed": "Biz bu fayl idxal etm\u0259k m\u00fcmk\u00fcn deyil idi. Xahi\u015f olunur m\u00fcxt\u0259lif s\u0259n\u0259dd\u0259n istifad\u0259 edin v\u0259 ya kopyalay\u0131b yap\u0131\u015fd\u0131rmaq yolundan istifad\u0259 edin", "pad.impexp.uploadFailed": "Y\u00fckl\u0259m\u0259d\u0259 s\u0259hv, xahi\u015f olunur yen\u0259 c\u0259hd edin", "pad.impexp.importfailed": "\u0130dxal zaman\u0131 s\u0259hv", - "pad.impexp.copypaste": "Xahi\u015f edirik kopyalay\u0131b yap\u0131\u015fd\u0131r\u0131n" + "pad.impexp.copypaste": "Xahi\u015f edirik kopyalay\u0131b yap\u0131\u015fd\u0131r\u0131n", + "pad.impexp.exportdisabled": "{{ type}} format\u0131nda ixrac s\u00f6nd\u00fcr\u00fclm\u00fc\u015fd\u00fcr. \u018ftrafl\u0131 informasiya \u00fc\u00e7\u00fcn sistem administratoruna m\u00fcraci\u0259t ediniz." } \ No newline at end of file diff --git a/src/locales/da.json b/src/locales/da.json index 3e785b58..dc6c0f25 100644 --- a/src/locales/da.json +++ b/src/locales/da.json @@ -78,6 +78,7 @@ "pad.share.emebdcode": "Integrerings URL", "pad.chat": "Chat", "pad.chat.title": "\u00c5ben chat for denne pad.", + "pad.chat.loadmessages": "Indl\u00e6s flere meddelelser", "timeslider.pageTitle": "{{appTitle}} Timeslider", "timeslider.toolbar.returnbutton": "Tilbage til pad", "timeslider.toolbar.authors": "Forfattere:", diff --git a/src/locales/de.json b/src/locales/de.json index 1bdbdaf3..7c51fa91 100644 --- a/src/locales/de.json +++ b/src/locales/de.json @@ -103,6 +103,8 @@ "timeslider.month.october": "Oktober", "timeslider.month.november": "November", "timeslider.month.december": "Dezember", + "timeslider.unnamedauthor": "{{num}} unbenannter Autor", + "timeslider.unnamedauthors": "{{num}} unbenannte Autoren", "pad.savedrevs.marked": "Diese Version wurde jetzt als gespeicherte Version gekennzeichnet", "pad.userlist.entername": "Geben Sie Ihren Namen ein", "pad.userlist.unnamed": "unbenannt", diff --git a/src/locales/es.json b/src/locales/es.json index 57bc35a8..f0358a90 100644 --- a/src/locales/es.json +++ b/src/locales/es.json @@ -82,6 +82,7 @@ "pad.share.emebdcode": "Incrustar URL", "pad.chat": "Chat", "pad.chat.title": "Abrir el chat para este pad.", + "pad.chat.loadmessages": "Cargar m\u00e1s mensajes", "timeslider.pageTitle": "{{appTitle}} L\u00ednea de tiempo", "timeslider.toolbar.returnbutton": "Volver al pad", "timeslider.toolbar.authors": "Autores:", diff --git a/src/locales/fi.json b/src/locales/fi.json index 9a644bda..74f7e36c 100644 --- a/src/locales/fi.json +++ b/src/locales/fi.json @@ -5,7 +5,8 @@ "1": "Jl", "2": "Nedergard", "3": "Nike", - "5": "VezonThunder" + "5": "Veikk0.ma", + "6": "VezonThunder" } }, "index.newPad": "Uusi muistio", @@ -82,6 +83,7 @@ "pad.share.emebdcode": "Upotusosoite", "pad.chat": "Keskustelu", "pad.chat.title": "Avaa keskustelu nykyisest\u00e4 muistiosta.", + "pad.chat.loadmessages": "Lataa lis\u00e4\u00e4 viestej\u00e4", "timeslider.pageTitle": "{{appTitle}} -aikajana", "timeslider.toolbar.returnbutton": "Palaa muistioon", "timeslider.toolbar.authors": "Tekij\u00e4t:", diff --git a/src/locales/it.json b/src/locales/it.json index 8f2a9c99..c60678db 100644 --- a/src/locales/it.json +++ b/src/locales/it.json @@ -81,6 +81,7 @@ "pad.share.emebdcode": "Incorpora URL", "pad.chat": "Chat", "pad.chat.title": "Apri la chat per questo Pad.", + "pad.chat.loadmessages": "Carica altri messaggi", "timeslider.pageTitle": "Cronologia {{appTitle}}", "timeslider.toolbar.returnbutton": "Ritorna al Pad", "timeslider.toolbar.authors": "Autori:", diff --git a/src/locales/ml.json b/src/locales/ml.json index 79c66bc6..4741fe77 100644 --- a/src/locales/ml.json +++ b/src/locales/ml.json @@ -35,7 +35,7 @@ "pad.settings.myView": "\u0d0e\u0d28\u0d4d\u0d31\u0d46 \u0d15\u0d3e\u0d34\u0d4d\u0d1a", "pad.settings.stickychat": "\u0d24\u0d24\u0d4d\u0d38\u0d2e\u0d2f\u0d02 \u0d38\u0d02\u0d35\u0d3e\u0d26\u0d02 \u0d0e\u0d2a\u0d4d\u0d2a\u0d4b\u0d34\u0d41\u0d02 \u0d38\u0d4d\u0d15\u0d4d\u0d30\u0d40\u0d28\u0d3f\u0d7d \u0d15\u0d3e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15", "pad.settings.colorcheck": "\u0d0e\u0d34\u0d41\u0d24\u0d4d\u0d24\u0d41\u0d15\u0d3e\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3f\u0d31\u0d19\u0d4d\u0d19\u0d7e", - "pad.settings.linenocheck": "\u0d0e\u0d23\u0d4d\u0d23\u0d2e\u0d3f\u0d1f\u0d4d\u0d1f \u0d35\u0d30\u0d3f\u0d15\u0d7e", + "pad.settings.linenocheck": "\u0d35\u0d30\u0d3f\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d15\u0d4d\u0d30\u0d2e\u0d38\u0d02\u0d16\u0d4d\u0d2f", "pad.settings.fontType": "\u0d2b\u0d4b\u0d23\u0d4d\u0d1f\u0d4d \u0d24\u0d30\u0d02:", "pad.settings.fontType.normal": "\u0d38\u0d3e\u0d27\u0d3e\u0d30\u0d23\u0d02", "pad.settings.fontType.monospaced": "\u0d2e\u0d4b\u0d23\u0d4b\u0d38\u0d4d\u0d2a\u0d47\u0d38\u0d4d", @@ -100,19 +100,19 @@ "timeslider.month.october": "\u0d12\u0d15\u0d4d\u0d1f\u0d4b\u0d2c\u0d7c", "timeslider.month.november": "\u0d28\u0d35\u0d02\u0d2c\u0d7c", "timeslider.month.december": "\u0d21\u0d3f\u0d38\u0d02\u0d2c\u0d7c", - "pad.savedrevs.marked": "\u0d08 \u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d \u0d38\u0d02\u0d30\u0d15\u0d4d\u0d37\u0d3f\u0d1a\u0d4d\u0d1a\u0d24\u0d3e\u0d2f\u0d3f \u0d05\u0d1f\u0d2f\u0d3e\u0d33\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d24\u0d4d\u0d24\u0d3f\u0d2f\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41", - "pad.userlist.entername": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d2a\u0d47\u0d30\u0d4d", + "pad.savedrevs.marked": "\u0d08 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d \u0d38\u0d47\u0d35\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3e\u0d7e\u0d2a\u0d4d\u0d2a\u0d24\u0d3f\u0d2a\u0d4d\u0d2a\u0d3e\u0d2f\u0d3f \u0d05\u0d1f\u0d2f\u0d3e\u0d33\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d24\u0d4d\u0d24\u0d3f\u0d2f\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41", + "pad.userlist.entername": "\u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15", "pad.userlist.unnamed": "\u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24", "pad.userlist.guest": "\u0d05\u0d24\u0d3f\u0d25\u0d3f", - "pad.userlist.deny": "\u0d24\u0d33\u0d4d\u0d33\u0d3f\u0d15\u0d4d\u0d15\u0d33\u0d2f\u0d41\u0d15", + "pad.userlist.deny": "\u0d28\u0d3f\u0d30\u0d38\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15", "pad.userlist.approve": "\u0d05\u0d02\u0d17\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15", - "pad.editbar.clearcolors": "\u0d30\u0d1a\u0d2f\u0d3f\u0d24\u0d3e\u0d35\u0d3f\u0d28\u0d46 \u0d38\u0d42\u0d1a\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28 \u0d28\u0d3f\u0d31\u0d19\u0d4d\u0d19\u0d33\u0d46\u0d32\u0d4d\u0d32\u0d3e\u0d02 \u0d15\u0d33\u0d2f\u0d23\u0d4b?", + "pad.editbar.clearcolors": "\u0d21\u0d4b\u0d15\u0d4d\u0d2f\u0d41\u0d2e\u0d46\u0d28\u0d4d\u0d31\u0d3f\u0d7d \u0d30\u0d1a\u0d2f\u0d3f\u0d24\u0d3e\u0d15\u0d4d\u0d15\u0d33\u0d46 \u0d38\u0d42\u0d1a\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d28\u0d3e\u0d2f\u0d3f \u0d28\u0d7d\u0d15\u0d3f\u0d2f\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d33\u0d4d\u0d33 \u0d28\u0d3f\u0d31\u0d19\u0d4d\u0d19\u0d7e \u0d12\u0d34\u0d3f\u0d35\u0d3e\u0d15\u0d4d\u0d15\u0d1f\u0d4d\u0d1f\u0d46?", "pad.impexp.importbutton": "\u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15", "pad.impexp.importing": "\u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41...", "pad.impexp.confirmimport": "\u0d12\u0d30\u0d41 \u0d2a\u0d4d\u0d30\u0d2e\u0d3e\u0d23\u0d02 \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d4d \u0d28\u0d3f\u0d32\u0d35\u0d3f\u0d32\u0d41\u0d33\u0d4d\u0d33 \u0d0e\u0d34\u0d41\u0d24\u0d4d\u0d24\u0d41\u0d15\u0d7e \u0d28\u0d37\u0d4d\u0d1f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d3e\u0d28\u0d3f\u0d1f\u0d2f\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d02, \u0d24\u0d41\u0d1f\u0d30\u0d23\u0d2e\u0d46\u0d28\u0d4d\u0d28\u0d4d \u0d09\u0d31\u0d2a\u0d4d\u0d2a\u0d3e\u0d23\u0d4b?", - "pad.impexp.convertFailed": "\u0d08 \u0d2a\u0d4d\u0d30\u0d2e\u0d3e\u0d23\u0d02 \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d38\u0d3e\u0d27\u0d3f\u0d1a\u0d4d\u0d1a\u0d3f\u0d32\u0d4d\u0d32. \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d21\u0d4b\u0d15\u0d4d\u0d2f\u0d41\u0d2e\u0d46\u0d28\u0d4d\u0d31\u0d4d \u0d2b\u0d4b\u0d7c\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15\u0d2f\u0d4b, \u0d38\u0d4d\u0d35\u0d28\u0d4d\u0d24\u0d2e\u0d3e\u0d2f\u0d3f \u0d15\u0d4b\u0d2a\u0d4d\u0d2a\u0d3f \u0d2a\u0d47\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15\u0d2f\u0d4b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d42", + "pad.impexp.convertFailed": "\u0d08 \u0d2a\u0d4d\u0d30\u0d2e\u0d3e\u0d23\u0d02 \u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d38\u0d3e\u0d27\u0d3f\u0d1a\u0d4d\u0d1a\u0d3f\u0d32\u0d4d\u0d32. \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d21\u0d4b\u0d15\u0d4d\u0d2f\u0d41\u0d2e\u0d46\u0d28\u0d4d\u0d31\u0d4d \u0d2b\u0d4b\u0d7c\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15\u0d2f\u0d4b, \u0d38\u0d4d\u0d35\u0d28\u0d4d\u0d24\u0d2e\u0d3e\u0d2f\u0d3f \u0d2a\u0d15\u0d7c\u0d24\u0d4d\u0d24\u0d3f \u0d1a\u0d47\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d15\u0d2f\u0d4b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15", "pad.impexp.uploadFailed": "\u0d05\u0d2a\u0d4d\u200c\u200c\u0d32\u0d4b\u0d21\u0d4d \u0d2a\u0d30\u0d3e\u0d1c\u0d2f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d4d\u0d1f\u0d41. \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d35\u0d40\u0d23\u0d4d\u0d1f\u0d41\u0d02 \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15", "pad.impexp.importfailed": "\u0d07\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d2e\u0d24\u0d3f \u0d2a\u0d30\u0d3e\u0d1c\u0d2f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d4d\u0d1f\u0d41", - "pad.impexp.copypaste": "\u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d15\u0d4b\u0d2a\u0d4d\u0d2a\u0d3f \u0d2a\u0d47\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15", - "pad.impexp.exportdisabled": "{{type}} \u0d2b\u0d4b\u0d7c\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d3f\u0d7d \u0d15\u0d2f\u0d31\u0d4d\u0d31\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d4d \u0d24\u0d1f\u0d1e\u0d4d\u0d1e\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41. \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d38\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d02 \u0d05\u0d21\u0d4d\u0d2e\u0d3f\u0d28\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4d\u0d30\u0d47\u0d31\u0d4d\u0d31\u0d31\u0d41\u0d2e\u0d3e\u0d2f\u0d3f \u0d2c\u0d28\u0d4d\u0d27\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d15" + "pad.impexp.copypaste": "\u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d2a\u0d15\u0d7c\u0d24\u0d4d\u0d24\u0d3f \u0d1a\u0d47\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d15", + "pad.impexp.exportdisabled": "{{type}} \u0d2b\u0d4b\u0d7c\u0d2e\u0d3e\u0d31\u0d4d\u0d31\u0d3f\u0d7d \u0d15\u0d2f\u0d31\u0d4d\u0d31\u0d41\u0d2e\u0d24\u0d3f \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d24\u0d4d \u0d24\u0d1f\u0d1e\u0d4d\u0d1e\u0d3f\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41. \u0d15\u0d42\u0d1f\u0d41\u0d24\u0d7d \u0d35\u0d3f\u0d35\u0d30\u0d19\u0d4d\u0d19\u0d7e\u0d15\u0d4d\u0d15\u0d4d \u0d24\u0d3e\u0d19\u0d4d\u0d15\u0d33\u0d41\u0d1f\u0d46 \u0d38\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d02 \u0d05\u0d21\u0d4d\u0d2e\u0d3f\u0d28\u0d3f\u0d38\u0d4d\u0d1f\u0d4d\u0d30\u0d47\u0d31\u0d4d\u0d31\u0d31\u0d41\u0d2e\u0d3e\u0d2f\u0d3f \u0d2c\u0d28\u0d4d\u0d27\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d15." } \ No newline at end of file diff --git a/src/locales/nl.json b/src/locales/nl.json index 01806053..9b1c773b 100644 --- a/src/locales/nl.json +++ b/src/locales/nl.json @@ -100,6 +100,8 @@ "timeslider.month.october": "oktober", "timeslider.month.november": "november", "timeslider.month.december": "december", + "timeslider.unnamedauthor": "{{num}} onbekende auteur", + "timeslider.unnamedauthors": "{{num}} onbekende auteurs", "pad.savedrevs.marked": "Deze versie is nu gemarkeerd als opgeslagen versie", "pad.userlist.entername": "Geef uw naam op", "pad.userlist.unnamed": "zonder naam", diff --git a/src/locales/oc.json b/src/locales/oc.json index 79e94db7..08390825 100644 --- a/src/locales/oc.json +++ b/src/locales/oc.json @@ -1,4 +1,9 @@ { + "@metadata": { + "authors": [ + "Cedric31" + ] + }, "index.newPad": "Pad nov\u00e8l", "index.createOpenPad": "o crear\/dobrir un Pad intitulat :", "pad.toolbar.bold.title": "Gras (Ctrl-B)", @@ -44,15 +49,29 @@ "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (Open Document Format)", "pad.importExport.exportdokuwiki": "DokuWiki", + "pad.importExport.abiword.innerHTML": "Pod\u00e8tz pas importar que de formats t\u00e8xte brut o html. Per de foncionalitats d'importacion mai evoluadas, installatz abiword<\/a>.", "pad.modals.connected": "Connectat.", "pad.modals.reconnecting": "Reconnexion cap a v\u00f2stre Pad...", "pad.modals.forcereconnect": "For\u00e7ar la reconnexion.", "pad.modals.userdup": "Dob\u00e8rt dins una autra fen\u00e8stra", + "pad.modals.userdup.explanation": "Sembla qu'aqueste Pad es dob\u00e8rt dins mai d'una fen\u00e8stra de v\u00f2stre navigador sus aqueste ordenador.", + "pad.modals.userdup.advice": "Se reconnectar en utilizant aquesta fen\u00e8stra.", "pad.modals.unauth": "Pas autorizat", + "pad.modals.unauth.explanation": "V\u00f2stras permissions son estadas cambiadas al moment de l'afichatge d'aquesta pagina. Ensajatz de vos reconnectar.", "pad.modals.looping": "Desconnectat", + "pad.modals.looping.explanation": "Av\u00e8m un probl\u00e8ma de comunicacion amb lo servidor de sincronizacion.", + "pad.modals.looping.cause": "Es possible que v\u00f2stra connexion si\u00e1 protegida per un parafu\u00f2c incompatible o un servidor proxy incompatible.", + "pad.modals.initsocketfail": "Lo servidor es introbable.", + "pad.modals.initsocketfail.explanation": "Impossible de se connectar al servidor de sincronizacion.", + "pad.modals.initsocketfail.cause": "Lo probl\u00e8ma p\u00f2t venir de v\u00f2stre navigador web o de v\u00f2stra connexion Internet.", "pad.modals.slowcommit": "Desconnectat", "pad.modals.slowcommit.explanation": "Lo servidor respond pas.", + "pad.modals.slowcommit.cause": "Aqueste probl\u00e8ma p\u00f2t venir d'una marrida connectivitat a la ret.", "pad.modals.deleted": "Suprimit.", + "pad.modals.deleted.explanation": "Aqueste Pad es estat suprimit.", + "pad.modals.disconnected": "S\u00e8tz estat desconnectat.", + "pad.modals.disconnected.explanation": "La connexion al servidor a fracassat.", + "pad.modals.disconnected.cause": "Es possible que lo servidor si\u00e1 indisponible. Informatz-nos-ne se lo probl\u00e8ma persist\u00eds.", "pad.share": "Partejar aqueste Pad", "pad.share.readonly": "Lectura sola", "pad.share.link": "Ligam", @@ -60,9 +79,12 @@ "pad.chat": "Chat", "pad.chat.title": "Dobrir lo chat associat a aqueste pad.", "pad.chat.loadmessages": "Cargar mai de messatges.", + "timeslider.pageTitle": "Istoric dinamic de {{appTitle}}", + "timeslider.toolbar.returnbutton": "Retorn a aqueste Pad.", "timeslider.toolbar.authors": "Autors :", "timeslider.toolbar.authorsList": "Pas cap d'autor", "timeslider.toolbar.exportlink.title": "Exportar", + "timeslider.exportCurrent": "Exportar la version actuala en\u00a0:", "timeslider.version": "Version {{version}}", "timeslider.saved": "Enregistrat lo {{day}} {{month}} {{year}}", "timeslider.dateformat": "{{month}}\/{{day}}\/{{year}} {{hours}}:{{minutes}}:{{seconds}}", @@ -78,18 +100,19 @@ "timeslider.month.october": "Octobre", "timeslider.month.november": "Novembre", "timeslider.month.december": "Decembre", + "pad.savedrevs.marked": "Aquesta revision es ara marcada coma revision enregistrada", "pad.userlist.entername": "Entratz v\u00f2stre nom", "pad.userlist.unnamed": "sens nom", "pad.userlist.guest": "Convidat", "pad.userlist.deny": "Refusar", "pad.userlist.approve": "Aprovar", + "pad.editbar.clearcolors": "Escafar las colors de paternitat dins tot lo document ?", "pad.impexp.importbutton": "Importar ara", "pad.impexp.importing": "Imp\u00f2rt en cors...", + "pad.impexp.confirmimport": "Importar un fichi\u00e8r espotir\u00e0 lo t\u00e8xte actual del bl\u00f2t. S\u00e8tz segur que lo vol\u00e8tz far ?", + "pad.impexp.convertFailed": "Pod\u00e8m pas importar aqueste fichi\u00e8r. Utilizatz un autre format de document o fas\u00e8tz un copiar\/pegar manual", + "pad.impexp.uploadFailed": "Lo telecargament a fracassat, reensajatz", "pad.impexp.importfailed": "Frac\u00e0s de l'importacion", "pad.impexp.copypaste": "Copiatz\/pegatz", - "@metadata": { - "authors": [ - "Cedric31" - ] - } + "pad.impexp.exportdisabled": "Exportar al format {{type}} es desactivat. Contactatz v\u00f2stre administrator del sist\u00e8ma per mai de detalhs." } \ No newline at end of file diff --git a/src/locales/pl.json b/src/locales/pl.json index e52f7c32..3481cafc 100644 --- a/src/locales/pl.json +++ b/src/locales/pl.json @@ -80,6 +80,7 @@ "pad.share.emebdcode": "Kod do umieszczenia", "pad.chat": "Czat", "pad.chat.title": "Otw\u00f3rz czat dla tego dokumentu.", + "pad.chat.loadmessages": "Za\u0142aduj wi\u0119cej wiadomo\u015bci", "timeslider.pageTitle": "O\u015b czasu {{appTitle}}", "timeslider.toolbar.returnbutton": "Powr\u00f3\u0107 do dokumentu", "timeslider.toolbar.authors": "Autorzy:", diff --git a/src/locales/ps.json b/src/locales/ps.json index 574fb1ad..6589c77f 100644 --- a/src/locales/ps.json +++ b/src/locales/ps.json @@ -1 +1,51 @@ -{"pad.toolbar.bold.title":"زغرد (Ctrl-B)","pad.toolbar.italic.title":"رېوند (Ctrl-I)","pad.toolbar.undo.title":"ناکړل (Ctrl-Z)","pad.toolbar.redo.title":"بياکړل (Ctrl-Y)","pad.toolbar.settings.title":"امستنې","pad.colorpicker.save":"خوندي کول","pad.colorpicker.cancel":"ناګارل","pad.loading":"برسېرېدنې کې دی...","pad.settings.myView":"زما کتنه","pad.settings.fontType":"ليکبڼې ډول:","pad.settings.fontType.normal":"نورمال","pad.settings.fontType.monospaced":"مونوسپېس","pad.settings.language":"ژبه:","pad.importExport.exporthtml":"اچ ټي ام اېل","pad.importExport.exportplain":"ساده متن","pad.importExport.exportword":"مايکروسافټ ورډ","pad.importExport.exportpdf":"پي ډي اېف","pad.importExport.exportopen":"ODF (اوپن ډاکومنټ فارمټ)","pad.modals.deleted":"ړنګ شو.","pad.share.readonly":"يوازې لوستنه","pad.share.link":"تړنه","pad.share.emebdcode":"يو آر اېل ټومبل","pad.chat":"بانډار","timeslider.toolbar.authors":"ليکوال:","timeslider.month.january":"جنوري","timeslider.month.february":"فبروري","timeslider.month.march":"مارچ","timeslider.month.april":"اپرېل","timeslider.month.may":"مۍ","timeslider.month.june":"جون","timeslider.month.july":"جولای","timeslider.month.august":"اګسټ","timeslider.month.september":"سېپتمبر","timeslider.month.october":"اکتوبر","timeslider.month.november":"نومبر","timeslider.month.december":"ډيسمبر"} \ No newline at end of file +{ + "@metadata": { + "authors": [ + "Ahmed-Najib-Biabani-Ibrahimkhel" + ] + }, + "pad.toolbar.bold.title": "\u0632\u063a\u0631\u062f (Ctrl-B)", + "pad.toolbar.italic.title": "\u0631\u06d0\u0648\u0646\u062f (Ctrl-I)", + "pad.toolbar.undo.title": "\u0646\u0627\u06a9\u0693\u0644 (Ctrl-Z)", + "pad.toolbar.redo.title": "\u0628\u064a\u0627\u06a9\u0693\u0644 (Ctrl-Y)", + "pad.toolbar.settings.title": "\u0627\u0645\u0633\u062a\u0646\u06d0", + "pad.colorpicker.save": "\u062e\u0648\u0646\u062f\u064a \u06a9\u0648\u0644", + "pad.colorpicker.cancel": "\u0646\u0627\u06ab\u0627\u0631\u0644", + "pad.loading": "\u0628\u0631\u0633\u06d0\u0631\u06d0\u062f\u0646\u06d0 \u06a9\u06d0 \u062f\u06cc...", + "pad.wrongPassword": "\u067e\u067c\u0646\u0648\u0645 \u0645\u0648 \u0633\u0645 \u0646\u0647 \u0648", + "pad.settings.myView": "\u0632\u0645\u0627 \u06a9\u062a\u0646\u0647", + "pad.settings.fontType": "\u0644\u064a\u06a9\u0628\u06bc\u06d0 \u0689\u0648\u0644:", + "pad.settings.fontType.normal": "\u0646\u0648\u0631\u0645\u0627\u0644", + "pad.settings.fontType.monospaced": "\u0645\u0648\u0646\u0648\u0633\u067e\u06d0\u0633", + "pad.settings.language": "\u0698\u0628\u0647:", + "pad.importExport.exporthtml": "\u0627\u0686 \u067c\u064a \u0627\u0645 \u0627\u06d0\u0644", + "pad.importExport.exportplain": "\u0633\u0627\u062f\u0647 \u0645\u062a\u0646", + "pad.importExport.exportword": "\u0645\u0627\u064a\u06a9\u0631\u0648\u0633\u0627\u0641\u067c \u0648\u0631\u0689", + "pad.importExport.exportpdf": "\u067e\u064a \u0689\u064a \u0627\u06d0\u0641", + "pad.importExport.exportopen": "ODF (\u0627\u0648\u067e\u0646 \u0689\u0627\u06a9\u0648\u0645\u0646\u067c \u0641\u0627\u0631\u0645\u067c)", + "pad.modals.deleted": "\u0693\u0646\u06ab \u0634\u0648.", + "pad.share.readonly": "\u064a\u0648\u0627\u0632\u06d0 \u0644\u0648\u0633\u062a\u0646\u0647", + "pad.share.link": "\u062a\u0693\u0646\u0647", + "pad.share.emebdcode": "\u064a\u0648 \u0622\u0631 \u0627\u06d0\u0644 \u067c\u0648\u0645\u0628\u0644", + "pad.chat": "\u0628\u0627\u0646\u0689\u0627\u0631", + "pad.chat.loadmessages": "\u0646\u0648\u0631 \u067e\u064a\u063a\u0627\u0645\u0648\u0646\u0647 \u0628\u0631\u0633\u06d0\u0631\u0648\u0644", + "timeslider.toolbar.authors": "\u0644\u064a\u06a9\u0648\u0627\u0644:", + "timeslider.toolbar.authorsList": "\u0628\u06d0 \u0644\u064a\u06a9\u0648\u0627\u0644\u0647", + "timeslider.month.january": "\u062c\u0646\u0648\u0631\u064a", + "timeslider.month.february": "\u0641\u0628\u0631\u0648\u0631\u064a", + "timeslider.month.march": "\u0645\u0627\u0631\u0686", + "timeslider.month.april": "\u0627\u067e\u0631\u06d0\u0644", + "timeslider.month.may": "\u0645\u06cd", + "timeslider.month.june": "\u062c\u0648\u0646", + "timeslider.month.july": "\u062c\u0648\u0644\u0627\u06cc", + "timeslider.month.august": "\u0627\u06ab\u0633\u067c", + "timeslider.month.september": "\u0633\u06d0\u067e\u062a\u0645\u0628\u0631", + "timeslider.month.october": "\u0627\u06a9\u062a\u0648\u0628\u0631", + "timeslider.month.november": "\u0646\u0648\u0645\u0628\u0631", + "timeslider.month.december": "\u0689\u064a\u0633\u0645\u0628\u0631", + "pad.userlist.entername": "\u0646\u0648\u0645 \u0645\u0648 \u0648\u0631\u06a9\u0693\u06cd", + "pad.userlist.unnamed": "\u0628\u06d0 \u0646\u0648\u0645\u0647", + "pad.userlist.guest": "\u0645\u06d0\u0644\u0645\u0647", + "pad.userlist.deny": "\u0631\u062f\u0648\u0644", + "pad.userlist.approve": "\u0645\u0646\u0644" +} \ No newline at end of file diff --git a/src/locales/pt-br.json b/src/locales/pt-br.json index 78c9ed3f..6562681a 100644 --- a/src/locales/pt-br.json +++ b/src/locales/pt-br.json @@ -78,6 +78,7 @@ "pad.share.emebdcode": "Incorporar o URL", "pad.chat": "Bate-papo", "pad.chat.title": "Abrir o bate-papo desta nota.", + "pad.chat.loadmessages": "Carregar mais mensagens", "timeslider.pageTitle": "Linha do tempo de {{appTitle}}", "timeslider.toolbar.returnbutton": "Retornar para a nota", "timeslider.toolbar.authors": "Autores:", diff --git a/src/locales/ru.json b/src/locales/ru.json index 7eb34c97..1f2fbda6 100644 --- a/src/locales/ru.json +++ b/src/locales/ru.json @@ -2,6 +2,7 @@ "@metadata": { "authors": [ "Amire80", + "DCamer", "Eleferen", "Volkov" ] @@ -28,6 +29,8 @@ "pad.colorpicker.save": "\u0421\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c", "pad.colorpicker.cancel": "\u041e\u0442\u043c\u0435\u043d\u0430", "pad.loading": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430...", + "pad.passwordRequired": "\u0412\u0430\u043c \u043d\u0443\u0436\u0435\u043d \u043f\u0430\u0440\u043e\u043b\u044c \u0434\u043b\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u0430", + "pad.permissionDenied": "\u0423 \u0432\u0430\u0441 \u043d\u0435\u0442 \u0440\u0430\u0437\u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0434\u043e\u0441\u0442\u0443\u043f", "pad.wrongPassword": "\u041d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u044b\u0439 \u043f\u0430\u0440\u043e\u043b\u044c", "pad.settings.padSettings": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430", "pad.settings.myView": "\u041c\u043e\u0439 \u0432\u0438\u0434", @@ -49,9 +52,11 @@ "pad.importExport.exportpdf": "PDF", "pad.importExport.exportopen": "ODF (\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442 OpenOffice)", "pad.importExport.exportdokuwiki": "DokuWiki", + "pad.importExport.abiword.innerHTML": "\u0412\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0438\u0437 \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430 \u0438\u043b\u0438 HTML. \u0414\u043b\u044f \u0431\u043e\u043b\u0435\u0435 \u043f\u0440\u043e\u0434\u0432\u0438\u043d\u0443\u0442\u044b\u0445 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438\u043c\u043f\u043e\u0440\u0442\u0430, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0435 AbiWord<\/a>.", "pad.modals.connected": "\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d.", "pad.modals.reconnecting": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0435 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a \u0432\u0430\u0448\u0435\u043c\u0443 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0443", "pad.modals.forcereconnect": "\u041f\u0440\u0438\u043d\u0443\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0435 \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435", + "pad.modals.userdup": "\u041e\u0442\u043a\u0440\u044b\u0442\u043e \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043e\u043a\u043d\u0435", "pad.modals.userdup.explanation": "\u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043e\u0442\u043a\u0440\u044b\u0442 \u0431\u043e\u043b\u0435\u0435 \u0447\u0435\u043c \u0432 \u043e\u0434\u043d\u043e\u043c \u043e\u043a\u043d\u0435 \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430 \u043d\u0430 \u044d\u0442\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435.", "pad.modals.userdup.advice": "\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u044d\u0442\u043e\u0433\u043e \u043e\u043a\u043d\u0430.", "pad.modals.unauth": "\u041d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d", @@ -76,22 +81,41 @@ "pad.share.emebdcode": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u044c URL", "pad.chat": "\u0427\u0430\u0442", "pad.chat.title": "\u041e\u0442\u043a\u0440\u044b\u0442\u044c \u0447\u0430\u0442 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430.", + "pad.chat.loadmessages": "\u0415\u0449\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f", "timeslider.pageTitle": "\u0412\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f \u0448\u043a\u0430\u043b\u0430 {{appTitle}}", "timeslider.toolbar.returnbutton": "\u041a \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0443", "timeslider.toolbar.authors": "\u0410\u0432\u0442\u043e\u0440\u044b:", "timeslider.toolbar.authorsList": "\u041d\u0435\u0442 \u0430\u0432\u0442\u043e\u0440\u043e\u0432", + "timeslider.toolbar.exportlink.title": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442", "timeslider.exportCurrent": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0442\u0435\u043a\u0443\u0449\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e \u043a\u0430\u043a:", "timeslider.version": "\u0412\u0435\u0440\u0441\u0438\u044f {{version}}", "timeslider.saved": "\u0421\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043e {{day}}.{{month}}.{{year}}", + "timeslider.dateformat": "{{month}}\/{{day}}\/{{year}} {{hours}}:{{minutes}}:{{seconds}}", "timeslider.month.january": "\u044f\u043d\u0432\u0430\u0440\u044c", "timeslider.month.february": "\u0444\u0435\u0432\u0440\u0430\u043b\u044c", "timeslider.month.march": "\u043c\u0430\u0440\u0442", "timeslider.month.april": "\u0430\u043f\u0440\u0435\u043b\u044c", "timeslider.month.may": "\u043c\u0430\u0439", + "timeslider.month.june": "\u0438\u044e\u043d\u044c", + "timeslider.month.july": "\u0438\u044e\u043b\u044c", + "timeslider.month.august": "\u0430\u0432\u0433\u0443\u0441\u0442", + "timeslider.month.september": "\u0441\u0435\u043d\u0442\u044f\u0431\u0440\u044c", + "timeslider.month.october": "\u043e\u043a\u0442\u044f\u0431\u0440\u044c", + "timeslider.month.november": "\u043d\u043e\u044f\u0431\u0440\u044c", + "timeslider.month.december": "\u0434\u0435\u043a\u0430\u0431\u0440\u044c", + "pad.savedrevs.marked": "\u042d\u0442\u0430 \u0432\u0435\u0440\u0441\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043c\u0435\u0447\u0435\u043d\u0430 \u043a\u0430\u043a \u0441\u043e\u0445\u0440\u0430\u043d\u0435\u043d\u043d\u0430\u044f", "pad.userlist.entername": "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f", + "pad.userlist.unnamed": "\u0431\u0435\u0437\u044b\u043c\u044f\u043d\u043d\u044b\u0439", "pad.userlist.guest": "\u0413\u043e\u0441\u0442\u044c", + "pad.userlist.deny": "\u041e\u0442\u043a\u043b\u043e\u043d\u0438\u0442\u044c", + "pad.userlist.approve": "\u0423\u0442\u0432\u0435\u0440\u0434\u0438\u0442\u044c", + "pad.editbar.clearcolors": "\u041e\u0447\u0438\u0441\u0442\u0438\u0442\u044c \u0430\u0432\u0442\u043e\u0440\u0441\u043a\u0438\u0435 \u0446\u0432\u0435\u0442\u0430 \u0432\u043e \u0432\u0441\u0435\u043c \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0435?", "pad.impexp.importbutton": "\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u0439\u0447\u0430\u0441", "pad.impexp.importing": "\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435\u2026", + "pad.impexp.confirmimport": "\u0418\u043c\u043f\u043e\u0440\u0442 \u0444\u0430\u0439\u043b\u0430 \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0438\u0448\u0435\u0442 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u0442\u0435\u043a\u0441\u0442. \u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c?", + "pad.impexp.convertFailed": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u0444\u0430\u0439\u043b. \u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0438\u043b\u0438 \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435 \u0432\u0440\u0443\u0447\u043d\u0443\u044e", "pad.impexp.uploadFailed": "\u0417\u0430\u0433\u0440\u0443\u0437\u043a\u0430 \u043d\u0435 \u0443\u0434\u0430\u043b\u0430\u0441\u044c, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0435\u0449\u0451 \u0440\u0430\u0437", - "pad.impexp.importfailed": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438" + "pad.impexp.importfailed": "\u041e\u0448\u0438\u0431\u043a\u0430 \u043f\u0440\u0438 \u0438\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438", + "pad.impexp.copypaste": "\u041f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430, \u0441\u043a\u043e\u043f\u0438\u0440\u0443\u0439\u0442\u0435", + "pad.impexp.exportdisabled": "\u042d\u043a\u0441\u043f\u043e\u0440\u0442 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 {{type}} \u043e\u0442\u043a\u043b\u044e\u0447\u0435\u043d. \u0414\u043b\u044f \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e\u0439 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435\u0441\u044c \u043a \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u043e\u043c\u0443 \u0430\u0434\u043c\u0438\u043d\u0438\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0443." } \ No newline at end of file diff --git a/src/locales/sl.json b/src/locales/sl.json index bf834206..c7cffa6f 100644 --- a/src/locales/sl.json +++ b/src/locales/sl.json @@ -78,6 +78,7 @@ "pad.share.emebdcode": "Vstavi naslov URL", "pad.chat": "Klepet", "pad.chat.title": "Odpri klepetalno okno dokumenta.", + "pad.chat.loadmessages": "Nalo\u017ei ve\u010d sporo\u010dil", "timeslider.pageTitle": "Zgodovina dokumenta {{appTitle}}", "timeslider.toolbar.returnbutton": "Vrni se na dokument", "timeslider.toolbar.authors": "Autorji:", diff --git a/src/locales/uk.json b/src/locales/uk.json index af035c65..ae6cbbb6 100644 --- a/src/locales/uk.json +++ b/src/locales/uk.json @@ -80,6 +80,7 @@ "pad.share.emebdcode": "\u0412\u0441\u0442\u0430\u0432\u0438\u0442\u0438 URL", "pad.chat": "\u0427\u0430\u0442", "pad.chat.title": "\u0412\u0456\u0434\u043a\u0440\u0438\u0442\u0438 \u0447\u0430\u0442 \u0434\u043b\u044f \u0446\u044c\u043e\u0433\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0443.", + "pad.chat.loadmessages": "\u0417\u0430\u0432\u0430\u043d\u0442\u0430\u0436\u0438\u0442\u0438 \u0431\u0456\u043b\u044c\u0448\u0435 \u043f\u043e\u0432\u0456\u0434\u043e\u043c\u043b\u0435\u043d\u044c", "timeslider.pageTitle": "\u0427\u0430\u0441\u043e\u0432\u0430 \u0448\u043a\u0430\u043b\u0430 {{appTitle}}", "timeslider.toolbar.returnbutton": "\u041f\u043e\u0432\u0435\u0440\u043d\u0443\u0442\u0438\u0441\u044c \u0434\u043e \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0443", "timeslider.toolbar.authors": "\u0410\u0432\u0442\u043e\u0440\u0438:", diff --git a/src/locales/zh-hant.json b/src/locales/zh-hant.json index c91e2fe3..6ee1e377 100644 --- a/src/locales/zh-hant.json +++ b/src/locales/zh-hant.json @@ -78,6 +78,7 @@ "pad.share.emebdcode": "\u5d4c\u5165\u7db2\u5740", "pad.chat": "\u804a\u5929", "pad.chat.title": "\u6253\u958b\u6b64pad\u7684\u804a\u5929\u3002", + "pad.chat.loadmessages": "\u8f09\u5165\u66f4\u591a\u8a0a\u606f", "timeslider.pageTitle": "{{appTitle}}\u6642\u9593\u8ef8", "timeslider.toolbar.returnbutton": "\u8fd4\u56de\u5230pad", "timeslider.toolbar.authors": "\u4f5c\u8005\uff1a", From f974136d0cf4e5555a81ebd655095efaa10b4643 Mon Sep 17 00:00:00 2001 From: mluto Date: Mon, 28 Jan 2013 10:13:37 +0100 Subject: [PATCH 16/22] Jump to revision given in URL, add current revision to URL --- src/static/js/broadcast_slider.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/static/js/broadcast_slider.js b/src/static/js/broadcast_slider.js index 221666de..821c9221 100644 --- a/src/static/js/broadcast_slider.js +++ b/src/static/js/broadcast_slider.js @@ -106,6 +106,7 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) function setSliderPosition(newpos) { newpos = Number(newpos); + window.location.hash = "#" + newpos; if (newpos < 0 || newpos > sliderLength) return; $("#ui-slider-handle").css('left', newpos * ($("#ui-slider-bar").width() - 2) / (sliderLength * 1.0)); $("a.tlink").map(function() @@ -481,6 +482,18 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) } $("#timeslider").show(); + + var startPos = clientVars.collab_client_vars.rev; + if(window.location.hash.length > 1) + { + var hashRev = Number(window.location.hash.substr(1)); + if(!isNaN(hashRev)) + { + // this is necessary because of the socket.io-event which loads the changesets + setTimeout(function() { setSliderPosition(hashRev); }, 1); + } + } + setSliderLength(clientVars.collab_client_vars.rev); setSliderPosition(clientVars.collab_client_vars.rev); From 437856188239e0f5d6b71c0de2083e9819e996b0 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 28 Jan 2013 16:52:23 +0000 Subject: [PATCH 17/22] change to createDiffHTML --- src/node/db/API.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node/db/API.js b/src/node/db/API.js index a700a491..f99a43af 100644 --- a/src/node/db/API.js +++ b/src/node/db/API.js @@ -658,14 +658,14 @@ exports.getChatHead = function(padID, callback) } /** -createDiff(padID, startRev, endRev) returns an object of diffs from 2 points in a pad +createDiffHTML(padID, startRev, endRev) returns an object of diffs from 2 points in a pad Example returns: {"code":0,"message":"ok","data":{"html":"Welcome to Etherpad Lite!

This pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!

Get involved with Etherpad at
http://etherpad.org
aw

","authors":["a.HKIv23mEbachFYfH",""]}} {"code":4,"message":"no or wrong API Key","data":null} */ -exports.createDiff = function(padID, startRev, endRev, callback){ +exports.createDiffHTML = function(padID, startRev, endRev, callback){ //check if rev is a number if(startRev !== undefined && typeof startRev != "number") { From 51eff0d659a8364b4a1fb6712a072873b8dbbd59 Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 28 Jan 2013 16:53:29 +0000 Subject: [PATCH 18/22] change to createDiffHTML --- src/node/handler/APIHandler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index 1f91c737..9f86277a 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -180,7 +180,7 @@ var version = , "deleteGroup" : ["groupID"] , "listPads" : ["groupID"] , "listAllPads" : [] - , "createDiff" : ["padID", "startRev", "endRev"] + , "createDiffHTML" : ["padID", "startRev", "endRev"] , "createPad" : ["padID", "text"] , "createGroupPad" : ["groupID", "padName", "text"] , "createAuthor" : ["name"] From a239158b49159f660546d0f358c34e9ba1bfc199 Mon Sep 17 00:00:00 2001 From: mluto Date: Mon, 28 Jan 2013 20:17:34 +0100 Subject: [PATCH 19/22] Renamed paramSettings to getParameters, to cause less confusion --- src/static/js/pad.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/static/js/pad.js b/src/static/js/pad.js index 9f0fba7f..1b244aea 100644 --- a/src/static/js/pad.js +++ b/src/static/js/pad.js @@ -107,7 +107,7 @@ function randomString() // * the parameter was supplied and matches checkVal // * the parameter was supplied and checkVal is null // callback: the function to call when all above succeeds, `val` is the value supplied by the user -var paramSettings = [ +var getParameters = [ { name: "noColors", checkVal: "true", callback: function(val) { settings.noColors = true; $('#clearAuthorship').hide(); } }, { name: "showControls", checkVal: "false", callback: function(val) { $('#editbar').hide(); $('#editorcontainer').css({"top":"0px"}); } }, { name: "showChat", checkVal: "false", callback: function(val) { $('#chaticon').hide(); } }, @@ -126,9 +126,9 @@ function getParams() { var params = getUrlVars() - for(var i = 0; i < paramSettings.length; i++) + for(var i = 0; i < getParameters.length; i++) { - var setting = paramSettings[i]; + var setting = getParameters[i]; var value = params[setting.name]; if(value && (value == setting.checkVal || setting.checkVal == null)) From 3002807741175a7b4f508346bcac9fcb7cf46fc2 Mon Sep 17 00:00:00 2001 From: mluto Date: Mon, 28 Jan 2013 21:12:50 +0100 Subject: [PATCH 20/22] Added tests for revision-jumping --- tests/frontend/specs/timeslider_revisions.js | 64 ++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/frontend/specs/timeslider_revisions.js b/tests/frontend/specs/timeslider_revisions.js index af59051a..de8ca52f 100644 --- a/tests/frontend/specs/timeslider_revisions.js +++ b/tests/frontend/specs/timeslider_revisions.js @@ -57,4 +57,68 @@ describe("timeslider", function(){ }, 6000); }, revs*timePerRev); }); + + it("changes the url when clicking on the timeslider", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + + // make some changes to produce 7 revisions + var timePerRev = 900 + , revs = 7; + this.timeout(revs*timePerRev+10000); + for(var i=0; i < revs; i++) { + setTimeout(function() { + // enter 'a' in the first text element + inner$("div").first().sendkeys('a'); + }, timePerRev*i); + } + + setTimeout(function() { + // go to timeslider + $('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider'); + + setTimeout(function() { + var timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; + var $sliderBar = timeslider$('#ui-slider-bar'); + + var latestContents = timeslider$('#padcontent').text(); + + var oldUrl = $('#iframe-container iframe')[0].contentWindow.location.hash; + + // Click somewhere on the timeslider + var e = new jQuery.Event('mousedown'); + e.clientX = e.pageX = 150; + e.clientY = e.pageY = 60; + $sliderBar.trigger(e); + + helper.waitFor(function(){ + return $('#iframe-container iframe')[0].contentWindow.location.hash != oldUrl; + }, 6000).always(function(){ + expect( $('#iframe-container iframe')[0].contentWindow.location.hash ).not.to.eql( oldUrl ); + done(); + }); + }, 6000); + }, revs*timePerRev); + }); + + it("jumps to a revision given in the url", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + this.timeout(11000); + inner$("div").first().sendkeys('a'); + + setTimeout(function() { + // go to timeslider + $('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0'); + var timeslider$; + + helper.waitFor(function(){ + timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; + return timeslider$ && timeslider$('#padcontent').text().length == 230; + }, 6000).always(function(){ + expect( timeslider$('#padcontent').text().length ).to.eql( 230 ); + done(); + }); + }, 2500); + }); }); From 0b90e5752be46113b3fcc9ae71a71c68c8a335f3 Mon Sep 17 00:00:00 2001 From: mluto Date: Mon, 28 Jan 2013 21:38:56 +0100 Subject: [PATCH 21/22] Added a test to check the export-url --- tests/frontend/specs/timeslider_revisions.js | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/frontend/specs/timeslider_revisions.js b/tests/frontend/specs/timeslider_revisions.js index de8ca52f..52f48764 100644 --- a/tests/frontend/specs/timeslider_revisions.js +++ b/tests/frontend/specs/timeslider_revisions.js @@ -121,4 +121,31 @@ describe("timeslider", function(){ }); }, 2500); }); + + it("checks the export url", function(done) { + var inner$ = helper.padInner$; + var chrome$ = helper.padChrome$; + this.timeout(11000); + inner$("div").first().sendkeys('a'); + + setTimeout(function() { + // go to timeslider + $('#iframe-container iframe').attr('src', $('#iframe-container iframe').attr('src')+'/timeslider#0'); + var timeslider$; + var exportLink; + + helper.waitFor(function(){ + timeslider$ = $('#iframe-container iframe')[0].contentWindow.$; + if(!timeslider$) + return false; + exportLink = timeslider$('#exportplaina').attr('href'); + if(!exportLink) + return false; + return exportLink.substr(exportLink.length - 12) == "0/export/txt"; + }, 6000).always(function(){ + expect( exportLink.substr(exportLink.length - 12) ).to.eql( "0/export/txt" ); + done(); + }); + }, 2500); + }); }); From 01fe5c183d0e123c5682ac5274df94103b6bd291 Mon Sep 17 00:00:00 2001 From: mluto Date: Mon, 28 Jan 2013 21:44:21 +0100 Subject: [PATCH 22/22] Only set url if the revsion will actually be loaded --- src/static/js/broadcast_slider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/static/js/broadcast_slider.js b/src/static/js/broadcast_slider.js index 821c9221..08ac08b5 100644 --- a/src/static/js/broadcast_slider.js +++ b/src/static/js/broadcast_slider.js @@ -106,8 +106,8 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) function setSliderPosition(newpos) { newpos = Number(newpos); - window.location.hash = "#" + newpos; if (newpos < 0 || newpos > sliderLength) return; + window.location.hash = "#" + newpos; $("#ui-slider-handle").css('left', newpos * ($("#ui-slider-bar").width() - 2) / (sliderLength * 1.0)); $("a.tlink").map(function() {