From 6bb37aed449f2b8674d27d2324201f54e0ca6b1b Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 12 Apr 2016 14:05:56 +0200 Subject: [PATCH 1/8] main.js : support tab insertion in /hack/ pad --- www/hack/main.js | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/www/hack/main.js b/www/hack/main.js index ab38f8402..8877260eb 100644 --- a/www/hack/main.js +++ b/www/hack/main.js @@ -3,9 +3,10 @@ define([ '/common/realtime-input.js', '/common/messages.js', '/common/crypto.js', + '/common/cursor.js', '/bower_components/jquery/dist/jquery.min.js', '/customize/pad.js' -], function (Config, Realtime, Messages, Crypto) { +], function (Config, Realtime, Messages, Crypto, Cursor) { var $ = window.jQuery; $(window).on('hashchange', function() { window.location.reload(); @@ -59,6 +60,48 @@ define([ var rt = Realtime.start(config); + var cursor = Cursor($textarea[0]); + + var splice = function (str, index, chars) { + var count = chars.length; + return str.slice(0, index) + chars + str.slice((index -1) + count); + }; + + var setSelectionRange = function (input, start, end) { + if (input.setSelectionRange) { + input.focus(); + input.setSelectionRange(start, end); + } else if (input.createTextRange) { + var range = input.createTextRange(); + range.collapse(true); + range.moveEnd('character', end); + range.moveStart('character', start); + range.select(); + } + }; + + var setCursor = function (el, pos) { + setSelectionRange(el, pos, pos); + }; + + $textarea.on('keypress', function (e) { + switch (e.key) { + case 'Tab': + // insert a tab wherever the cursor is... + var position = $textarea.prop("selectionStart"); + if (typeof position !== 'undefined') { + $textarea.val(function (i, val) { + return splice(val, position, "\t"); + }); + setCursor($textarea[0], position +1); + } + // prevent default behaviour for tab + e.preventDefault(); + default: + break; + } + }); + $run.click(function (e) { e.preventDefault(); var content = $textarea.val(); From 9f0cc4ed64f92c8ed8f951382efc901153e3f213 Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 12 Apr 2016 18:51:03 +0200 Subject: [PATCH 2/8] update hack with a slightly better UI --- www/hack/index.html | 37 +++++++++++++++++++++++++++++-------- www/hack/main.js | 31 +++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/www/hack/index.html b/www/hack/index.html index 4fa7e6065..2e8df970f 100644 --- a/www/hack/index.html +++ b/www/hack/index.html @@ -12,8 +12,14 @@ box-sizing: border-box; } textarea{ + position: absolute; + top: 5vh; + left: 0px; + border: 0px; + + padding-top: 15px; width: 100%; - height: 100vh; + height: 95vh; max-width: 100%; max-height: 100vh; @@ -32,26 +38,41 @@ color: #637476; } - #run { + #panel { position: fixed; top: 0px; right: 0px; - - z-index: 100; - width: 5vw; + width: 100%; height: 5vh; + z-index: 95; + background-color: #777; + /* min-height: 75px; */ + } + #run { + display: block; + float: right; + height: 100%; + width: 10vw; + z-index: 100; + line-height: 5vw; + font-size: 1.5em; background-color: #222; color: #CCC; - - display: block; text-align: center; + border-radius: 5%; + border: 0px; } - RUN +
+ + + + RUN +
diff --git a/www/hack/main.js b/www/hack/main.js index 8877260eb..f5618c8b3 100644 --- a/www/hack/main.js +++ b/www/hack/main.js @@ -84,16 +84,35 @@ define([ setSelectionRange(el, pos, pos); }; + var state = {}; + + // TODO + $textarea.on('keydown', function (e) { + // track when control keys are pushed down + //switch (e.key) { } + }); + + // TODO + $textarea.on('keyup', function (e) { + // track when control keys are released + }); + $textarea.on('keypress', function (e) { switch (e.key) { case 'Tab': // insert a tab wherever the cursor is... - var position = $textarea.prop("selectionStart"); - if (typeof position !== 'undefined') { - $textarea.val(function (i, val) { - return splice(val, position, "\t"); - }); - setCursor($textarea[0], position +1); + var start = $textarea.prop('selectionStart'); + var end = $textarea.prop('selectionEnd'); + if (typeof start !== 'undefined') { + if (start === end) { + $textarea.val(function (i, val) { + return splice(val, start, "\t"); + }); + setCursor($textarea[0], start +1); + } else { + // indentation?? this ought to be fun. + + } } // prevent default behaviour for tab e.preventDefault(); From 284da6a4e9bb0c807473d8a434462e4eaf8a9a1a Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 13 Apr 2016 10:16:44 +0200 Subject: [PATCH 3/8] minor improvements I made to the /hack/ pad last night --- www/hack/main.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/www/hack/main.js b/www/hack/main.js index f5618c8b3..b775b73dc 100644 --- a/www/hack/main.js +++ b/www/hack/main.js @@ -58,7 +58,7 @@ define([ window.alert("Server Connection Lost"); }; - var rt = Realtime.start(config); + var rt = window.rt = Realtime.start(config); var cursor = Cursor($textarea[0]); @@ -114,13 +114,20 @@ define([ } } + // simulate a keypress so the event goes through.. // prevent default behaviour for tab e.preventDefault(); + rt.bumpSharejs(); + break; default: break; } }); + $textarea.on('change', function () { + rt.bumpSharejs(); + }); + $run.click(function (e) { e.preventDefault(); var content = $textarea.val(); From 8a369635820fe5a390336af8bff655504161a5cc Mon Sep 17 00:00:00 2001 From: Caleb James DeLisle Date: Wed, 13 Apr 2016 13:51:01 +0200 Subject: [PATCH 4/8] Enable ChainPad PARANOIA mode but remove the part which causes most slowness --- www/common/chainpad.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/www/common/chainpad.js b/www/common/chainpad.js index 9d9dcc071..134d80ce2 100644 --- a/www/common/chainpad.js +++ b/www/common/chainpad.js @@ -368,7 +368,7 @@ var random = Patch.random = function (doc, opCount) { * along with this program. If not, see . */ -var PARANOIA = module.exports.PARANOIA = false; +var PARANOIA = module.exports.PARANOIA = true; /* throw errors over non-compliant messages which would otherwise be treated as invalid */ var TESTING = module.exports.TESTING = true; @@ -832,7 +832,7 @@ var check = ChainPad.check = function(realtime) { Common.assert(uiDoc === realtime.userInterfaceContent); } - var doc = realtime.authDoc; + /*var doc = realtime.authDoc; var patchMsg = realtime.best; Common.assert(patchMsg.content.inverseOf.parentHash === realtime.uncommitted.parentHash); var patches = []; @@ -844,7 +844,7 @@ var check = ChainPad.check = function(realtime) { while ((patchMsg = patches.pop())) { doc = Patch.apply(patchMsg.content, doc); } - Common.assert(doc === realtime.authDoc); + Common.assert(doc === realtime.authDoc);*/ }; var doOperation = ChainPad.doOperation = function (realtime, op) { From 0537c289198f21627997efebe358224d20c6c940 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 13 Apr 2016 13:53:20 +0200 Subject: [PATCH 5/8] Add switchable logging to TextPatcher.js --- www/common/TextPatcher.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/www/common/TextPatcher.js b/www/common/TextPatcher.js index 66858826d..ee9c6fb61 100644 --- a/www/common/TextPatcher.js +++ b/www/common/TextPatcher.js @@ -79,14 +79,15 @@ var log = function (text, op) { Due to its reliance on patch, applyChange has side effects on the supplied realtime facade. */ -var applyChange = function(ctx, oldval, newval) { +var applyChange = function(ctx, oldval, newval, logging) { var op = diff(oldval, newval); - // log(oldval, op) + if (logging) { log(oldval, op) } patch(ctx, op); }; var create = function(config) { var ctx = config.realtime; + var logging = config.logging; // initial state will always fail the !== check in genop. // because nothing will equal this object @@ -100,7 +101,7 @@ var create = function(config) { // propogate() return function (newContent) { if (newContent !== content) { - applyChange(ctx, ctx.getUserDoc(), newContent); + applyChange(ctx, ctx.getUserDoc(), newContent, logging); if (ctx.getUserDoc() !== newContent) { console.log("Expected that: `ctx.getUserDoc() === newContent`!"); } From 259772dd62035c03759a075b2e30a41f98b08c7b Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 13 Apr 2016 13:54:25 +0200 Subject: [PATCH 6/8] Turn on TextPatcher logging for _socket --- www/common/RealtimeTextSocket.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/www/common/RealtimeTextSocket.js b/www/common/RealtimeTextSocket.js index edb8e3791..4821ce454 100644 --- a/www/common/RealtimeTextSocket.js +++ b/www/common/RealtimeTextSocket.js @@ -264,7 +264,8 @@ define([ }, 200); toReturn.patchText = TextPatcher.create({ - realtime: realtime + realtime: realtime, + logging: true }); realtime.start(); From f4c5b2a99646f9310c0b496d69907ceadb74b72f Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 13 Apr 2016 14:51:15 +0200 Subject: [PATCH 7/8] Add sane defaults to TextPatcher diffs --- www/common/TextPatcher.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/common/TextPatcher.js b/www/common/TextPatcher.js index ee9c6fb61..98ccea65a 100644 --- a/www/common/TextPatcher.js +++ b/www/common/TextPatcher.js @@ -23,8 +23,8 @@ var diff = function (oldval, newval) { commonEnd++; } - var toRemove; - var toInsert; + var toRemove = 0; + var toInsert = ''; /* throw some assertions in here before dropping patches into the realtime */ if (oldval.length !== commonStart + commonEnd) { From a1fe941f6990fe733a8ed0ca76c875c6bdb1e5d8 Mon Sep 17 00:00:00 2001 From: ansuz Date: Wed, 13 Apr 2016 15:00:19 +0200 Subject: [PATCH 8/8] Always serialize the DOM in one way. --- www/_socket/main.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/www/_socket/main.js b/www/_socket/main.js index 67bfaff89..042bd3c20 100644 --- a/www/_socket/main.js +++ b/www/_socket/main.js @@ -45,6 +45,16 @@ define([ return true; }; + /* catch `type="_moz"` before it goes over the wire */ + var brFilter = function (hj) { + if (hj[1].type === '_moz') { hj[1].type = undefined; } + return hj; + }; + + var stringifyDOM = function (dom) { + return JSON.stringify(Hyperjson.fromDOM(dom, isNotMagicLine, brFilter)); + }; + var andThen = function (Ckeditor) { $(window).on('hashchange', function() { window.location.reload(); @@ -76,6 +86,8 @@ define([ var inner = window.inner = documentBody; var cursor = window.cursor = Cursor(inner); + + var setEditable = function (bool) { // careful about putting attributes onto the DOM // they get put into the chain, and you can have trouble @@ -165,8 +177,7 @@ define([ doc: inner, // provide initialstate... - initialState: JSON.stringify(Hyperjson - .fromDOM(inner, isNotMagicLine)) || '{}', + initialState: stringifyDOM(inner) || '{}', // really basic operational transform // reject patch if it results in invalid JSON @@ -221,7 +232,8 @@ define([ // build a dom from HJSON, diff, and patch the editor applyHjson(shjson); - var shjson2 = JSON.stringify(Hyperjson.fromDOM(inner)); + var shjson2 = stringifyDOM(inner); + if (shjson2 !== shjson) { console.error("shjson2 !== shjson"); module.realtimeInput.patchText(shjson2); @@ -255,11 +267,6 @@ define([ var rti = module.realtimeInput = realtimeInput.start(realtimeOptions); - /* catch `type="_moz"` before it goes over the wire */ - var brFilter = function (hj) { - if (hj[1].type === '_moz') { hj[1].type = undefined; } - return hj; - }; /* It's incredibly important that you assign 'rti.onLocal' It's used inside of realtimeInput to make sure that all changes @@ -270,7 +277,7 @@ define([ the code less extensible. */ var propogate = rti.onLocal = function () { - var shjson = JSON.stringify(Hyperjson.fromDOM(inner, isNotMagicLine, brFilter)); + var shjson = stringifyDOM(inner); if (!rti.patchText(shjson)) { return; }