diff --git a/www/_socket/main.js b/www/_socket/main.js index 0974a66f0..f334929e9 100644 --- a/www/_socket/main.js +++ b/www/_socket/main.js @@ -28,13 +28,16 @@ define([ toolbar; var module = window.REALTIME_MODULE = { - localChangeInProgress: 0 + localChangeInProgress: 0, + Hyperjson: Hyperjson, + Hyperscript: Hyperscript }; var isNotMagicLine = function (el) { // factor as: // return !(el.tagName === 'SPAN' && el.contentEditable === 'false'); - var filter = (el.tagName === 'SPAN' && el.contentEditable === 'false'); + var filter = (el.tagName === 'SPAN' && + el.getAttribute('contentEditable') === 'false'); if (filter) { console.log("[hyperjson.serializer] prevented an element" + "from being serialized:", el); @@ -95,7 +98,7 @@ define([ we should check when such an element is going to be removed, and prevent that from happening. */ if (info.node && info.node.tagName === 'SPAN' && - info.node.contentEditable === "true") { + info.node.getAttribute('contentEditable') === "false") { // it seems to be a magicline plugin element... if (info.diff.action === 'removeElement') { // and you're about to remove it... @@ -163,7 +166,8 @@ define([ doc: inner, // provide initialstate... - initialState: JSON.stringify(Hyperjson.fromDOM(inner, isNotMagicLine)), + initialState: JSON.stringify(Hyperjson + .fromDOM(inner, isNotMagicLine)) || '{}', // really basic operational transform // reject patch if it results in invalid JSON @@ -186,8 +190,7 @@ define([ var localWorkInProgress = function (stage) { if (module.localChangeInProgress) { console.error("Applied a change while a local patch was in progress"); - alert("local work was interrupted at stage: " + stage); - //module.realtimeInput.onLocal(); + console.error("local work was interrupted at stage: " + stage); return true; } return false; @@ -200,6 +203,21 @@ define([ var userDocStateDom = hjsonToDom(JSON.parse(shjson)); localWorkInProgress(2); // check again + + + /* in the DOM contentEditable is "false" + while "contenteditable" is undefined. + + When it goes over the wire, it seems hyperjson transforms it. + of course, hyperjson simply gets attributes from the DOM. + + el.attributes returns 'contenteditable', so we have to correct for that + + There are quite possibly all sorts of other attributes which might lose + information, and we won't know what they are until after we've lost them. + + this comes from hyperscript line 101. FIXME maybe + */ userDocStateDom.setAttribute("contenteditable", "true"); // lol wtf localWorkInProgress(3); // check again var patch = (DD).diff(inner, userDocStateDom); diff --git a/www/_socket/realtime-input.js b/www/_socket/realtime-input.js index 06caa1c5d..a8d02e0b5 100644 --- a/www/_socket/realtime-input.js +++ b/www/_socket/realtime-input.js @@ -147,7 +147,8 @@ define([ passwd, // password, to be deprecated (maybe) channel, // the channel we're to connect to - // initialState argument. (optional) + /* optional unless your application expects JSON + from getUserDoc */ config.initialState || '', // transform function (optional), which handles conflicts @@ -160,7 +161,6 @@ define([ // this is a problem warn("realtime.getUserDoc() !== newText"); } - //try{throw new Error();}catch(e){console.log(e.stack);} }; // pass your shiny new realtime into initialization functions diff --git a/www/common/chainpad.js b/www/common/chainpad.js index 502e502ab..9d9dcc071 100644 --- a/www/common/chainpad.js +++ b/www/common/chainpad.js @@ -220,10 +220,9 @@ var transform = Patch.transform = function (origToTransform, transformBy, doc, t Common.assert(origToTransform.parentHash === transformBy.parentHash); var resultOfTransformBy = apply(transformBy, doc); - toTransform = clone(origToTransform); + var toTransform = clone(origToTransform); var text = doc; for (var i = toTransform.operations.length-1; i >= 0; i--) { - text = Operation.apply(toTransform.operations[i], text); for (var j = transformBy.operations.length-1; j >= 0; j--) { toTransform.operations[i] = Operation.transform(text, toTransform.operations[i], diff --git a/www/common/hyperjson.js b/www/common/hyperjson.js index 1cfeda733..27bee7cee 100644 --- a/www/common/hyperjson.js +++ b/www/common/hyperjson.js @@ -1,5 +1,4 @@ define([], function () { - // this makes recursing a lot simpler var isArray = function (A) { return Object.prototype.toString.call(A)==='[object Array]'; @@ -39,8 +38,14 @@ define([], function () { return cb(hj[0], hj[1], children); }; - var prependDot = function (token) { - return '.' + token; + var classify = function (token) { + return '.' + token.trim(); + }; + + var isValidClass = function (x) { + if (x && /\S/.test(x)) { + return true; + } }; var isTruthy = function (x) { @@ -61,13 +66,13 @@ define([], function () { if(!el.attributes){ return; } - if (predicate) { if (!predicate(el)) { // shortcircuit return; } } + var attributes = {}; var i = 0; @@ -91,19 +96,25 @@ define([], function () { var sel = el.tagName; if(attributes.id){ + // we don't have to do much to validate IDs because the browser + // will only permit one id to exist + // unless we come across a strange browser in the wild sel = sel +'#'+ attributes.id; delete attributes.id; } if(attributes.class){ + // actually parse out classes so that we produce a valid selector + // string. leading or trailing spaces would have caused it to choke + // these are really common in generated html /* TODO this can be done with RegExps alone, and it will be faster but this works and is a little less error prone, albeit slower come back and speed it up when it comes time to optimize */ - sel = sel + attributes.class - .split(/\s+/) - .filter(isTruthy) - .map(prependDot) - .join(''); + .split(/\s+/g) + .filter(isValidClass) + .map(classify) + .join('') + .replace(/\.\./g, '.'); delete attributes.class; } result.push(sel); @@ -116,11 +127,9 @@ define([], function () { // js hint complains if we use 'var' here i = 0; - for(; i < el.childNodes.length; i++){ children.push(DOM2HyperJSON(el.childNodes[i], predicate, filter)); } - result.push(children.filter(isTruthy)); if (filter) { diff --git a/www/common/json-ot.js b/www/common/json-ot.js index 41a628dc4..98e1af4ec 100644 --- a/www/common/json-ot.js +++ b/www/common/json-ot.js @@ -6,6 +6,11 @@ define([ var validate = JsonOT.validate = function (text, toTransform, transformBy) { try { + // text = O (mutual common ancestor) + // toTransform = A (the first incoming operation) + // transformBy = B (the second incoming operation) + // threeway merge (0, A, B) + var resultOp = ChainPad.Operation.transform0(text, toTransform, transformBy); var text2 = ChainPad.Operation.apply(transformBy, text); var text3 = ChainPad.Operation.apply(resultOp, text2);