diff --git a/www/_socket/main.js b/www/_socket/main.js index 56f03cc1e..d41274a98 100644 --- a/www/_socket/main.js +++ b/www/_socket/main.js @@ -37,6 +37,25 @@ define([ return true; }; + var setRandomizedInterval = function (func, target, range) { + var timeout; + var again = function () { + setTimeout(function () { + again(); + func(); + }, target - (range / 2) + Math.random() * range); + }; + again(); + return { + cancel: function () { + if (timeout) { + clearTimeout(timeout); + timeout = undefined; + } + } + }; + } + var andThen = function (Ckeditor) { $(window).on('hashchange', function() { window.location.reload(); @@ -149,20 +168,22 @@ define([ }, 0); }; + var now = function () { return new Date().getTime() }; + + var DD = new DiffDom(diffOptions); // apply patches, and try not to lose the cursor in the process! var applyHjson = function (shjson) { - setEditable(false); + //setEditable(false); + console.log(now()); var userDocStateDom = Convert.hjson.to.dom(JSON.parse(shjson)); userDocStateDom.setAttribute("contenteditable", "true"); // lol wtf - var DD = new DiffDom(diffOptions); - + console.log(now()); //assertStateMatches(); - var patch = (DD).diff(inner, userDocStateDom); (DD).apply(inner, patch); - + console.log(now()); // push back to the textarea so we get a userDocState - setEditable(true); + //setEditable(true); }; var onRemote = function (info) { @@ -238,11 +259,11 @@ define([ var rti = module.realtimeInput = window.rti = realtimeInput.start(realtimeOptions); - var propogate = function () { + var propogate = window.cryptpad_propogate = function () { var hjson = Convert.core.hyperjson.fromDOM(inner, isNotMagicLine); var shjson = JSON.stringify(hjson); - rti.propogate(shjson); + if (!rti.propogate(shjson)) { return; } rti.onEvent(shjson); }; @@ -255,10 +276,10 @@ define([ max_errors = 15, interval; var cancel = function () { - if (interval) { window.clearInterval(interval); } + //if (interval) { interval.cancel(); } }; - interval = window.setInterval(function () { + interval = setRandomizedInterval(function () { propogate(); try { el.replaceData(j, 0, input.charAt(i)); @@ -270,14 +291,14 @@ define([ } console.error(err); - var next = document.createTextNode(""); - el.parentNode.appendChild(next); + var next = document.createTextNode("-"); + window.inner.appendChild(next); el = next; - j = 0; + j = -1; } i = (i + 1) % l; j++; - }, 200); + }, 200, 50); return { cancel: cancel diff --git a/www/_socket/realtime-input.js b/www/_socket/realtime-input.js index 4cc66227b..3d36217b1 100644 --- a/www/_socket/realtime-input.js +++ b/www/_socket/realtime-input.js @@ -52,7 +52,7 @@ define([ // ------------------ Trapping Keyboard Events ---------------------- // - var bindEvents = function (element, events, callback, unbind) { + var _unused_bindEvents = function (element, events, callback, unbind) { for (var i = 0; i < events.length; i++) { var e = events[i]; if (element.addEventListener) { @@ -71,7 +71,7 @@ define([ } }; - var bindAllEvents = function (textarea, docBody, onEvent, unbind) + var _unused_bindAllEvents = function (textarea, docBody, onEvent, unbind) { /* we use docBody for the purposes of CKEditor. @@ -208,8 +208,10 @@ define([ // assert things here... if (realtime.getUserDoc() !== newText) { // this is a problem -// warn("realtime.getUserDoc() !== newText"); + warn("realtime.getUserDoc() !== newText"); } + //try{throw new Error();}catch(e){console.log(e.stack);} + console.log("2: " + realtime.Sha.hex_sha256(realtime.getUserDoc())); }; // pass your shiny new realtime into initialization functions @@ -255,11 +257,14 @@ define([ } }); - // TODO improve this RegExp such that it allows for more names - // right now it only handles names generated by rand64() - var whoami = new RegExp(userName.replace(/[\/\+]/g, function (c) { - return '\\' +c; - })); + realtime.onPatch(function () { + if (config.onRemote) { + config.onRemote({ + realtime: realtime + //realtime.getUserDoc() + }); + } + }); // when you receive a message... socket.onMessage.push(function (evt) { @@ -270,10 +275,11 @@ define([ verbose(message); allMessages.push(message); if (!initializing) { - if (PARANOIA) { - // FIXME this is out of sync with the application logic - onEvent(); - } + // FIXME this is out of sync with the application logic + console.log("xxx"); + window.cryptpad_propogate(); + } else { + console.log("init"); } realtime.message(message); if (/\[5,/.test(message)) { verbose("pong"); } @@ -281,16 +287,9 @@ define([ if (!initializing) { if (/\[2,/.test(message)) { //verbose("Got a patch"); - if (whoami.test(message)) { - //verbose("Received own message"); - } else { - //verbose("Received remote message"); - // obviously this is only going to get called if... XXX wat - if (config.onRemote) { config.onRemote({ - realtime: realtime - //realtime.getUserDoc() - }); } - } + +//TODO clean this all up + } } }); @@ -329,7 +328,7 @@ define([ }, 200); // TODO maybe push this out to the application layer. - bindAllEvents(null, doc, onEvent, false); + //bindAllEvents(null, doc, onEvent, false); // TODO rename 'sharejs.attach' to imply what we want to do var genOp = toReturn.propogate = sharejs.attach({ diff --git a/www/_socket/sharejs_textarea-transport-only.js b/www/_socket/sharejs_textarea-transport-only.js index 64d220051..910eca008 100644 --- a/www/_socket/sharejs_textarea-transport-only.js +++ b/www/_socket/sharejs_textarea-transport-only.js @@ -46,27 +46,28 @@ var attachTextarea = function(config) { var content = {}; // FIXME this is only necessary because we need to be able to update the - // textarea. This is being deprecated, however. Instead + // textarea. This is being deprecated, however. Instead var replaceText = function(newText) { content = newText; }; // *** remote -> local changes - ctx.onRemove(function(pos, length) { - replaceText(ctx.getUserDoc()); - }); - - ctx.onInsert(function(pos, text) { + ctx.onPatch(function(pos, length) { replaceText(ctx.getUserDoc()); }); + // propogate() return function (newContent) { if (newContent !== content) { applyChange(ctx, ctx.getUserDoc(), newContent); if (ctx.getUserDoc() !== newContent) { console.log("Expected that: `ctx.getUserDoc() === newContent`!"); } + console.log("1: " + ctx.Sha.hex_sha256(ctx.getUserDoc())); + return true; } + console.log("no change"); + return false; }; }; diff --git a/www/common/chainpad.js b/www/common/chainpad.js index c5854c7cf..2d45bf8ba 100644 --- a/www/common/chainpad.js +++ b/www/common/chainpad.js @@ -1163,6 +1163,7 @@ module.exports.create = function (userName, authToken, channelId, initialState, Common.assert(typeof(initialState) === 'string'); var realtime = ChainPad.create(userName, authToken, channelId, initialState, conf); return { + Sha: Sha, onPatch: enterChainPad(realtime, function (handler) { Common.assert(typeof(handler) === 'function'); realtime.patchHandlers.push(handler); diff --git a/www/pad/realtime-wysiwyg.js b/www/pad/realtime-wysiwyg.js index 30529a90f..2b35ef0a8 100644 --- a/www/pad/realtime-wysiwyg.js +++ b/www/pad/realtime-wysiwyg.js @@ -327,10 +327,11 @@ console.log(new Error().stack); error(false, 'realtime.getUserDoc() !== docText'); } }; - +var now = function () { return new Date().getTime(); }; var userDocBeforePatch; var incomingPatch = function () { if (isErrorState || initializing) { return; } + console.log("before patch " + now()); userDocBeforePatch = userDocBeforePatch || getFixedDocText(doc, ifr.contentWindow); if (PARANOIA && userDocBeforePatch !== getFixedDocText(doc, ifr.contentWindow)) { error(false, "userDocBeforePatch !== getFixedDocText(doc, ifr.contentWindow)"); @@ -339,6 +340,7 @@ console.log(new Error().stack); if (!op) { return; } attempt(HTMLPatcher.applyOp)( userDocBeforePatch, op, doc.body, Rangy, ifr.contentWindow); + console.log("after patch " + now()); }; realtime.onUserListChange(function (userList) {