diff --git a/www/hack/main.js b/www/hack/main.js index d63aadbfa..8805a3169 100644 --- a/www/hack/main.js +++ b/www/hack/main.js @@ -1,12 +1,10 @@ define([ '/api/config?cb=' + Math.random().toString(16).substring(2), - '/common/realtime-input.js', - '/common/messages.js', + '/common/RealtimeTextarea.js', '/common/crypto.js', - '/common/cursor.js', - '/bower_components/jquery/dist/jquery.min.js', - '/customize/pad.js' -], function (Config, Realtime, Messages, Crypto, Cursor) { + '/common/TextPatcher.js', + '/bower_components/jquery/dist/jquery.min.js' +], function (Config, Realtime, Crypto, TextPatcher) { var $ = window.jQuery; $(window).on('hashchange', function() { window.location.reload(); @@ -21,6 +19,8 @@ define([ var $textarea = $('textarea'), $run = $('#run'); + var module = {}; + /* onRemote onInit @@ -31,7 +31,7 @@ define([ var config = { textarea: $textarea[0], - websocketURL: Config.websocketURL, + websocketURL: Config.websocketURL + '_old', webrtcURL: Config.webrtcURL, userName: Crypto.rand64(8), channel: key.channel, @@ -39,29 +39,56 @@ define([ }; var initializing = true; - $textarea.attr('disabled', true); + var setEditable = function (bool) { $textarea.attr('disabled', !bool); }; + var canonicalize = function (text) { return text.replace(/\r\n/g, '\n'); }; + + setEditable(false); var onInit = config.onInit = function (info) { }; - var onRemote = config.onRemote = function (contents) { + var onRemote = config.onRemote = function (info) { if (initializing) { return; } + + var userDoc = info.realtime.getUserDoc(); + var current = canonicalize($textarea.val()); + + var op = TextPatcher.diff(current, userDoc); + + var elem = $textarea[0]; + + var selects = ['selectionStart', 'selectionEnd'].map(function (attr) { + return TextPatcher.transformCursor(elem[attr], op); + }); + + $textarea.val(userDoc); + elem.selectionStart = selects[0]; + elem.selectionEnd = selects[1]; + // TODO do something on external messages // http://webdesign.tutsplus.com/tutorials/how-to-display-update-notifications-in-the-browser-tab--cms-23458 }; var onReady = config.onReady = function (info) { + module.patchText = TextPatcher.create({ + realtime: info.realtime + // logging: true + }); initializing = false; - $textarea.attr('disabled', false); + setEditable(true); + $textarea.val(info.realtime.getUserDoc()); }; var onAbort = config.onAbort = function (info) { - $textarea.attr('disabled', true); + setEditable(false); window.alert("Server Connection Lost"); }; - var rt = window.rt = Realtime.start(config); + var onLocal = config.onLocal = function () { + if (initializing) { return; } + module.patchText(canonicalize($textarea.val())); + }; - var cursor = Cursor($textarea[0]); + var rt = window.rt = Realtime.start(config); var splice = function (str, index, chars) { var count = chars.length; @@ -98,7 +125,9 @@ define([ // track when control keys are released }); + //$textarea.on('change', onLocal); $textarea.on('keypress', function (e) { + onLocal(); switch (e.key) { case 'Tab': // insert a tab wherever the cursor is... @@ -118,16 +147,18 @@ define([ // simulate a keypress so the event goes through.. // prevent default behaviour for tab e.preventDefault(); - rt.bumpSharejs(); + + onLocal(); break; default: break; } }); - $textarea.on('change', function () { - rt.bumpSharejs(); - }); + ['cut', 'paste', 'change', 'keyup', 'keydown', 'select', 'textInput'] + .forEach(function (evt) { + $textarea.on(evt, onLocal); + }); $run.click(function (e) { e.preventDefault();