diff --git a/src/locales/pms.json b/src/locales/pms.json
index 80a857e39..cdc80bea3 100644
--- a/src/locales/pms.json
+++ b/src/locales/pms.json
@@ -44,5 +44,86 @@
"pad.importExport.import": "Carié n'archivi o document ëd test",
"pad.importExport.importSuccessful": "Bele fàit!",
"pad.importExport.export": "Esporté ël feuj atual coma:",
- "pad.importExport.exportetherpad": "Etherpad"
+ "pad.importExport.exportetherpad": "Etherpad",
+ "pad.importExport.exporthtml": "HTML",
+ "pad.importExport.exportplain": "Mach test",
+ "pad.importExport.exportword": "Microsoft Word",
+ "pad.importExport.exportpdf": "PDF",
+ "pad.importExport.exportopen": "ODF (Open Document Format)",
+ "pad.importExport.abiword.innerHTML": "A peul mach amporté dij formà ëd test sempi o HTML. Për dle fonsionalità d'amportassion pi avansà, ch'a anstala AbiWord.",
+ "pad.modals.connected": "Colegà.",
+ "pad.modals.reconnecting": "Neuva conession a sò feuj...",
+ "pad.modals.forcereconnect": "Forsé la neuva conession",
+ "pad.modals.reconnecttimer": "Tentativ ëd neuva conession",
+ "pad.modals.cancel": "Anulé",
+ "pad.modals.userdup": "Duvertà an n'àutra fnestra",
+ "pad.modals.userdup.explanation": "Ës feuj a smija esse duvert an vàire fnestre ansima a st'ordinator.",
+ "pad.modals.userdup.advice": "Coleghesse torna për dovré costa fnestra.",
+ "pad.modals.unauth": "Nen autorisà",
+ "pad.modals.unauth.explanation": "Ij sò përmess a son cangià antramentre ch'a vëdìa costa pàgina. Ch'a sërca ëd coleghesse torna.",
+ "pad.modals.looping.explanation": "A-i é dij problema ëd comunicassion con ël servent ëd sincronisassion.",
+ "pad.modals.looping.cause": "Peul desse che chiel a l'é colegasse con un para-feu o un mandatari incompatìbil.",
+ "pad.modals.initsocketfail": "Ël servent a l'é introvàbil.",
+ "pad.modals.initsocketfail.explanation": "Impossìbil coleghesse al servent ëd sincronisassion.",
+ "pad.modals.initsocketfail.cause": "A l'é probàbil che sòn a sia dovù a sò navigador o a soa conession an sl'aragnà.",
+ "pad.modals.slowcommit.explanation": "Ël servent a rëspond nen.",
+ "pad.modals.slowcommit.cause": "Sòn a podrìa esse dovù a dij problema ëd conession a l'aragnà.",
+ "pad.modals.badChangeset.explanation": "Na modìfica ch'a l'ha fàit a l'é stàita cassificà tanme ilegal dal servent ëd sincronisassion.",
+ "pad.modals.badChangeset.cause": "Sòn a podrìa esse dovù a na bruta configurassion dël servent o a chèich àutr comportament nen ëspetà. Për piasì, ch'a contata l'aministrator dël servissi, s'a pensa ch'a sia n'eror. Ch'a preuva a rintré torna ant ël sistema për andé anans a modifiché.",
+ "pad.modals.corruptPad.explanation": "Ël feuj al qual a sërca d'acede a l'é corompù.",
+ "pad.modals.corruptPad.cause": "Sòn a podrìa esse dovù a na configurassion ësbalià dël servent o a chèich àutr comportament nen ëspetà. Për piasì, ch'a contata l'aministrator dël servissi.",
+ "pad.modals.deleted": "Dëscancelà.",
+ "pad.modals.deleted.explanation": "Ës feuj a l'é stàit eliminà.",
+ "pad.modals.disconnected": "A l'é stàit dëscolegà",
+ "pad.modals.disconnected.explanation": "La conession al servent a l'é perdusse",
+ "pad.modals.disconnected.cause": "Ël servent a podrìa esse indisponìbil. Për piasì, ch'a anforma l'aministrator dël servissi si ël problema a persist.",
+ "pad.share": "Partagé 's feuj",
+ "pad.share.readonly": "Mach letura",
+ "pad.share.link": "Liura",
+ "pad.share.emebdcode": "Ancorporé na liura",
+ "pad.chat": "Ciaciarada",
+ "pad.chat.title": "Duverté la ciaciarada për cost feuj.",
+ "pad.chat.loadmessages": "Carié pi 'd mëssagi",
+ "timeslider.pageTitle": "Stòria dinàmica ëd {{appTitle}}",
+ "timeslider.toolbar.returnbutton": "Torné al feuj",
+ "timeslider.toolbar.authors": "Autor:",
+ "timeslider.toolbar.authorsList": "Gnun autor",
+ "timeslider.toolbar.exportlink.title": "Esporté",
+ "timeslider.exportCurrent": "Esporté la version corenta tanme:",
+ "timeslider.version": "Version {{version}}",
+ "timeslider.saved": "Argistrà ai {{day}} {{month}} {{year}}",
+ "timeslider.playPause": "Letura / Pàusa dij contnù dël feuj",
+ "timeslider.backRevision": "Andé andaré ëd na revision ant ës feuj",
+ "timeslider.forwardRevision": "Andé anans ëd na revision ant ëd feuj",
+ "timeslider.dateformat": "{{day}}/{{month}}/{{year}} {{hours}}:{{minutes}}:{{seconds}}",
+ "timeslider.month.january": "Gené",
+ "timeslider.month.february": "Fërvé",
+ "timeslider.month.march": "Mars",
+ "timeslider.month.april": "Avril",
+ "timeslider.month.may": "Maj",
+ "timeslider.month.june": "Giugn",
+ "timeslider.month.july": "Luj",
+ "timeslider.month.august": "Ost",
+ "timeslider.month.september": "Stèmber",
+ "timeslider.month.october": "Otóber",
+ "timeslider.month.november": "Novèmber",
+ "timeslider.month.december": "Dzèmber",
+ "timeslider.unnamedauthors": "{{num}} {[plural(num) one: autor anònim, other: autor anònim ]}",
+ "pad.savedrevs.marked": "Sa revision a l'é adess marcà tanme revision argistrà",
+ "pad.savedrevs.timeslider": "A peul vëdde le revision argistrà an visitand la stòria",
+ "pad.userlist.entername": "Ch'a buta sò nòm",
+ "pad.userlist.unnamed": "anònim",
+ "pad.userlist.guest": "Anvità",
+ "pad.userlist.deny": "Arfudé",
+ "pad.userlist.approve": "Aprové",
+ "pad.editbar.clearcolors": "Dëscancelé ij color ëd paternità dj'autor an tut ël document?",
+ "pad.impexp.importbutton": "Amporté adess",
+ "pad.impexp.importing": "An camin ch'as ampòrta...",
+ "pad.impexp.confirmimport": "Amportand n'archivi as dëscancelërà ël test corent dël feuj. É-lo sigur ëd vorèj felo?",
+ "pad.impexp.convertFailed": "I l'oma nen podù amporté s'archivi. Për piasì, ch'a deuvra n'àutr formà ëd document o ch'a còpia e ancòla a man",
+ "pad.impexp.padHasData": "I l'oma nen podù amporté s'archivi përché 's feuj a l'ha già avù dle modìfiche; për piasì, ch'a ampòrta un feuj neuv",
+ "pad.impexp.uploadFailed": "Ël cariament a l'ha falì, për piasì ch'a preuva torna",
+ "pad.impexp.importfailed": "Amportassion falìa",
+ "pad.impexp.copypaste": "Për piasì, ch'a còpia e ancòla",
+ "pad.impexp.exportdisabled": "L'esportassion an formà {{type}} a l'é disativà. Për piasì, ch'a contata sò aministrator ëd sistema për ij detaj."
}
diff --git a/src/node/handler/PadMessageHandler.js b/src/node/handler/PadMessageHandler.js
index 060bca7b9..b575125a2 100644
--- a/src/node/handler/PadMessageHandler.js
+++ b/src/node/handler/PadMessageHandler.js
@@ -1153,6 +1153,101 @@ function handleClientReady(client, message)
client.join(padIds.padId);
//Save the revision in sessioninfos, we take the revision from the info the client send to us
sessioninfos[client.id].rev = message.client_rev;
+
+ //During the client reconnect, client might miss some revisions from other clients. By using client revision,
+ //this below code sends all the revisions missed during the client reconnect
+ var revisionsNeeded = [];
+ var changesets = {};
+
+ var startNum = message.client_rev + 1;
+ var endNum = pad.getHeadRevisionNumber() + 1;
+
+ async.series([
+ //push all the revision numbers needed into revisionsNeeded array
+ function(callback)
+ {
+ var headNum = pad.getHeadRevisionNumber();
+ if (endNum > headNum+1)
+ endNum = headNum+1;
+ if (startNum < 0)
+ startNum = 0;
+
+ for(var r=startNum;r>>>>>> develop
}
if (prevLine && line.listTypeName !== prevLine.listTypeName)
{
diff --git a/src/static/css/iframe_editor.css b/src/static/css/iframe_editor.css
index 0286a5df8..9aa003aaf 100644
--- a/src/static/css/iframe_editor.css
+++ b/src/static/css/iframe_editor.css
@@ -31,17 +31,13 @@ body {
body.grayedout { background-color: #eee !important }
#innerdocbody {
- font-size: 16px; /* overridden by body.style */
+ font-size: 12px; /* overridden by body.style */
font-family:Arial, sans-serif; /* overridden by body.style */
- line-height: 22px; /* overridden by body.style */
+ line-height: 16px; /* overridden by body.style */
background-color: white;
color: black;
}
-.innerdocbody>div{
- padding: 1px;
-}
-
body.doesWrap {
/* white-space: pre-wrap; */
diff --git a/src/static/js/collab_client.js b/src/static/js/collab_client.js
index fd0d9d446..4bcc6ad2b 100644
--- a/src/static/js/collab_client.js
+++ b/src/static/js/collab_client.js
@@ -60,6 +60,8 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
var debugMessages = [];
var msgQueue = [];
+ var isPendingRevision = false;
+
tellAceAboutHistoricalAuthors(serverVars.historicalAuthorData);
tellAceActiveAuthorInfo(initialUserInfo);
@@ -178,23 +180,36 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
editor.applyChangesToBase(changeset, author, apool);
}
}
+ if (isPendingRevision) {
+ setIsPendingRevision(false);
+ }
}
var sentMessage = false;
- var userChangesData = editor.prepareUserChangeset();
- if (userChangesData.changeset)
+ // Check if there are any pending revisions to be received from server.
+ // Allow only if there are no pending revisions to be received from server
+ if (!isPendingRevision)
{
- lastCommitTime = t;
- state = "COMMITTING";
- stateMessage = {
- type: "USER_CHANGES",
- baseRev: rev,
- changeset: userChangesData.changeset,
- apool: userChangesData.apool
- };
- sendMessage(stateMessage);
- sentMessage = true;
- callbacks.onInternalAction("commitPerformed");
+ var userChangesData = editor.prepareUserChangeset();
+ if (userChangesData.changeset)
+ {
+ lastCommitTime = t;
+ state = "COMMITTING";
+ stateMessage = {
+ type: "USER_CHANGES",
+ baseRev: rev,
+ changeset: userChangesData.changeset,
+ apool: userChangesData.apool
+ };
+ sendMessage(stateMessage);
+ sentMessage = true;
+ callbacks.onInternalAction("commitPerformed");
+ }
+ }
+ else
+ {
+ // run again in a few seconds, to check if there was a reconnection attempt
+ setTimeout(wrapRecordingErrors("setTimeout(handleUserChanges)", handleUserChanges), 3000);
}
if (sentMessage)
@@ -330,6 +345,69 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
});
handleUserChanges();
}
+ else if (msg.type == 'CLIENT_RECONNECT')
+ {
+ // Server sends a CLIENT_RECONNECT message when there is a client reconnect. Server also returns
+ // all pending revisions along with this CLIENT_RECONNECT message
+ if (msg.noChanges)
+ {
+ // If no revisions are pending, just make everything normal
+ setIsPendingRevision(false);
+ return;
+ }
+
+ var headRev = msg.headRev;
+ var newRev = msg.newRev;
+ var changeset = msg.changeset;
+ var author = (msg.author || '');
+ var apool = msg.apool;
+
+ if (msgQueue.length > 0)
+ {
+ if (newRev != (msgQueue[msgQueue.length - 1].newRev + 1))
+ {
+ window.console.warn("bad message revision on CLIENT_RECONNECT: " + newRev + " not " + (msgQueue[msgQueue.length - 1][0] + 1));
+ // setChannelState("DISCONNECTED", "badmessage_acceptcommit");
+ return;
+ }
+ msg.type = "NEW_CHANGES";
+ msgQueue.push(msg);
+ return;
+ }
+
+ if (newRev != (rev + 1))
+ {
+ window.console.warn("bad message revision on CLIENT_RECONNECT: " + newRev + " not " + (rev + 1));
+ // setChannelState("DISCONNECTED", "badmessage_acceptcommit");
+ return;
+ }
+
+ rev = newRev;
+ if (author == pad.getUserId())
+ {
+ editor.applyPreparedChangesetToBase();
+ setStateIdle();
+ callCatchingErrors("onInternalAction", function()
+ {
+ callbacks.onInternalAction("commitAcceptedByServer");
+ });
+ callCatchingErrors("onConnectionTrouble", function()
+ {
+ callbacks.onConnectionTrouble("OK");
+ });
+ handleUserChanges();
+ }
+ else
+ {
+ editor.applyChangesToBase(changeset, author, apool);
+ }
+
+ if (newRev == headRev)
+ {
+ // Once we have applied all pending revisions, make everything normal
+ setIsPendingRevision(false);
+ }
+ }
else if (msg.type == "NO_COMMIT_PENDING")
{
if (state == "COMMITTING")
@@ -591,6 +669,11 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
schedulePerhapsCallIdleFuncs();
}
+ function setIsPendingRevision(value)
+ {
+ isPendingRevision = value;
+ }
+
function callWhenNotCommitting(func)
{
idleFuncs.push(func);
@@ -656,7 +739,9 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
getMissedChanges: getMissedChanges,
callWhenNotCommitting: callWhenNotCommitting,
addHistoricalAuthors: tellAceAboutHistoricalAuthors,
- setChannelState: setChannelState
+ setChannelState: setChannelState,
+ setStateIdle: setStateIdle,
+ setIsPendingRevision: setIsPendingRevision
};
$(document).ready(setUpSocket);
diff --git a/src/static/js/pad.js b/src/static/js/pad.js
index 8fcec23f1..de613910d 100644
--- a/src/static/js/pad.js
+++ b/src/static/js/pad.js
@@ -206,10 +206,12 @@ function handshake()
socket.on('reconnect', function () {
pad.collabClient.setChannelState("CONNECTED");
- pad.sendClientReady(true);
+ pad.sendClientReady(receivedClientVars);
});
socket.on('reconnecting', function() {
+ pad.collabClient.setStateIdle();
+ pad.collabClient.setIsPendingRevision(true);
pad.collabClient.setChannelState("RECONNECTING");
});
@@ -217,6 +219,11 @@ function handshake()
pad.collabClient.setChannelState("DISCONNECTED", "reconnect_timeout");
});
+ socket.on('error', function(error) {
+ pad.collabClient.setStateIdle();
+ pad.collabClient.setIsPendingRevision(true);
+ });
+
var initalized = false;
socket.on('message', function(obj)
@@ -831,7 +838,7 @@ var pad = {
$.ajax(
{
type: 'post',
- url: '/ep/pad/connection-diagnostic-info',
+ url: 'ep/pad/connection-diagnostic-info',
data: {
diagnosticInfo: JSON.stringify(pad.diagnosticInfo)
},