Merge pull request #15 from xwiki-labs/diffdom
merge diffdom into netflux
This commit is contained in:
commit
7782069dbd
@ -28,13 +28,16 @@ define([
|
|||||||
toolbar;
|
toolbar;
|
||||||
|
|
||||||
var module = window.REALTIME_MODULE = {
|
var module = window.REALTIME_MODULE = {
|
||||||
localChangeInProgress: 0
|
localChangeInProgress: 0,
|
||||||
|
Hyperjson: Hyperjson,
|
||||||
|
Hyperscript: Hyperscript
|
||||||
};
|
};
|
||||||
|
|
||||||
var isNotMagicLine = function (el) {
|
var isNotMagicLine = function (el) {
|
||||||
// factor as:
|
// factor as:
|
||||||
// return !(el.tagName === 'SPAN' && el.contentEditable === 'false');
|
// 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) {
|
if (filter) {
|
||||||
console.log("[hyperjson.serializer] prevented an element" +
|
console.log("[hyperjson.serializer] prevented an element" +
|
||||||
"from being serialized:", el);
|
"from being serialized:", el);
|
||||||
@ -95,7 +98,7 @@ define([
|
|||||||
we should check when such an element is going to be
|
we should check when such an element is going to be
|
||||||
removed, and prevent that from happening. */
|
removed, and prevent that from happening. */
|
||||||
if (info.node && info.node.tagName === 'SPAN' &&
|
if (info.node && info.node.tagName === 'SPAN' &&
|
||||||
info.node.contentEditable === "true") {
|
info.node.getAttribute('contentEditable') === "false") {
|
||||||
// it seems to be a magicline plugin element...
|
// it seems to be a magicline plugin element...
|
||||||
if (info.diff.action === 'removeElement') {
|
if (info.diff.action === 'removeElement') {
|
||||||
// and you're about to remove it...
|
// and you're about to remove it...
|
||||||
@ -163,7 +166,8 @@ define([
|
|||||||
doc: inner,
|
doc: inner,
|
||||||
|
|
||||||
// provide initialstate...
|
// provide initialstate...
|
||||||
initialState: JSON.stringify(Hyperjson.fromDOM(inner, isNotMagicLine)),
|
initialState: JSON.stringify(Hyperjson
|
||||||
|
.fromDOM(inner, isNotMagicLine)) || '{}',
|
||||||
|
|
||||||
// really basic operational transform
|
// really basic operational transform
|
||||||
// reject patch if it results in invalid JSON
|
// reject patch if it results in invalid JSON
|
||||||
@ -186,8 +190,7 @@ define([
|
|||||||
var localWorkInProgress = function (stage) {
|
var localWorkInProgress = function (stage) {
|
||||||
if (module.localChangeInProgress) {
|
if (module.localChangeInProgress) {
|
||||||
console.error("Applied a change while a local patch was in progress");
|
console.error("Applied a change while a local patch was in progress");
|
||||||
alert("local work was interrupted at stage: " + stage);
|
console.error("local work was interrupted at stage: " + stage);
|
||||||
//module.realtimeInput.onLocal();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -200,6 +203,21 @@ define([
|
|||||||
|
|
||||||
var userDocStateDom = hjsonToDom(JSON.parse(shjson));
|
var userDocStateDom = hjsonToDom(JSON.parse(shjson));
|
||||||
localWorkInProgress(2); // check again
|
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
|
userDocStateDom.setAttribute("contenteditable", "true"); // lol wtf
|
||||||
localWorkInProgress(3); // check again
|
localWorkInProgress(3); // check again
|
||||||
var patch = (DD).diff(inner, userDocStateDom);
|
var patch = (DD).diff(inner, userDocStateDom);
|
||||||
|
|||||||
@ -147,7 +147,8 @@ define([
|
|||||||
passwd, // password, to be deprecated (maybe)
|
passwd, // password, to be deprecated (maybe)
|
||||||
channel, // the channel we're to connect to
|
channel, // the channel we're to connect to
|
||||||
|
|
||||||
// initialState argument. (optional)
|
/* optional unless your application expects JSON
|
||||||
|
from getUserDoc */
|
||||||
config.initialState || '',
|
config.initialState || '',
|
||||||
|
|
||||||
// transform function (optional), which handles conflicts
|
// transform function (optional), which handles conflicts
|
||||||
@ -160,7 +161,6 @@ define([
|
|||||||
// this is a problem
|
// this is a problem
|
||||||
warn("realtime.getUserDoc() !== newText");
|
warn("realtime.getUserDoc() !== newText");
|
||||||
}
|
}
|
||||||
//try{throw new Error();}catch(e){console.log(e.stack);}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// pass your shiny new realtime into initialization functions
|
// pass your shiny new realtime into initialization functions
|
||||||
|
|||||||
@ -220,10 +220,9 @@ var transform = Patch.transform = function (origToTransform, transformBy, doc, t
|
|||||||
Common.assert(origToTransform.parentHash === transformBy.parentHash);
|
Common.assert(origToTransform.parentHash === transformBy.parentHash);
|
||||||
var resultOfTransformBy = apply(transformBy, doc);
|
var resultOfTransformBy = apply(transformBy, doc);
|
||||||
|
|
||||||
toTransform = clone(origToTransform);
|
var toTransform = clone(origToTransform);
|
||||||
var text = doc;
|
var text = doc;
|
||||||
for (var i = toTransform.operations.length-1; i >= 0; i--) {
|
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--) {
|
for (var j = transformBy.operations.length-1; j >= 0; j--) {
|
||||||
toTransform.operations[i] = Operation.transform(text,
|
toTransform.operations[i] = Operation.transform(text,
|
||||||
toTransform.operations[i],
|
toTransform.operations[i],
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
define([], function () {
|
define([], function () {
|
||||||
|
|
||||||
// this makes recursing a lot simpler
|
// this makes recursing a lot simpler
|
||||||
var isArray = function (A) {
|
var isArray = function (A) {
|
||||||
return Object.prototype.toString.call(A)==='[object Array]';
|
return Object.prototype.toString.call(A)==='[object Array]';
|
||||||
@ -39,8 +38,14 @@ define([], function () {
|
|||||||
return cb(hj[0], hj[1], children);
|
return cb(hj[0], hj[1], children);
|
||||||
};
|
};
|
||||||
|
|
||||||
var prependDot = function (token) {
|
var classify = function (token) {
|
||||||
return '.' + token;
|
return '.' + token.trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
var isValidClass = function (x) {
|
||||||
|
if (x && /\S/.test(x)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var isTruthy = function (x) {
|
var isTruthy = function (x) {
|
||||||
@ -61,13 +66,13 @@ define([], function () {
|
|||||||
if(!el.attributes){
|
if(!el.attributes){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (predicate) {
|
if (predicate) {
|
||||||
if (!predicate(el)) {
|
if (!predicate(el)) {
|
||||||
// shortcircuit
|
// shortcircuit
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attributes = {};
|
var attributes = {};
|
||||||
|
|
||||||
var i = 0;
|
var i = 0;
|
||||||
@ -91,19 +96,25 @@ define([], function () {
|
|||||||
var sel = el.tagName;
|
var sel = el.tagName;
|
||||||
|
|
||||||
if(attributes.id){
|
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;
|
sel = sel +'#'+ attributes.id;
|
||||||
delete attributes.id;
|
delete attributes.id;
|
||||||
}
|
}
|
||||||
if(attributes.class){
|
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
|
/* 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
|
but this works and is a little less error prone, albeit slower
|
||||||
come back and speed it up when it comes time to optimize */
|
come back and speed it up when it comes time to optimize */
|
||||||
|
|
||||||
sel = sel + attributes.class
|
sel = sel + attributes.class
|
||||||
.split(/\s+/)
|
.split(/\s+/g)
|
||||||
.filter(isTruthy)
|
.filter(isValidClass)
|
||||||
.map(prependDot)
|
.map(classify)
|
||||||
.join('');
|
.join('')
|
||||||
|
.replace(/\.\./g, '.');
|
||||||
delete attributes.class;
|
delete attributes.class;
|
||||||
}
|
}
|
||||||
result.push(sel);
|
result.push(sel);
|
||||||
@ -116,11 +127,9 @@ define([], function () {
|
|||||||
|
|
||||||
// js hint complains if we use 'var' here
|
// js hint complains if we use 'var' here
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
for(; i < el.childNodes.length; i++){
|
for(; i < el.childNodes.length; i++){
|
||||||
children.push(DOM2HyperJSON(el.childNodes[i], predicate, filter));
|
children.push(DOM2HyperJSON(el.childNodes[i], predicate, filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push(children.filter(isTruthy));
|
result.push(children.filter(isTruthy));
|
||||||
|
|
||||||
if (filter) {
|
if (filter) {
|
||||||
|
|||||||
@ -6,6 +6,11 @@ define([
|
|||||||
|
|
||||||
var validate = JsonOT.validate = function (text, toTransform, transformBy) {
|
var validate = JsonOT.validate = function (text, toTransform, transformBy) {
|
||||||
try {
|
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 resultOp = ChainPad.Operation.transform0(text, toTransform, transformBy);
|
||||||
var text2 = ChainPad.Operation.apply(transformBy, text);
|
var text2 = ChainPad.Operation.apply(transformBy, text);
|
||||||
var text3 = ChainPad.Operation.apply(resultOp, text2);
|
var text3 = ChainPad.Operation.apply(resultOp, text2);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user