outsourced all types (except for object type)
This commit is contained in:
parent
c663230c1b
commit
96ed8b0f98
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -316,7 +316,7 @@ module.exports = function() {
|
||||
}
|
||||
this.prev_cl.next_cl = this.next_cl;
|
||||
this.next_cl.prev_cl = this.prev_cl;
|
||||
if (this.content instanceof ops.Operation && !deleted_earlyer) {
|
||||
if (this.content instanceof ops.Operation) {
|
||||
this.content.referenced_by--;
|
||||
if (this.content.referenced_by <= 0 && !this.content.is_deleted) {
|
||||
this.content.applyDelete();
|
||||
|
@ -1,97 +0,0 @@
|
||||
var json_types_uninitialized,
|
||||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
||||
__hasProp = {}.hasOwnProperty;
|
||||
|
||||
json_types_uninitialized = require("./JsonTypes");
|
||||
|
||||
module.exports = function(HB) {
|
||||
var XmlType, json_types, parser, types;
|
||||
json_types = json_types_uninitialized(HB);
|
||||
types = json_types.types;
|
||||
parser = json_types.parser;
|
||||
XmlType = (function(_super) {
|
||||
__extends(XmlType, _super);
|
||||
|
||||
function XmlType(uid, _at_tagname, attributes, elements, _at_xml) {
|
||||
this.tagname = _at_tagname;
|
||||
this.xml = _at_xml;
|
||||
}
|
||||
|
||||
XmlType.prototype.setXmlProxy = function() {};
|
||||
|
||||
XmlType.prototype.val = function(enforce) {
|
||||
var a, attr, attr_name, e, n, text_node, value;
|
||||
if (enforce == null) {
|
||||
enforce = false;
|
||||
}
|
||||
if (typeof document !== "undefined" && document !== null) {
|
||||
if ((this.xml == null) || enforce) {
|
||||
this.xml = document.createElement(this.tagname);
|
||||
attr = this.attributes.val();
|
||||
for (attr_name in attr) {
|
||||
value = attr[attr_name];
|
||||
if (value != null) {
|
||||
a = document.createAttribute(attr_name);
|
||||
a.value = value;
|
||||
this.xml.setAttributeNode(a);
|
||||
}
|
||||
}
|
||||
e = this.elements.beginning.next_cl;
|
||||
while (e.type !== "Delimiter") {
|
||||
n = e.content;
|
||||
if (!e.isDeleted() && (e.content != null)) {
|
||||
if (n.type === "XmlType") {
|
||||
this.xml.appendChild(n.val(enforce));
|
||||
} else if (n.type === "TextNodeType") {
|
||||
text_node = n.val();
|
||||
this.xml.appendChild(text_node);
|
||||
} else {
|
||||
throw new Error("Internal structure cannot be transformed to dom");
|
||||
}
|
||||
}
|
||||
e = e.next_cl;
|
||||
}
|
||||
}
|
||||
this.setXmlProxy();
|
||||
return this.xml;
|
||||
}
|
||||
};
|
||||
|
||||
XmlType.prototype.execute = function() {
|
||||
return XmlType.__super__.execute.call(this);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
if not @validateSavedOperations()
|
||||
return false
|
||||
else
|
||||
|
||||
return true
|
||||
*/
|
||||
|
||||
XmlType.prototype.getParent = function() {
|
||||
return this.parent;
|
||||
};
|
||||
|
||||
XmlType.prototype._encode = function() {
|
||||
var json;
|
||||
json = {
|
||||
'type': this.type,
|
||||
'attributes': this.attributes.getUid(),
|
||||
'elements': this.elements.getUid(),
|
||||
'tagname': this.tagname,
|
||||
'uid': this.getUid()
|
||||
};
|
||||
return json;
|
||||
};
|
||||
|
||||
return XmlType;
|
||||
|
||||
})(types.Insert);
|
||||
return parser['XmlType'] = function(json) {
|
||||
var attributes, elements, tagname, uid;
|
||||
uid = json['uid'], attributes = json['attributes'], elements = json['elements'], tagname = json['tagname'];
|
||||
return new XmlType(uid, tagname, attributes, elements, void 0);
|
||||
};
|
||||
};
|
@ -1,84 +0,0 @@
|
||||
var YList;
|
||||
|
||||
YList = (function() {
|
||||
function YList(list) {
|
||||
if (list == null) {
|
||||
this._list = [];
|
||||
} else if (list.constructor === Array) {
|
||||
this._list = list;
|
||||
} else {
|
||||
throw new Error("Y.List expects an Array as a parameter");
|
||||
}
|
||||
}
|
||||
|
||||
YList.prototype._name = "List";
|
||||
|
||||
YList.prototype._getModel = function(types, ops) {
|
||||
if (this._model == null) {
|
||||
this._model = new ops.ListManager(this).execute();
|
||||
this._model.insert(0, this._list);
|
||||
}
|
||||
delete this._list;
|
||||
return this._model;
|
||||
};
|
||||
|
||||
YList.prototype._setModel = function(_at__model) {
|
||||
this._model = _at__model;
|
||||
return delete this._list;
|
||||
};
|
||||
|
||||
YList.prototype.val = function() {
|
||||
return this._model.val.apply(this._model, arguments);
|
||||
};
|
||||
|
||||
YList.prototype.observe = function() {
|
||||
this._model.observe.apply(this._model, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
YList.prototype.unobserve = function() {
|
||||
this._model.unobserve.apply(this._model, arguments);
|
||||
return this;
|
||||
};
|
||||
|
||||
YList.prototype.insert = function(position, content) {
|
||||
if (typeof position !== "number") {
|
||||
throw new Error("Y.List.insert expects a Number as the first parameter!");
|
||||
}
|
||||
this._model.insert(position, [content]);
|
||||
return this;
|
||||
};
|
||||
|
||||
YList.prototype.insertContents = function(position, contents) {
|
||||
if (typeof position !== "number") {
|
||||
throw new Error("Y.List.insert expects a Number as the first parameter!");
|
||||
}
|
||||
this._model.insert(position, contents);
|
||||
return this;
|
||||
};
|
||||
|
||||
YList.prototype["delete"] = function(position, length) {
|
||||
this._model["delete"](position, length);
|
||||
return this;
|
||||
};
|
||||
|
||||
YList.prototype.push = function(content) {
|
||||
this._model.push(content);
|
||||
return this;
|
||||
};
|
||||
|
||||
return YList;
|
||||
|
||||
})();
|
||||
|
||||
if (typeof window !== "undefined" && window !== null) {
|
||||
if (window.Y != null) {
|
||||
window.Y.List = YList;
|
||||
} else {
|
||||
throw new Error("You must first import Y!");
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined" && module !== null) {
|
||||
module.exports = YList;
|
||||
}
|
@ -1,335 +0,0 @@
|
||||
var YText;
|
||||
|
||||
YText = (function() {
|
||||
function YText(text) {
|
||||
this.textfields = [];
|
||||
if (text == null) {
|
||||
this._text = "";
|
||||
} else if (text.constructor === String) {
|
||||
this._text = text;
|
||||
} else {
|
||||
throw new Error("Y.Text expects a String as a constructor");
|
||||
}
|
||||
}
|
||||
|
||||
YText.prototype._name = "Text";
|
||||
|
||||
YText.prototype._getModel = function(types, ops) {
|
||||
if (this._model == null) {
|
||||
this._model = new ops.ListManager(this).execute();
|
||||
this.insert(0, this._text);
|
||||
}
|
||||
delete this._text;
|
||||
return this._model;
|
||||
};
|
||||
|
||||
YText.prototype._setModel = function(_at__model) {
|
||||
this._model = _at__model;
|
||||
return delete this._text;
|
||||
};
|
||||
|
||||
YText.prototype.val = function() {
|
||||
return this._model.fold("", function(left, o) {
|
||||
return left + o.val();
|
||||
});
|
||||
};
|
||||
|
||||
YText.prototype.observe = function() {
|
||||
return this._model.observe.apply(this._model, arguments);
|
||||
};
|
||||
|
||||
YText.prototype.unobserve = function() {
|
||||
return this._model.unobserve.apply(this._model, arguments);
|
||||
};
|
||||
|
||||
YText.prototype.toString = function() {
|
||||
return this.val();
|
||||
};
|
||||
|
||||
YText.prototype.insert = function(position, content) {
|
||||
var ith;
|
||||
if (content.constructor !== String) {
|
||||
throw new Error("Y.String.insert expects a String as the second parameter!");
|
||||
}
|
||||
if (typeof position !== "number") {
|
||||
throw new Error("Y.String.insert expects a Number as the first parameter!");
|
||||
}
|
||||
if (content.length > 0) {
|
||||
ith = this._model.getOperationByPosition(position);
|
||||
return this._model.insertAfter(ith, content);
|
||||
}
|
||||
};
|
||||
|
||||
YText.prototype["delete"] = function(position, length) {
|
||||
return this._model["delete"](position, length);
|
||||
};
|
||||
|
||||
YText.prototype.bind = function(textfield, dom_root) {
|
||||
var createRange, creator_token, t, word, writeContent, writeRange, _i, _len, _ref;
|
||||
if (dom_root == null) {
|
||||
dom_root = window;
|
||||
}
|
||||
if (dom_root.getSelection == null) {
|
||||
dom_root = window;
|
||||
}
|
||||
_ref = this.textfields;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
t = _ref[_i];
|
||||
if (t === textfield) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
creator_token = false;
|
||||
word = this;
|
||||
textfield.value = this.val();
|
||||
this.textfields.push(textfield);
|
||||
if ((textfield.selectionStart != null) && (textfield.setSelectionRange != null)) {
|
||||
createRange = function(fix) {
|
||||
var left, right;
|
||||
left = textfield.selectionStart;
|
||||
right = textfield.selectionEnd;
|
||||
if (fix != null) {
|
||||
left = fix(left);
|
||||
right = fix(right);
|
||||
}
|
||||
return {
|
||||
left: left,
|
||||
right: right
|
||||
};
|
||||
};
|
||||
writeRange = function(range) {
|
||||
writeContent(word.val());
|
||||
return textfield.setSelectionRange(range.left, range.right);
|
||||
};
|
||||
writeContent = function(content) {
|
||||
return textfield.value = content;
|
||||
};
|
||||
} else {
|
||||
createRange = function(fix) {
|
||||
var clength, edited_element, range, s;
|
||||
range = {};
|
||||
s = dom_root.getSelection();
|
||||
clength = textfield.textContent.length;
|
||||
range.left = Math.min(s.anchorOffset, clength);
|
||||
range.right = Math.min(s.focusOffset, clength);
|
||||
if (fix != null) {
|
||||
range.left = fix(range.left);
|
||||
range.right = fix(range.right);
|
||||
}
|
||||
edited_element = s.focusNode;
|
||||
if (edited_element === textfield || edited_element === textfield.childNodes[0]) {
|
||||
range.isReal = true;
|
||||
} else {
|
||||
range.isReal = false;
|
||||
}
|
||||
return range;
|
||||
};
|
||||
writeRange = function(range) {
|
||||
var r, s, textnode;
|
||||
writeContent(word.val());
|
||||
textnode = textfield.childNodes[0];
|
||||
if (range.isReal && (textnode != null)) {
|
||||
if (range.left < 0) {
|
||||
range.left = 0;
|
||||
}
|
||||
range.right = Math.max(range.left, range.right);
|
||||
if (range.right > textnode.length) {
|
||||
range.right = textnode.length;
|
||||
}
|
||||
range.left = Math.min(range.left, range.right);
|
||||
r = document.createRange();
|
||||
r.setStart(textnode, range.left);
|
||||
r.setEnd(textnode, range.right);
|
||||
s = window.getSelection();
|
||||
s.removeAllRanges();
|
||||
return s.addRange(r);
|
||||
}
|
||||
};
|
||||
writeContent = function(content) {
|
||||
var c, content_array, i, _j, _len1, _results;
|
||||
content_array = content.replace(new RegExp("\n", 'g'), " ").split(" ");
|
||||
textfield.innerText = "";
|
||||
_results = [];
|
||||
for (i = _j = 0, _len1 = content_array.length; _j < _len1; i = ++_j) {
|
||||
c = content_array[i];
|
||||
textfield.innerText += c;
|
||||
if (i !== content_array.length - 1) {
|
||||
_results.push(textfield.innerHTML += ' ');
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
}
|
||||
writeContent(this.val());
|
||||
this.observe(function(events) {
|
||||
var event, fix, o_pos, r, _j, _len1, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
|
||||
event = events[_j];
|
||||
if (!creator_token) {
|
||||
if (event.type === "insert") {
|
||||
o_pos = event.position;
|
||||
fix = function(cursor) {
|
||||
if (cursor <= o_pos) {
|
||||
return cursor;
|
||||
} else {
|
||||
cursor += 1;
|
||||
return cursor;
|
||||
}
|
||||
};
|
||||
r = createRange(fix);
|
||||
_results.push(writeRange(r));
|
||||
} else if (event.type === "delete") {
|
||||
o_pos = event.position;
|
||||
fix = function(cursor) {
|
||||
if (cursor < o_pos) {
|
||||
return cursor;
|
||||
} else {
|
||||
cursor -= 1;
|
||||
return cursor;
|
||||
}
|
||||
};
|
||||
r = createRange(fix);
|
||||
_results.push(writeRange(r));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
textfield.onkeypress = function(event) {
|
||||
var char, diff, pos, r;
|
||||
if (word.is_deleted) {
|
||||
textfield.onkeypress = null;
|
||||
return true;
|
||||
}
|
||||
creator_token = true;
|
||||
char = null;
|
||||
if (event.keyCode === 13) {
|
||||
char = '\n';
|
||||
} else if (event.key != null) {
|
||||
if (event.charCode === 32) {
|
||||
char = " ";
|
||||
} else {
|
||||
char = event.key;
|
||||
}
|
||||
} else {
|
||||
char = window.String.fromCharCode(event.keyCode);
|
||||
}
|
||||
if (char.length > 1) {
|
||||
return true;
|
||||
} else if (char.length > 0) {
|
||||
r = createRange();
|
||||
pos = Math.min(r.left, r.right);
|
||||
diff = Math.abs(r.right - r.left);
|
||||
word["delete"](pos, diff);
|
||||
word.insert(pos, char);
|
||||
r.left = pos + char.length;
|
||||
r.right = r.left;
|
||||
writeRange(r);
|
||||
}
|
||||
event.preventDefault();
|
||||
creator_token = false;
|
||||
return false;
|
||||
};
|
||||
textfield.onpaste = function(event) {
|
||||
if (word.is_deleted) {
|
||||
textfield.onpaste = null;
|
||||
return true;
|
||||
}
|
||||
return event.preventDefault();
|
||||
};
|
||||
textfield.oncut = function(event) {
|
||||
if (word.is_deleted) {
|
||||
textfield.oncut = null;
|
||||
return true;
|
||||
}
|
||||
return event.preventDefault();
|
||||
};
|
||||
return textfield.onkeydown = function(event) {
|
||||
var del_length, diff, new_pos, pos, r, val;
|
||||
creator_token = true;
|
||||
if (word.is_deleted) {
|
||||
textfield.onkeydown = null;
|
||||
return true;
|
||||
}
|
||||
r = createRange();
|
||||
pos = Math.min(r.left, r.right, word.val().length);
|
||||
diff = Math.abs(r.left - r.right);
|
||||
if ((event.keyCode != null) && event.keyCode === 8) {
|
||||
if (diff > 0) {
|
||||
word["delete"](pos, diff);
|
||||
r.left = pos;
|
||||
r.right = pos;
|
||||
writeRange(r);
|
||||
} else {
|
||||
if ((event.ctrlKey != null) && event.ctrlKey) {
|
||||
val = word.val();
|
||||
new_pos = pos;
|
||||
del_length = 0;
|
||||
if (pos > 0) {
|
||||
new_pos--;
|
||||
del_length++;
|
||||
}
|
||||
while (new_pos > 0 && val[new_pos] !== " " && val[new_pos] !== '\n') {
|
||||
new_pos--;
|
||||
del_length++;
|
||||
}
|
||||
word["delete"](new_pos, pos - new_pos);
|
||||
r.left = new_pos;
|
||||
r.right = new_pos;
|
||||
writeRange(r);
|
||||
} else {
|
||||
if (pos > 0) {
|
||||
word["delete"](pos - 1, 1);
|
||||
r.left = pos - 1;
|
||||
r.right = pos - 1;
|
||||
writeRange(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
event.preventDefault();
|
||||
creator_token = false;
|
||||
return false;
|
||||
} else if ((event.keyCode != null) && event.keyCode === 46) {
|
||||
if (diff > 0) {
|
||||
word["delete"](pos, diff);
|
||||
r.left = pos;
|
||||
r.right = pos;
|
||||
writeRange(r);
|
||||
} else {
|
||||
word["delete"](pos, 1);
|
||||
r.left = pos;
|
||||
r.right = pos;
|
||||
writeRange(r);
|
||||
}
|
||||
event.preventDefault();
|
||||
creator_token = false;
|
||||
return false;
|
||||
} else {
|
||||
creator_token = false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return YText;
|
||||
|
||||
})();
|
||||
|
||||
if (typeof window !== "undefined" && window !== null) {
|
||||
if (window.Y != null) {
|
||||
window.Y.Text = YText;
|
||||
} else {
|
||||
throw new Error("You must first import Y!");
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined" && module !== null) {
|
||||
module.exports = YText;
|
||||
}
|
@ -1,622 +0,0 @@
|
||||
var YXml, dont_proxy, initialize_proxies, proxies_are_initialized, proxy_token;
|
||||
|
||||
YXml = (function() {
|
||||
function YXml(tag_or_dom, attributes) {
|
||||
var a, a_name, c, c_name, tagname, _classes, _i, _len, _ref;
|
||||
if (attributes == null) {
|
||||
attributes = {};
|
||||
}
|
||||
if (tag_or_dom == null) {
|
||||
|
||||
} else if (tag_or_dom.constructor === String) {
|
||||
tagname = tag_or_dom;
|
||||
this._xml = {};
|
||||
this._xml.children = [];
|
||||
this._xml.tagname = tagname;
|
||||
if (attributes.constructor !== Object) {
|
||||
throw new Error("The attributes must be specified as a Object");
|
||||
}
|
||||
for (a_name in attributes) {
|
||||
a = attributes[a_name];
|
||||
if (a.constructor !== String) {
|
||||
throw new Error("The attributes must be of type String!");
|
||||
}
|
||||
}
|
||||
this._xml.attributes = attributes;
|
||||
this._xml.classes = {};
|
||||
_classes = this._xml.attributes["class"];
|
||||
delete this._xml.attributes["class"];
|
||||
if (_classes != null) {
|
||||
_ref = _classes.split(" ");
|
||||
for (c = _i = 0, _len = _ref.length; _i < _len; c = ++_i) {
|
||||
c_name = _ref[c];
|
||||
if (c.length > 0) {
|
||||
this._xml.classes[c_name] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
void 0;
|
||||
} else if (tag_or_dom instanceof Element) {
|
||||
this._dom = tag_or_dom;
|
||||
this._xml = {};
|
||||
}
|
||||
}
|
||||
|
||||
YXml.prototype._name = "Xml";
|
||||
|
||||
YXml.prototype._getModel = function(Y, ops) {
|
||||
var attribute, c, child, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
|
||||
if (this._model == null) {
|
||||
if (this._dom != null) {
|
||||
this._xml.tagname = this._dom.tagName.toLowerCase();
|
||||
this._xml.attributes = {};
|
||||
this._xml.classes = {};
|
||||
_ref = this._dom.attributes;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
attribute = _ref[_i];
|
||||
if (attribute.name === "class") {
|
||||
_ref1 = attribute.value.split(" ");
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
c = _ref1[_j];
|
||||
this._xml.classes[c] = true;
|
||||
}
|
||||
} else {
|
||||
this._xml.attributes[attribute.name] = attribute.value;
|
||||
}
|
||||
}
|
||||
this._xml.children = [];
|
||||
_ref2 = this._dom.childNodes;
|
||||
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
||||
child = _ref2[_k];
|
||||
if (child.nodeType === child.TEXT_NODE) {
|
||||
this._xml.children.push(child.textContent);
|
||||
} else {
|
||||
this._xml.children.push(new YXml(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
this._model = new ops.MapManager(this).execute();
|
||||
this._model.val("attributes", new Y.Object(this._xml.attributes));
|
||||
this._model.val("classes", new Y.Object(this._xml.classes));
|
||||
this._model.val("tagname", this._xml.tagname);
|
||||
this._model.val("children", new Y.List(this._xml.children));
|
||||
if (this._xml.parent != null) {
|
||||
this._model.val("parent", this._xml.parent);
|
||||
}
|
||||
if (this._dom != null) {
|
||||
this.getDom();
|
||||
}
|
||||
this._setModel(this._model);
|
||||
}
|
||||
return this._model;
|
||||
};
|
||||
|
||||
YXml.prototype._setModel = function(_at__model) {
|
||||
this._model = _at__model;
|
||||
this._model.observe(function(events) {
|
||||
var c, children, event, i, parent, _i, _len, _ref, _results;
|
||||
_results = [];
|
||||
for (_i = 0, _len = events.length; _i < _len; _i++) {
|
||||
event = events[_i];
|
||||
if (event.name === "parent" && event.type !== "add") {
|
||||
parent = event.oldValue;
|
||||
children = (_ref = parent._model.val("children")) != null ? _ref.val() : void 0;
|
||||
if (children != null) {
|
||||
_results.push((function() {
|
||||
var _j, _len1, _results1;
|
||||
_results1 = [];
|
||||
for (i = _j = 0, _len1 = children.length; _j < _len1; i = ++_j) {
|
||||
c = children[i];
|
||||
if (c === this) {
|
||||
parent._model.val("children")["delete"](i);
|
||||
break;
|
||||
} else {
|
||||
_results1.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results1;
|
||||
}).call(this));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
return delete this._xml;
|
||||
};
|
||||
|
||||
YXml.prototype._setParent = function(parent) {
|
||||
if (parent instanceof YXml) {
|
||||
if (this._model != null) {
|
||||
this.remove();
|
||||
return this._model.val("parent", parent);
|
||||
} else {
|
||||
return this._xml.parent = parent;
|
||||
}
|
||||
} else {
|
||||
throw new Error("parent must be of type Y.Xml!");
|
||||
}
|
||||
};
|
||||
|
||||
YXml.prototype.toString = function() {
|
||||
var child, name, value, xml, _i, _len, _ref, _ref1;
|
||||
xml = "<" + this._model.val("tagname");
|
||||
_ref = this.attr();
|
||||
for (name in _ref) {
|
||||
value = _ref[name];
|
||||
xml += " " + name + '="' + value + '"';
|
||||
}
|
||||
xml += ">";
|
||||
_ref1 = this._model.val("children").val();
|
||||
for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
|
||||
child = _ref1[_i];
|
||||
xml += child.toString();
|
||||
}
|
||||
xml += '</' + this._model.val("tagname") + '>';
|
||||
return xml;
|
||||
};
|
||||
|
||||
YXml.prototype.attr = function(name, value) {
|
||||
var attrs, c, classes, cs, _i, _len;
|
||||
if (arguments.length > 1) {
|
||||
if (value.constructor !== String) {
|
||||
throw new Error("The attributes must be of type String!");
|
||||
}
|
||||
if (name === "class") {
|
||||
classes = value.split(" ");
|
||||
cs = {};
|
||||
for (_i = 0, _len = classes.length; _i < _len; _i++) {
|
||||
c = classes[_i];
|
||||
cs[c] = true;
|
||||
}
|
||||
this._model.val("classes", new this._model.custom_types.Object(cs));
|
||||
} else {
|
||||
this._model.val("attributes").val(name, value);
|
||||
}
|
||||
return this;
|
||||
} else if (arguments.length > 0) {
|
||||
if (name === "class") {
|
||||
return Object.keys(this._model.val("classes").val()).join(" ");
|
||||
} else {
|
||||
return this._model.val("attributes").val(name);
|
||||
}
|
||||
} else {
|
||||
attrs = this._model.val("attributes").val();
|
||||
classes = Object.keys(this._model.val("classes").val()).join(" ");
|
||||
if (classes.length > 0) {
|
||||
attrs["class"] = classes;
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
};
|
||||
|
||||
YXml.prototype.addClass = function(names) {
|
||||
var name, _i, _len, _ref;
|
||||
_ref = names.split(" ");
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
name = _ref[_i];
|
||||
this._model.val("classes").val(name, true);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.after = function() {
|
||||
var c, content, contents, parent, position, _i, _j, _len, _len1, _ref;
|
||||
parent = this._model.val("parent");
|
||||
if (parent == null) {
|
||||
throw new Error("This Xml Element must not have siblings! (for it does not have a parent)");
|
||||
}
|
||||
_ref = parent.getChildren();
|
||||
for (position = _i = 0, _len = _ref.length; _i < _len; position = ++_i) {
|
||||
c = _ref[position];
|
||||
if (c === this) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
contents = [];
|
||||
for (_j = 0, _len1 = arguments.length; _j < _len1; _j++) {
|
||||
content = arguments[_j];
|
||||
if (content instanceof YXml) {
|
||||
content._setParent(this._model.val("parent"));
|
||||
} else if (content.constructor !== String) {
|
||||
throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
|
||||
}
|
||||
contents.push(content);
|
||||
}
|
||||
return parent._model.val("children").insertContents(position + 1, contents);
|
||||
};
|
||||
|
||||
YXml.prototype.append = function() {
|
||||
var content, _i, _len;
|
||||
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
|
||||
content = arguments[_i];
|
||||
if (content instanceof YXml) {
|
||||
content._setParent(this);
|
||||
} else if (content.constructor !== String) {
|
||||
throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
|
||||
}
|
||||
this._model.val("children").push(content);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.before = function() {
|
||||
var c, content, contents, parent, position, _i, _j, _len, _len1, _ref;
|
||||
parent = this._model.val("parent");
|
||||
if (parent == null) {
|
||||
throw new Error("This Xml Element must not have siblings! (for it does not have a parent)");
|
||||
}
|
||||
_ref = parent.getChildren();
|
||||
for (position = _i = 0, _len = _ref.length; _i < _len; position = ++_i) {
|
||||
c = _ref[position];
|
||||
if (c === this) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
contents = [];
|
||||
for (_j = 0, _len1 = arguments.length; _j < _len1; _j++) {
|
||||
content = arguments[_j];
|
||||
if (content instanceof YXml) {
|
||||
content._setParent(this._model.val("parent"));
|
||||
} else if (content.constructor !== String) {
|
||||
throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
|
||||
}
|
||||
contents.push(content);
|
||||
}
|
||||
return parent._model.val("children").insertContents(position, contents);
|
||||
};
|
||||
|
||||
YXml.prototype.empty = function() {
|
||||
var child, children, _i, _len, _ref, _results;
|
||||
children = this._model.val("children");
|
||||
_ref = children.val();
|
||||
_results = [];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
child = _ref[_i];
|
||||
if (child.constructor === String) {
|
||||
_results.push(children["delete"](0));
|
||||
} else {
|
||||
_results.push(child.remove());
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
|
||||
YXml.prototype.hasClass = function(className) {
|
||||
if (this._model.val("classes").val(className) != null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
YXml.prototype.prepend = function() {
|
||||
var content, _i, _len;
|
||||
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
|
||||
content = arguments[_i];
|
||||
if (content instanceof YXml) {
|
||||
content._setParent(this);
|
||||
} else if (content.constructor !== String) {
|
||||
throw new Error("Y.Xml.after expects instances of YXml or String as a parameter");
|
||||
}
|
||||
this._model.val("children").insert(0, content);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.remove = function() {
|
||||
var parent;
|
||||
parent = this._model["delete"]("parent");
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.removeAttr = function(attrName) {
|
||||
if (attrName === "class") {
|
||||
this._model.val("classes", new this._model.custom_types.Object());
|
||||
} else {
|
||||
this._model.val("attributes")["delete"](attrName);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.removeClass = function() {
|
||||
var className, _i, _len;
|
||||
if (arguments.length === 0) {
|
||||
this._model.val("classes", new this._model.custom_types.Object());
|
||||
} else {
|
||||
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
|
||||
className = arguments[_i];
|
||||
this._model.val("classes")["delete"](className);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.toggleClass = function() {
|
||||
var className, classes, _i, _len;
|
||||
for (_i = 0, _len = arguments.length; _i < _len; _i++) {
|
||||
className = arguments[_i];
|
||||
classes = this._model.val("classes");
|
||||
if (classes.val(className) != null) {
|
||||
classes["delete"](className);
|
||||
} else {
|
||||
classes.val(className, true);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
YXml.prototype.getParent = function() {
|
||||
return this._model.val("parent");
|
||||
};
|
||||
|
||||
YXml.prototype.getChildren = function() {
|
||||
return this._model.val("children").val();
|
||||
};
|
||||
|
||||
YXml.prototype.getPosition = function() {
|
||||
var c, i, parent, _i, _len, _ref;
|
||||
parent = this._model.val("parent");
|
||||
if (parent != null) {
|
||||
_ref = parent._model.val("children").val();
|
||||
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
||||
c = _ref[i];
|
||||
if (c === this) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw new Error("This is not a child of its parent (should not happen in Y.Xml!)");
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
YXml.prototype.getDom = function() {
|
||||
var attr_name, attr_value, child, dom, i, setClasses, that, _i, _len, _ref, _ref1;
|
||||
if (this._dom == null) {
|
||||
this._dom = document.createElement(this._model.val("tagname"));
|
||||
_ref = this.attr();
|
||||
for (attr_name in _ref) {
|
||||
attr_value = _ref[attr_name];
|
||||
this._dom.setAttribute(attr_name, attr_value);
|
||||
}
|
||||
_ref1 = this.getChildren();
|
||||
for (i = _i = 0, _len = _ref1.length; _i < _len; i = ++_i) {
|
||||
child = _ref1[i];
|
||||
if (child.constructor === String) {
|
||||
dom = document.createTextNode(child);
|
||||
} else {
|
||||
dom = child.getDom();
|
||||
}
|
||||
this._dom.insertBefore(dom);
|
||||
}
|
||||
}
|
||||
that = this;
|
||||
if (this._dom._y_xml == null) {
|
||||
this._dom._y_xml = this;
|
||||
initialize_proxies.call(this);
|
||||
this._model.val("children").observe(function(events) {
|
||||
var children, deleted, event, newNode, rightNode, _j, _len1, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
|
||||
event = events[_j];
|
||||
if (event.type === "insert") {
|
||||
if (event.value.constructor === String) {
|
||||
newNode = document.createTextNode(event.value);
|
||||
} else {
|
||||
newNode = event.value.getDom();
|
||||
event.value._setParent(that);
|
||||
}
|
||||
children = that._dom.childNodes;
|
||||
if (children.length === event.position) {
|
||||
rightNode = null;
|
||||
} else {
|
||||
rightNode = children[event.position];
|
||||
}
|
||||
_results.push(dont_proxy(function() {
|
||||
return that._dom.insertBefore(newNode, rightNode);
|
||||
}));
|
||||
} else if (event.type === "delete") {
|
||||
deleted = event.oldValue.getDom();
|
||||
_results.push(dont_proxy(function() {
|
||||
return that._dom.removeChild(deleted);
|
||||
}));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
this._model.val("attributes").observe(function(events) {
|
||||
var event, newval, _j, _len1, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
|
||||
event = events[_j];
|
||||
if (event.type === "add" || event.type === "update") {
|
||||
newval = event.object.val(event.name);
|
||||
_results.push(dont_proxy(function() {
|
||||
return that._dom.setAttribute(event.name, newval);
|
||||
}));
|
||||
} else if (event.type === "delete") {
|
||||
_results.push(dont_proxy(function() {
|
||||
return that._dom.removeAttribute(event.name);
|
||||
}));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
setClasses = function() {
|
||||
return that._model.val("classes").observe(function(events) {
|
||||
var event, _j, _len1, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
|
||||
event = events[_j];
|
||||
if (event.type === "add" || event.type === "update") {
|
||||
_results.push(dont_proxy(function() {
|
||||
return that._dom.classList.add(event.name);
|
||||
}));
|
||||
} else if (event.type === "delete") {
|
||||
_results.push(dont_proxy(function() {
|
||||
return that._dom.classList.remove(event.name);
|
||||
}));
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
};
|
||||
setClasses();
|
||||
this._model.observe(function(events) {
|
||||
var event, _j, _len1, _results;
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = events.length; _j < _len1; _j++) {
|
||||
event = events[_j];
|
||||
if (event.type === "add" || event.type === "update") {
|
||||
dont_proxy(function() {
|
||||
var classes;
|
||||
classes = that.attr("class");
|
||||
if ((classes == null) || classes === "") {
|
||||
return that._dom.removeAttribute("class");
|
||||
} else {
|
||||
return that._dom.setAttribute("class", that.attr("class"));
|
||||
}
|
||||
});
|
||||
_results.push(setClasses());
|
||||
} else {
|
||||
_results.push(void 0);
|
||||
}
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
}
|
||||
return this._dom;
|
||||
};
|
||||
|
||||
return YXml;
|
||||
|
||||
})();
|
||||
|
||||
proxies_are_initialized = false;
|
||||
|
||||
proxy_token = false;
|
||||
|
||||
dont_proxy = function(f) {
|
||||
var e;
|
||||
proxy_token = true;
|
||||
try {
|
||||
f();
|
||||
} catch (_error) {
|
||||
e = _error;
|
||||
proxy_token = false;
|
||||
throw new Error(e);
|
||||
}
|
||||
return proxy_token = false;
|
||||
};
|
||||
|
||||
initialize_proxies = function() {
|
||||
var f_add, f_remove, insertBefore, removeChild, replaceChild, that, _proxy;
|
||||
_proxy = function(f_name, f, source, y) {
|
||||
var old_f;
|
||||
if (source == null) {
|
||||
source = Element.prototype;
|
||||
}
|
||||
old_f = source[f_name];
|
||||
return source[f_name] = function() {
|
||||
if ((!((y != null) || (this._y_xml != null))) || proxy_token) {
|
||||
return old_f.apply(this, arguments);
|
||||
} else if (this._y_xml != null) {
|
||||
return f.apply(this._y_xml, arguments);
|
||||
} else {
|
||||
return f.apply(y, arguments);
|
||||
}
|
||||
};
|
||||
};
|
||||
that = this;
|
||||
f_add = function(c) {
|
||||
return that.addClass(c);
|
||||
};
|
||||
_proxy("add", f_add, this._dom.classList, this);
|
||||
f_remove = function(c) {
|
||||
return that.removeClass(c);
|
||||
};
|
||||
_proxy("remove", f_remove, this._dom.classList, this);
|
||||
this._dom.__defineSetter__('className', function(val) {
|
||||
return that.attr('class', val);
|
||||
});
|
||||
this._dom.__defineGetter__('className', function() {
|
||||
return that.attr('class');
|
||||
});
|
||||
this._dom.__defineSetter__('textContent', function(val) {
|
||||
that.empty();
|
||||
if (val !== "") {
|
||||
return that.append(val);
|
||||
}
|
||||
});
|
||||
if (proxies_are_initialized) {
|
||||
return;
|
||||
}
|
||||
proxies_are_initialized = true;
|
||||
insertBefore = function(insertedNode_s, adjacentNode) {
|
||||
var child, new_childs, pos;
|
||||
if (adjacentNode != null) {
|
||||
pos = adjacentNode._y_xml.getPosition();
|
||||
} else {
|
||||
pos = this.getChildren().length;
|
||||
}
|
||||
new_childs = [];
|
||||
if (insertedNode_s.nodeType === insertedNode_s.DOCUMENT_FRAGMENT_NODE) {
|
||||
child = insertedNode_s.firstChild;
|
||||
while (child != null) {
|
||||
new_childs.push(child);
|
||||
child = child.nextSibling;
|
||||
}
|
||||
} else {
|
||||
new_childs.push(insertedNode_s);
|
||||
}
|
||||
new_childs = new_childs.map(function(child) {
|
||||
if (child._y_xml != null) {
|
||||
return child._y_xml;
|
||||
} else if (child.nodeType === child.TEXT_NODE) {
|
||||
return child.textContent;
|
||||
} else {
|
||||
return new YXml(child);
|
||||
}
|
||||
});
|
||||
return this._model.val("children").insertContents(pos, new_childs);
|
||||
};
|
||||
_proxy('insertBefore', insertBefore);
|
||||
_proxy('appendChild', insertBefore);
|
||||
_proxy('removeAttribute', function(name) {
|
||||
return this.removeAttr(name);
|
||||
});
|
||||
_proxy('setAttribute', function(name, value) {
|
||||
return this.attr(name, value);
|
||||
});
|
||||
removeChild = function(node) {
|
||||
return node._y_xml.remove();
|
||||
};
|
||||
_proxy('removeChild', removeChild);
|
||||
replaceChild = function(insertedNode, replacedNode) {
|
||||
insertBefore.call(this, insertedNode, replacedNode);
|
||||
return removeChild.call(this, replacedNode);
|
||||
};
|
||||
return _proxy('replaceChild', replaceChild);
|
||||
};
|
||||
|
||||
if (typeof window !== "undefined" && window !== null) {
|
||||
if (window.Y != null) {
|
||||
window.Y.Xml = YXml;
|
||||
} else {
|
||||
throw new Error("You must first import Y!");
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof module !== "undefined" && module !== null) {
|
||||
module.exports = YXml;
|
||||
}
|
@ -42,4 +42,4 @@ if (typeof window !== "undefined" && window !== null) {
|
||||
window.Y = createY;
|
||||
}
|
||||
|
||||
createY.Object = require("./Types/Object");
|
||||
createY.Object = require("./ObjectType");
|
||||
|
16915
build/test/Json_test.js
16915
build/test/Json_test.js
File diff suppressed because one or more lines are too long
16589
build/test/Text_test.js
16589
build/test/Text_test.js
File diff suppressed because one or more lines are too long
26877
build/test/Xml_test.js
26877
build/test/Xml_test.js
File diff suppressed because one or more lines are too long
@ -6,17 +6,16 @@
|
||||
</head>
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<div id="test_dom" test_attribute="the test" class="stuffy" style="color: blue"><p id="replaceme">replace me</p><p id="removeme">remove me</p><p>This is a test object for <b>XmlFramework</b></p><span class="span_element"><p>span</p></span></div>
|
||||
<script src="../../node_modules/mocha/mocha.js" class="awesome"></script>
|
||||
<script>
|
||||
mocha.setup('bdd');
|
||||
mocha.ui('bdd');
|
||||
mocha.reporter('html');
|
||||
</script>
|
||||
<script src="Xml_test.js"></script>
|
||||
<!--script src="Text_test.js"></script>
|
||||
<script src="Json_test.js"></script-->
|
||||
<!--script src="Xml_test_browser.js"></script-->
|
||||
<script src="object-test.js"></script>
|
||||
<script src="xml-test.js"></script>
|
||||
<script src="list-test.js"></script>
|
||||
<script src="text-test.js"></script>
|
||||
<script>
|
||||
//mocha.checkLeaks();
|
||||
//mocha.run();
|
||||
|
22357
build/test/list-test.js
Normal file
22357
build/test/list-test.js
Normal file
File diff suppressed because one or more lines are too long
16925
build/test/object-test.js
Normal file
16925
build/test/object-test.js
Normal file
File diff suppressed because one or more lines are too long
22375
build/test/text-test.js
Normal file
22375
build/test/text-test.js
Normal file
File diff suppressed because one or more lines are too long
32117
build/test/xml-test.js
Normal file
32117
build/test/xml-test.js
Normal file
File diff suppressed because one or more lines are too long
@ -25,7 +25,7 @@ gulp.task 'default', ['build_browser']
|
||||
files =
|
||||
lib : ['./lib/**/*.coffee']
|
||||
browser : ['./lib/y.coffee','./lib/y-object.coffee']
|
||||
test : ['./test/**/*_test.coffee']
|
||||
test : ['./test/**/*test.coffee', '../y-*/test/*test.coffee']
|
||||
#test : ['./test/Json_test.coffee', './test/Text_test.coffee']
|
||||
gulp : ['./gulpfile.coffee']
|
||||
examples : ['./examples/**/*.js']
|
||||
@ -67,6 +67,7 @@ gulp.task 'build_browser', ->
|
||||
debug: true
|
||||
.pipe rename
|
||||
extname: ".js"
|
||||
dirname: "./"
|
||||
.pipe gulp.dest './build/test/'
|
||||
|
||||
gulp.task 'build_node', ->
|
||||
|
@ -369,7 +369,7 @@ module.exports = ()->
|
||||
# (e.g. the following operation order must be invertible :
|
||||
# Insert refers to content, then the content is deleted)
|
||||
# Therefore, we have to do this in the cleanup
|
||||
if @content instanceof ops.Operation and not deleted_earlyer
|
||||
if @content instanceof ops.Operation
|
||||
@content.referenced_by--
|
||||
if @content.referenced_by <= 0 and not @content.is_deleted
|
||||
@content.applyDelete()
|
||||
|
@ -1,94 +0,0 @@
|
||||
|
||||
json_types_uninitialized = require "./JsonTypes"
|
||||
|
||||
module.exports = (HB)->
|
||||
json_types = json_types_uninitialized HB
|
||||
types = json_types.types
|
||||
parser = json_types.parser
|
||||
|
||||
#
|
||||
# Manages XML types
|
||||
# Not supported:
|
||||
# * Attribute nodes
|
||||
# * Real replace of child elements (to much overhead). Currently, the new element is inserted after the 'replaced' element, and then it is deleted.
|
||||
# * Namespaces (*NS)
|
||||
# * Browser specific methods (webkit-* operations)
|
||||
class XmlType extends types.Insert
|
||||
|
||||
constructor: (uid, @tagname, attributes, elements, @xml)->
|
||||
|
||||
|
||||
|
||||
setXmlProxy: ()->
|
||||
|
||||
val: (enforce = false)->
|
||||
if document?
|
||||
if (not @xml?) or enforce
|
||||
@xml = document.createElement @tagname
|
||||
|
||||
attr = @attributes.val()
|
||||
for attr_name, value of attr
|
||||
if value?
|
||||
a = document.createAttribute attr_name
|
||||
a.value = value
|
||||
@xml.setAttributeNode a
|
||||
|
||||
e = @elements.beginning.next_cl
|
||||
while e.type isnt "Delimiter"
|
||||
n = e.content
|
||||
if not e.isDeleted() and e.content? # TODO: how can this happen? Probably because listeners
|
||||
if n.type is "XmlType"
|
||||
@xml.appendChild n.val(enforce)
|
||||
else if n.type is "TextNodeType"
|
||||
text_node = n.val()
|
||||
@xml.appendChild text_node
|
||||
else
|
||||
throw new Error "Internal structure cannot be transformed to dom"
|
||||
e = e.next_cl
|
||||
@setXmlProxy()
|
||||
@xml
|
||||
|
||||
|
||||
execute: ()->
|
||||
super()
|
||||
###
|
||||
if not @validateSavedOperations()
|
||||
return false
|
||||
else
|
||||
|
||||
return true
|
||||
###
|
||||
|
||||
#
|
||||
# Get the parent of this JsonType.
|
||||
# @return {XmlType}
|
||||
#
|
||||
getParent: ()->
|
||||
@parent
|
||||
|
||||
#
|
||||
# @private
|
||||
#
|
||||
# Convert all relevant information of this operation to the json-format.
|
||||
# This result can be send to other clients.
|
||||
#
|
||||
_encode: ()->
|
||||
json =
|
||||
{
|
||||
'type' : @type
|
||||
'attributes' : @attributes.getUid()
|
||||
'elements' : @elements.getUid()
|
||||
'tagname' : @tagname
|
||||
'uid' : @getUid()
|
||||
}
|
||||
json
|
||||
|
||||
parser['XmlType'] = (json)->
|
||||
{
|
||||
'uid' : uid
|
||||
'attributes' : attributes
|
||||
'elements' : elements
|
||||
'tagname' : tagname
|
||||
} = json
|
||||
|
||||
new XmlType uid, tagname, attributes, elements, undefined
|
@ -1,80 +0,0 @@
|
||||
class YList
|
||||
|
||||
#
|
||||
# @private
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
#
|
||||
constructor: (list)->
|
||||
if not list?
|
||||
@_list = []
|
||||
else if list.constructor is Array
|
||||
@_list = list
|
||||
else
|
||||
throw new Error "Y.List expects an Array as a parameter"
|
||||
|
||||
_name: "List"
|
||||
|
||||
_getModel: (types, ops)->
|
||||
if not @_model?
|
||||
@_model = new ops.ListManager(@).execute()
|
||||
@_model.insert 0, @_list
|
||||
delete @_list
|
||||
@_model
|
||||
|
||||
_setModel: (@_model)->
|
||||
delete @_list
|
||||
|
||||
val: ()->
|
||||
@_model.val.apply @_model, arguments
|
||||
|
||||
observe: ()->
|
||||
@_model.observe.apply @_model, arguments
|
||||
@
|
||||
|
||||
unobserve: ()->
|
||||
@_model.unobserve.apply @_model, arguments
|
||||
@
|
||||
|
||||
#
|
||||
# Inserts an Object into the list.
|
||||
#
|
||||
# @return {ListManager Type} This String object.
|
||||
#
|
||||
insert: (position, content)->
|
||||
if typeof position isnt "number"
|
||||
throw new Error "Y.List.insert expects a Number as the first parameter!"
|
||||
@_model.insert position, [content]
|
||||
@
|
||||
|
||||
insertContents: (position, contents)->
|
||||
if typeof position isnt "number"
|
||||
throw new Error "Y.List.insert expects a Number as the first parameter!"
|
||||
@_model.insert position, contents
|
||||
@
|
||||
|
||||
delete: (position, length)->
|
||||
@_model.delete position, length
|
||||
@
|
||||
|
||||
push: (content)->
|
||||
@_model.push content
|
||||
@
|
||||
|
||||
if window?
|
||||
if window.Y?
|
||||
window.Y.List = YList
|
||||
else
|
||||
throw new Error "You must first import Y!"
|
||||
|
||||
if module?
|
||||
module.exports = YList
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,305 +0,0 @@
|
||||
#
|
||||
# Handles a String-like data structures with support for insert/delete at a word-position.
|
||||
#
|
||||
class YText
|
||||
|
||||
#
|
||||
# @private
|
||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
||||
#
|
||||
constructor: (text)->
|
||||
@textfields = []
|
||||
if not text?
|
||||
@_text = ""
|
||||
else if text.constructor is String
|
||||
@_text = text
|
||||
else
|
||||
throw new Error "Y.Text expects a String as a constructor"
|
||||
|
||||
_name: "Text"
|
||||
|
||||
_getModel: (types, ops)->
|
||||
if not @_model?
|
||||
@_model = new ops.ListManager(@).execute()
|
||||
@insert 0, @_text
|
||||
delete @_text
|
||||
@_model
|
||||
|
||||
_setModel: (@_model)->
|
||||
delete @_text
|
||||
|
||||
#
|
||||
# Get the String-representation of this word.
|
||||
# @return {String} The String-representation of this object.
|
||||
#
|
||||
val: ()->
|
||||
@_model.fold "", (left, o)->
|
||||
left + o.val()
|
||||
|
||||
observe: ()->
|
||||
@_model.observe.apply @_model, arguments
|
||||
|
||||
unobserve: ()->
|
||||
@_model.unobserve.apply @_model, arguments
|
||||
|
||||
#
|
||||
# Same as String.val
|
||||
# @see String.val
|
||||
#
|
||||
toString: ()->
|
||||
@val()
|
||||
|
||||
#
|
||||
# Inserts a string into the word.
|
||||
#
|
||||
# @return {ListManager Type} This String object.
|
||||
#
|
||||
insert: (position, content)->
|
||||
if content.constructor isnt String
|
||||
throw new Error "Y.String.insert expects a String as the second parameter!"
|
||||
if typeof position isnt "number"
|
||||
throw new Error "Y.String.insert expects a Number as the first parameter!"
|
||||
if content.length > 0
|
||||
ith = @_model.getOperationByPosition position
|
||||
# the (i-1)th character. e.g. "abc" the 1th character is "a"
|
||||
# the 0th character is the left Delimiter
|
||||
@_model.insertAfter ith, content
|
||||
|
||||
delete: (position, length)->
|
||||
@_model.delete position, length
|
||||
|
||||
#
|
||||
# Bind this String to a textfield or input field.
|
||||
#
|
||||
# @example
|
||||
# var textbox = document.getElementById("textfield");
|
||||
# y.bind(textbox);
|
||||
#
|
||||
bind: (textfield, dom_root)->
|
||||
dom_root ?= window
|
||||
if (not dom_root.getSelection?)
|
||||
dom_root = window
|
||||
|
||||
# don't duplicate!
|
||||
for t in @textfields
|
||||
if t is textfield
|
||||
return
|
||||
creator_token = false;
|
||||
|
||||
word = @
|
||||
textfield.value = @val()
|
||||
@textfields.push textfield
|
||||
|
||||
if textfield.selectionStart? and textfield.setSelectionRange?
|
||||
createRange = (fix)->
|
||||
left = textfield.selectionStart
|
||||
right = textfield.selectionEnd
|
||||
if fix?
|
||||
left = fix left
|
||||
right = fix right
|
||||
{
|
||||
left: left
|
||||
right: right
|
||||
}
|
||||
|
||||
writeRange = (range)->
|
||||
writeContent word.val()
|
||||
textfield.setSelectionRange range.left, range.right
|
||||
|
||||
writeContent = (content)->
|
||||
textfield.value = content
|
||||
else
|
||||
createRange = (fix)->
|
||||
range = {}
|
||||
s = dom_root.getSelection()
|
||||
clength = textfield.textContent.length
|
||||
range.left = Math.min s.anchorOffset, clength
|
||||
range.right = Math.min s.focusOffset, clength
|
||||
if fix?
|
||||
range.left = fix range.left
|
||||
range.right = fix range.right
|
||||
|
||||
edited_element = s.focusNode
|
||||
if edited_element is textfield or edited_element is textfield.childNodes[0]
|
||||
range.isReal = true
|
||||
else
|
||||
range.isReal = false
|
||||
range
|
||||
|
||||
writeRange = (range)->
|
||||
writeContent word.val()
|
||||
textnode = textfield.childNodes[0]
|
||||
if range.isReal and textnode?
|
||||
if range.left < 0
|
||||
range.left = 0
|
||||
range.right = Math.max range.left, range.right
|
||||
if range.right > textnode.length
|
||||
range.right = textnode.length
|
||||
range.left = Math.min range.left, range.right
|
||||
r = document.createRange()
|
||||
r.setStart(textnode, range.left)
|
||||
r.setEnd(textnode, range.right)
|
||||
s = window.getSelection()
|
||||
s.removeAllRanges()
|
||||
s.addRange(r)
|
||||
writeContent = (content)->
|
||||
content_array = content.replace(new RegExp("\n",'g')," ").split(" ")
|
||||
textfield.innerText = ""
|
||||
for c, i in content_array
|
||||
textfield.innerText += c
|
||||
if i isnt content_array.length-1
|
||||
textfield.innerHTML += ' '
|
||||
|
||||
writeContent this.val()
|
||||
|
||||
@observe (events)->
|
||||
for event in events
|
||||
if not creator_token
|
||||
if event.type is "insert"
|
||||
o_pos = event.position
|
||||
fix = (cursor)->
|
||||
if cursor <= o_pos
|
||||
cursor
|
||||
else
|
||||
cursor += 1
|
||||
cursor
|
||||
r = createRange fix
|
||||
writeRange r
|
||||
|
||||
else if event.type is "delete"
|
||||
o_pos = event.position
|
||||
fix = (cursor)->
|
||||
if cursor < o_pos
|
||||
cursor
|
||||
else
|
||||
cursor -= 1
|
||||
cursor
|
||||
r = createRange fix
|
||||
writeRange r
|
||||
|
||||
# consume all text-insert changes.
|
||||
textfield.onkeypress = (event)->
|
||||
if word.is_deleted
|
||||
# if word is deleted, do not do anything ever again
|
||||
textfield.onkeypress = null
|
||||
return true
|
||||
creator_token = true
|
||||
char = null
|
||||
if event.keyCode is 13
|
||||
char = '\n'
|
||||
else if event.key?
|
||||
if event.charCode is 32
|
||||
char = " "
|
||||
else
|
||||
char = event.key
|
||||
else
|
||||
char = window.String.fromCharCode event.keyCode
|
||||
if char.length > 1
|
||||
return true
|
||||
else if char.length > 0
|
||||
r = createRange()
|
||||
pos = Math.min r.left, r.right
|
||||
diff = Math.abs(r.right - r.left)
|
||||
word.delete pos, diff
|
||||
word.insert pos, char
|
||||
r.left = pos + char.length
|
||||
r.right = r.left
|
||||
writeRange r
|
||||
|
||||
event.preventDefault()
|
||||
creator_token = false
|
||||
false
|
||||
|
||||
textfield.onpaste = (event)->
|
||||
if word.is_deleted
|
||||
# if word is deleted, do not do anything ever again
|
||||
textfield.onpaste = null
|
||||
return true
|
||||
event.preventDefault()
|
||||
textfield.oncut = (event)->
|
||||
if word.is_deleted
|
||||
# if word is deleted, do not do anything ever again
|
||||
textfield.oncut = null
|
||||
return true
|
||||
event.preventDefault()
|
||||
|
||||
#
|
||||
# consume deletes. Note that
|
||||
# chrome: won't consume deletions on keypress event.
|
||||
# keyCode is deprecated. BUT: I don't see another way.
|
||||
# since event.key is not implemented in the current version of chrome.
|
||||
# Every browser supports keyCode. Let's stick with it for now..
|
||||
#
|
||||
textfield.onkeydown = (event)->
|
||||
creator_token = true
|
||||
if word.is_deleted
|
||||
# if word is deleted, do not do anything ever again
|
||||
textfield.onkeydown = null
|
||||
return true
|
||||
r = createRange()
|
||||
pos = Math.min(r.left, r.right, word.val().length)
|
||||
diff = Math.abs(r.left - r.right)
|
||||
if event.keyCode? and event.keyCode is 8 # Backspace
|
||||
if diff > 0
|
||||
word.delete pos, diff
|
||||
r.left = pos
|
||||
r.right = pos
|
||||
writeRange r
|
||||
else
|
||||
if event.ctrlKey? and event.ctrlKey
|
||||
val = word.val()
|
||||
new_pos = pos
|
||||
del_length = 0
|
||||
if pos > 0
|
||||
new_pos--
|
||||
del_length++
|
||||
while new_pos > 0 and val[new_pos] isnt " " and val[new_pos] isnt '\n'
|
||||
new_pos--
|
||||
del_length++
|
||||
word.delete new_pos, (pos-new_pos)
|
||||
r.left = new_pos
|
||||
r.right = new_pos
|
||||
writeRange r
|
||||
else
|
||||
if pos > 0
|
||||
word.delete (pos-1), 1
|
||||
r.left = pos-1
|
||||
r.right = pos-1
|
||||
writeRange r
|
||||
event.preventDefault()
|
||||
creator_token = false
|
||||
return false
|
||||
else if event.keyCode? and event.keyCode is 46 # Delete
|
||||
if diff > 0
|
||||
word.delete pos, diff
|
||||
r.left = pos
|
||||
r.right = pos
|
||||
writeRange r
|
||||
else
|
||||
word.delete pos, 1
|
||||
r.left = pos
|
||||
r.right = pos
|
||||
writeRange r
|
||||
event.preventDefault()
|
||||
creator_token = false
|
||||
return false
|
||||
else
|
||||
creator_token = false
|
||||
true
|
||||
|
||||
|
||||
if window?
|
||||
if window.Y?
|
||||
window.Y.Text = YText
|
||||
else
|
||||
throw new Error "You must first import Y!"
|
||||
|
||||
if module?
|
||||
module.exports = YText
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,492 +0,0 @@
|
||||
class YXml
|
||||
|
||||
constructor: (tag_or_dom, attributes = {})->
|
||||
if not tag_or_dom?
|
||||
# nop
|
||||
else if tag_or_dom.constructor is String
|
||||
tagname = tag_or_dom
|
||||
@_xml = {}
|
||||
@_xml.children = []
|
||||
#TODO: How to force the user to specify parameters?
|
||||
#if not tagname?
|
||||
# throw new Error "You must specify a tagname"
|
||||
@_xml.tagname = tagname
|
||||
if attributes.constructor isnt Object
|
||||
throw new Error "The attributes must be specified as a Object"
|
||||
for a_name, a of attributes
|
||||
if a.constructor isnt String
|
||||
throw new Error "The attributes must be of type String!"
|
||||
@_xml.attributes = attributes
|
||||
@_xml.classes = {}
|
||||
_classes = @_xml.attributes.class
|
||||
delete @_xml.attributes.class
|
||||
if _classes?
|
||||
for c_name, c in _classes.split(" ")
|
||||
if c.length > 0
|
||||
@_xml.classes[c_name] = c
|
||||
undefined
|
||||
else if tag_or_dom instanceof Element
|
||||
@_dom = tag_or_dom
|
||||
@_xml = {}
|
||||
|
||||
|
||||
|
||||
_name: "Xml"
|
||||
|
||||
_getModel: (Y, ops)->
|
||||
if not @_model?
|
||||
if @_dom?
|
||||
@_xml.tagname = @_dom.tagName.toLowerCase()
|
||||
@_xml.attributes = {}
|
||||
@_xml.classes = {}
|
||||
for attribute in @_dom.attributes
|
||||
if attribute.name is "class"
|
||||
for c in attribute.value.split(" ")
|
||||
@_xml.classes[c] = true
|
||||
else
|
||||
@_xml.attributes[attribute.name] = attribute.value
|
||||
@_xml.children = []
|
||||
for child in @_dom.childNodes
|
||||
if child.nodeType is child.TEXT_NODE
|
||||
@_xml.children.push child.textContent
|
||||
else
|
||||
@_xml.children.push(new YXml(child))
|
||||
@_model = new ops.MapManager(@).execute()
|
||||
@_model.val("attributes", new Y.Object(@_xml.attributes))
|
||||
@_model.val("classes", new Y.Object(@_xml.classes))
|
||||
@_model.val("tagname", @_xml.tagname)
|
||||
@_model.val("children", new Y.List(@_xml.children))
|
||||
if @_xml.parent?
|
||||
@_model.val("parent", @_xml.parent)
|
||||
|
||||
if @_dom?
|
||||
@getDom() # two way bind dom to this xml type
|
||||
|
||||
@_setModel @_model
|
||||
|
||||
@_model
|
||||
|
||||
_setModel: (@_model)->
|
||||
@_model.observe (events)->
|
||||
for event in events
|
||||
if event.name is "parent" and event.type isnt "add"
|
||||
parent = event.oldValue
|
||||
children = parent._model.val("children")?.val()
|
||||
if children?
|
||||
for c,i in children
|
||||
if c is @
|
||||
parent._model.val("children").delete i
|
||||
break
|
||||
delete @_xml
|
||||
|
||||
_setParent: (parent)->
|
||||
if parent instanceof YXml
|
||||
if @_model?
|
||||
@remove()
|
||||
@_model.val("parent", parent)
|
||||
else
|
||||
@_xml.parent = parent
|
||||
else
|
||||
throw new Error "parent must be of type Y.Xml!"
|
||||
|
||||
toString: ()->
|
||||
xml = "<"+@_model.val("tagname")
|
||||
for name, value of @attr()
|
||||
xml += " "+name+'="'+value+'"'
|
||||
xml += ">"
|
||||
for child in @_model.val("children").val()
|
||||
xml += child.toString()
|
||||
xml += '</'+@_model.val("tagname")+'>'
|
||||
xml
|
||||
|
||||
#
|
||||
# Get/set the attribute(s) of this element.
|
||||
# .attr()
|
||||
# .attr(name)
|
||||
# .attr(name, value)
|
||||
#
|
||||
attr: (name, value)->
|
||||
if arguments.length > 1
|
||||
if value.constructor isnt String
|
||||
throw new Error "The attributes must be of type String!"
|
||||
if name is "class"
|
||||
classes = value.split(" ")
|
||||
cs = {}
|
||||
for c in classes
|
||||
cs[c] = true
|
||||
|
||||
@_model.val("classes", new @_model.custom_types.Object(cs))
|
||||
else
|
||||
@_model.val("attributes").val(name, value)
|
||||
@
|
||||
else if arguments.length > 0
|
||||
if name is "class"
|
||||
Object.keys(@_model.val("classes").val()).join(" ")
|
||||
else
|
||||
@_model.val("attributes").val(name)
|
||||
else
|
||||
attrs = @_model.val("attributes").val()
|
||||
classes = Object.keys(@_model.val("classes").val()).join(" ")
|
||||
if classes.length > 0
|
||||
attrs["class"] = classes
|
||||
attrs
|
||||
|
||||
#
|
||||
# Adds the specified class(es) to this element
|
||||
#
|
||||
addClass: (names)->
|
||||
for name in names.split(" ")
|
||||
@_model.val("classes").val(name, true)
|
||||
@
|
||||
|
||||
#
|
||||
# Insert content, specified by the parameter, after this element
|
||||
# .after(content [, content])
|
||||
#
|
||||
after: ()->
|
||||
parent = @_model.val("parent")
|
||||
if not parent?
|
||||
throw new Error "This Xml Element must not have siblings! (for it does not have a parent)"
|
||||
|
||||
# find the position of this element
|
||||
for c,position in parent.getChildren()
|
||||
if c is @
|
||||
break
|
||||
|
||||
contents = []
|
||||
for content in arguments
|
||||
if content instanceof YXml
|
||||
content._setParent(@_model.val("parent"))
|
||||
else if content.constructor isnt String
|
||||
throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
|
||||
contents.push content
|
||||
|
||||
parent._model.val("children").insertContents(position+1, contents)
|
||||
|
||||
#
|
||||
# Insert content, specified by the parameter, to the end of this element
|
||||
# .append(content [, content])
|
||||
#
|
||||
append: ()->
|
||||
for content in arguments
|
||||
if content instanceof YXml
|
||||
content._setParent(@)
|
||||
else if content.constructor isnt String
|
||||
throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
|
||||
@_model.val("children").push(content)
|
||||
@
|
||||
|
||||
#
|
||||
# Insert content, specified by the parameter, after this element
|
||||
# .after(content [, content])
|
||||
#
|
||||
before: ()->
|
||||
parent = @_model.val("parent")
|
||||
if not parent?
|
||||
throw new Error "This Xml Element must not have siblings! (for it does not have a parent)"
|
||||
|
||||
# find the position of this element
|
||||
for c,position in parent.getChildren()
|
||||
if c is @
|
||||
break
|
||||
|
||||
contents = []
|
||||
for content in arguments
|
||||
if content instanceof YXml
|
||||
content._setParent(@_model.val("parent"))
|
||||
else if content.constructor isnt String
|
||||
throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
|
||||
contents.push content
|
||||
|
||||
parent._model.val("children").insertContents(position, contents)
|
||||
|
||||
#
|
||||
# Remove all child nodes of the set of matched elements from the DOM.
|
||||
# .empty()
|
||||
#
|
||||
empty: ()->
|
||||
# TODO: do it like this : @_model.val("children", new Y.List())
|
||||
children = @_model.val("children")
|
||||
for child in children.val()
|
||||
if child.constructor is String
|
||||
children.delete(0)
|
||||
else
|
||||
child.remove()
|
||||
|
||||
#
|
||||
# Determine whether any of the matched elements are assigned the given class.
|
||||
# .hasClass(className)
|
||||
#
|
||||
hasClass: (className)->
|
||||
if @_model.val("classes").val(className)?
|
||||
true
|
||||
else
|
||||
false
|
||||
|
||||
#
|
||||
# Insert content, specified by the parameter, to the beginning of this element.
|
||||
# .prepend(content [, content])
|
||||
#
|
||||
prepend: ()->
|
||||
for content in arguments
|
||||
if content instanceof YXml
|
||||
content._setParent(@)
|
||||
else if content.constructor isnt String
|
||||
throw new Error "Y.Xml.after expects instances of YXml or String as a parameter"
|
||||
@_model.val("children").insert(0, content)
|
||||
@
|
||||
|
||||
#
|
||||
# Remove this element from the DOM
|
||||
# .remove()
|
||||
#
|
||||
remove: ()->
|
||||
parent = @_model.delete("parent")
|
||||
@
|
||||
|
||||
#
|
||||
# Remove an attribute from this element
|
||||
# .removeAttr(attrName)
|
||||
#
|
||||
removeAttr: (attrName)->
|
||||
if attrName is "class"
|
||||
@_model.val("classes", new @_model.custom_types.Object())
|
||||
else
|
||||
@_model.val("attributes").delete(attrName)
|
||||
@
|
||||
|
||||
#
|
||||
# Remove a single class, multiple classes, or all classes from this element
|
||||
# .removeClass([className])
|
||||
#
|
||||
removeClass: ()->
|
||||
if arguments.length is 0
|
||||
@_model.val("classes", new @_model.custom_types.Object())
|
||||
else
|
||||
for className in arguments
|
||||
@_model.val("classes").delete(className)
|
||||
@
|
||||
|
||||
#
|
||||
# Add or remove one or more classes from this element,
|
||||
# depending on either the class’s presence or the value of the state argument.
|
||||
# .toggleClass([className])
|
||||
#
|
||||
toggleClass: ()->
|
||||
for className in arguments
|
||||
classes = @_model.val("classes")
|
||||
if classes.val(className)?
|
||||
classes.delete(className)
|
||||
else
|
||||
classes.val(className, true)
|
||||
@
|
||||
|
||||
#
|
||||
# Get the parent of this Element
|
||||
# @Note: Every XML element can only have one parent
|
||||
# .getParent()
|
||||
#
|
||||
getParent: ()->
|
||||
@_model.val("parent")
|
||||
|
||||
#
|
||||
# Get all the children of this XML Element as an Array
|
||||
# @Note: The children are either of type Y.Xml or String
|
||||
# .getChildren()
|
||||
#
|
||||
getChildren: ()->
|
||||
@_model.val("children").val()
|
||||
|
||||
getPosition: ()->
|
||||
parent = @_model.val("parent")
|
||||
if parent?
|
||||
for c,i in parent._model.val("children").val()
|
||||
if c is @
|
||||
return i
|
||||
throw new Error "This is not a child of its parent (should not happen in Y.Xml!)"
|
||||
else
|
||||
null
|
||||
|
||||
|
||||
getDom: ()->
|
||||
if not @_dom?
|
||||
@_dom = document.createElement(@_model.val("tagname"))
|
||||
|
||||
# set the attributes _and_ the classes (@see .attr())
|
||||
for attr_name, attr_value of @attr()
|
||||
@_dom.setAttribute attr_name, attr_value
|
||||
for child,i in @getChildren()
|
||||
if child.constructor is String
|
||||
dom = document.createTextNode child
|
||||
else
|
||||
dom = child.getDom()
|
||||
@_dom.insertBefore dom
|
||||
|
||||
that = @
|
||||
|
||||
if (not @_dom._y_xml?)
|
||||
@_dom._y_xml = @
|
||||
initialize_proxies.call @
|
||||
|
||||
@_model.val("children").observe (events)->
|
||||
for event in events
|
||||
if event.type is "insert"
|
||||
if event.value.constructor is String
|
||||
newNode = document.createTextNode(event.value)
|
||||
else
|
||||
newNode = event.value.getDom()
|
||||
event.value._setParent that
|
||||
children = that._dom.childNodes
|
||||
if children.length is event.position
|
||||
rightNode = null
|
||||
else
|
||||
rightNode = children[event.position]
|
||||
|
||||
dont_proxy ()->
|
||||
that._dom.insertBefore newNode, rightNode
|
||||
else if event.type is "delete"
|
||||
deleted = event.oldValue.getDom()
|
||||
dont_proxy ()->
|
||||
that._dom.removeChild deleted
|
||||
@_model.val("attributes").observe (events)->
|
||||
for event in events
|
||||
if event.type is "add" or event.type is "update"
|
||||
newval = event.object.val(event.name)
|
||||
dont_proxy ()->
|
||||
that._dom.setAttribute event.name, newval
|
||||
else if event.type is "delete"
|
||||
dont_proxy ()->
|
||||
that._dom.removeAttribute event.name
|
||||
setClasses = ()->
|
||||
that._model.val("classes").observe (events)->
|
||||
for event in events
|
||||
if event.type is "add" or event.type is "update"
|
||||
dont_proxy ()->
|
||||
that._dom.classList.add event.name # classes are stored as the keys
|
||||
else if event.type is "delete"
|
||||
dont_proxy ()->
|
||||
that._dom.classList.remove event.name
|
||||
setClasses()
|
||||
@_model.observe (events)->
|
||||
for event in events
|
||||
if event.type is "add" or event.type is "update"
|
||||
dont_proxy ()->
|
||||
classes = that.attr("class")
|
||||
if (not classes?) or classes is ""
|
||||
that._dom.removeAttribute "class"
|
||||
else
|
||||
that._dom.setAttribute "class", that.attr("class")
|
||||
setClasses()
|
||||
|
||||
@_dom
|
||||
|
||||
proxies_are_initialized = false
|
||||
# some dom implementations may call another dom.method that simulates the behavior of another.
|
||||
# For example xml.insertChild(dom) , wich inserts an element at the end, and xml.insertAfter(dom,null) wich does the same
|
||||
# But Y's proxy may be called only once!
|
||||
proxy_token = false
|
||||
dont_proxy = (f)->
|
||||
proxy_token = true
|
||||
try
|
||||
f()
|
||||
catch e
|
||||
proxy_token = false
|
||||
throw new Error e
|
||||
proxy_token = false
|
||||
|
||||
initialize_proxies = ()->
|
||||
|
||||
_proxy = (f_name, f, source = Element.prototype, y)->
|
||||
old_f = source[f_name]
|
||||
source[f_name] = ()->
|
||||
if (not (y? or @_y_xml?)) or proxy_token
|
||||
old_f.apply this, arguments
|
||||
else if @_y_xml?
|
||||
f.apply @_y_xml, arguments
|
||||
else
|
||||
f.apply y, arguments
|
||||
|
||||
that = this
|
||||
f_add = (c)->
|
||||
that.addClass c
|
||||
_proxy "add", f_add, @_dom.classList, @
|
||||
|
||||
f_remove = (c)->
|
||||
that.removeClass c
|
||||
|
||||
_proxy "remove", f_remove, @_dom.classList, @
|
||||
|
||||
@_dom.__defineSetter__ 'className', (val)->
|
||||
that.attr('class', val)
|
||||
@_dom.__defineGetter__ 'className', ()->
|
||||
that.attr('class')
|
||||
@_dom.__defineSetter__ 'textContent', (val)->
|
||||
# remove all nodes
|
||||
that.empty()
|
||||
|
||||
# insert word content
|
||||
if val isnt ""
|
||||
that.append val
|
||||
|
||||
|
||||
if proxies_are_initialized
|
||||
return
|
||||
proxies_are_initialized = true
|
||||
|
||||
# the following methods are initialized on prototypes and therefore they need to be written only once!
|
||||
|
||||
insertBefore = (insertedNode_s, adjacentNode)->
|
||||
if adjacentNode?
|
||||
pos = adjacentNode._y_xml.getPosition()
|
||||
else
|
||||
pos = @getChildren().length
|
||||
|
||||
new_childs = []
|
||||
if insertedNode_s.nodeType is insertedNode_s.DOCUMENT_FRAGMENT_NODE
|
||||
child = insertedNode_s.firstChild
|
||||
while child?
|
||||
new_childs.push child
|
||||
child = child.nextSibling
|
||||
else
|
||||
new_childs.push insertedNode_s
|
||||
new_childs = new_childs.map (child)->
|
||||
if child._y_xml?
|
||||
child._y_xml
|
||||
else if child.nodeType == child.TEXT_NODE
|
||||
child.textContent
|
||||
else
|
||||
new YXml(child)
|
||||
@_model.val("children").insertContents pos, new_childs
|
||||
|
||||
_proxy 'insertBefore', insertBefore
|
||||
_proxy 'appendChild', insertBefore
|
||||
_proxy 'removeAttribute', (name)->
|
||||
@removeAttr name
|
||||
_proxy 'setAttribute', (name, value)->
|
||||
@attr name, value
|
||||
|
||||
removeChild = (node)->
|
||||
node._y_xml.remove()
|
||||
_proxy 'removeChild', removeChild
|
||||
replaceChild = (insertedNode, replacedNode)-> # TODO: handle replace with replace behavior...
|
||||
insertBefore.call this, insertedNode, replacedNode
|
||||
removeChild.call this, replacedNode
|
||||
_proxy 'replaceChild', replaceChild
|
||||
|
||||
if window?
|
||||
if window.Y?
|
||||
window.Y.Xml = YXml
|
||||
else
|
||||
throw new Error "You must first import Y!"
|
||||
|
||||
if module?
|
||||
module.exports = YXml
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -36,4 +36,4 @@ module.exports = createY
|
||||
if window?
|
||||
window.Y = createY
|
||||
|
||||
createY.Object = require "./Types/Object"
|
||||
createY.Object = require "./ObjectType"
|
||||
|
@ -13,7 +13,6 @@
|
||||
"keywords": [
|
||||
"OT",
|
||||
"collaboration",
|
||||
"Yata",
|
||||
"synchronization",
|
||||
"ShareJS",
|
||||
"Coweb",
|
||||
|
@ -7,7 +7,7 @@ _ = require("underscore")
|
||||
chai.use(sinonChai)
|
||||
|
||||
Connector = require "../../y-test/lib/y-test.coffee"
|
||||
Y = null
|
||||
Y = null # need global reference!
|
||||
|
||||
module.exports = class Test
|
||||
constructor: (@name_suffix = "", Yjs)->
|
||||
@ -20,7 +20,7 @@ module.exports = class Test
|
||||
@time = 0 # denotes to the time when run was started
|
||||
@ops = 0 # number of operations (used with @time)
|
||||
@time_now = 0 # current time
|
||||
@max_depth = 4
|
||||
@max_depth = 3
|
||||
|
||||
@debug = false
|
||||
|
||||
@ -79,22 +79,7 @@ module.exports = class Test
|
||||
|
||||
getGeneratingFunctions: (user_num)=>
|
||||
types = @users[user_num]._model.operations
|
||||
[
|
||||
f : (y)=> # INSERT TEXT
|
||||
y
|
||||
pos = _.random 0, (y.val().length-1)
|
||||
y.insert pos, @getRandomText()
|
||||
null
|
||||
types: [Y.Text]
|
||||
,
|
||||
f : (y)-> # DELETE TEXT
|
||||
if y.val().length > 0
|
||||
pos = _.random 0, (y.val().length-1) # TODO: put here also arbitrary number (test behaviour in error cases)
|
||||
length = _.random 0, (y.val().length - pos)
|
||||
ops1 = y.delete pos, length
|
||||
undefined
|
||||
types : [Y.Text]
|
||||
]
|
||||
[]
|
||||
getRandomRoot: (user_num)->
|
||||
throw new Error "implement me!"
|
||||
|
||||
@ -103,11 +88,14 @@ module.exports = class Test
|
||||
true
|
||||
else if o1._name? and o1._name isnt o2._name
|
||||
throw new Error "different types"
|
||||
else if o1._name is "Object" or o1.type is "MapManager"
|
||||
else if o1._model?
|
||||
@compare o1._model, o2._model, depth
|
||||
else if o1.type is "MapManager"
|
||||
for name, val of o1.val()
|
||||
@compare(val, o2.val(name), depth-1)
|
||||
else if o1._name?
|
||||
@compare(o1.val(), o2.val(), depth-1)
|
||||
else if o1.type is "ListManager"
|
||||
for val,i in o1.val()
|
||||
@compare(val, o2.val(i), depth-1)
|
||||
else if o1.constructor is Array and o2.constructor is Array
|
||||
if o1.length isnt o2.length
|
||||
throw new Error "The Arrays do not have the same size!"
|
||||
|
@ -1,171 +0,0 @@
|
||||
chai = require('chai')
|
||||
expect = chai.expect
|
||||
should = chai.should()
|
||||
sinon = require('sinon')
|
||||
sinonChai = require('sinon-chai')
|
||||
_ = require("underscore")
|
||||
|
||||
chai.use(sinonChai)
|
||||
|
||||
Y = require "../lib/y"
|
||||
Y.Text = require "../lib/Types/Text"
|
||||
|
||||
Connector = require "../../y-test/lib/y-test.coffee"
|
||||
|
||||
Test = require "./TestSuite"
|
||||
class TextTest extends Test
|
||||
|
||||
constructor: (suffix)->
|
||||
super suffix, Y
|
||||
|
||||
type: "TextTest"
|
||||
|
||||
makeNewUser: (userId)->
|
||||
conn = new Connector userId
|
||||
new Y conn
|
||||
|
||||
initUsers: (u)->
|
||||
u.val("TextTest",new Y.Text())
|
||||
|
||||
getRandomRoot: (user_num)->
|
||||
@users[user_num].val("TextTest")
|
||||
|
||||
getContent: (user_num)->
|
||||
@users[user_num].val("TextTest").val()
|
||||
|
||||
describe "TextFramework", ->
|
||||
@timeout 500000
|
||||
|
||||
beforeEach (done)->
|
||||
@yTest = new TextTest()
|
||||
done()
|
||||
|
||||
it "simple multi-char insert", ->
|
||||
u = @yTest.users[0].val("TextTest")
|
||||
u.insert 0, "abc"
|
||||
u = @yTest.users[1].val("TextTest")
|
||||
u.insert 0, "xyz"
|
||||
@yTest.compareAll()
|
||||
u.delete 0, 1
|
||||
@yTest.compareAll()
|
||||
expect(u.val()).to.equal("bcxyz")
|
||||
|
||||
it "Observers work on shared Text (insert type observers, local and foreign)", ->
|
||||
u = @yTest.users[0].val("TextTest",new Y.Text("my awesome Text")).val("TextTest")
|
||||
@yTest.flushAll()
|
||||
last_task = null
|
||||
observer1 = (changes)->
|
||||
expect(changes.length).to.equal(1)
|
||||
change = changes[0]
|
||||
expect(change.type).to.equal("insert")
|
||||
expect(change.object).to.equal(u)
|
||||
expect(change.value).to.equal("a")
|
||||
expect(change.position).to.equal(1)
|
||||
expect(change.changedBy).to.equal('0')
|
||||
last_task = "observer1"
|
||||
u.observe observer1
|
||||
u.insert 1, "a"
|
||||
expect(last_task).to.equal("observer1")
|
||||
u.unobserve observer1
|
||||
|
||||
observer2 = (changes)->
|
||||
expect(changes.length).to.equal(1)
|
||||
change = changes[0]
|
||||
expect(change.type).to.equal("insert")
|
||||
expect(change.object).to.equal(u)
|
||||
expect(change.value).to.equal("x")
|
||||
expect(change.position).to.equal(0)
|
||||
expect(change.changedBy).to.equal('1')
|
||||
last_task = "observer2"
|
||||
u.observe observer2
|
||||
v = @yTest.users[1].val("TextTest")
|
||||
v.insert 0, "x"
|
||||
@yTest.flushAll()
|
||||
expect(last_task).to.equal("observer2")
|
||||
u.unobserve observer2
|
||||
|
||||
it "Observers work on shared Text (delete type observers, local and foreign)", ->
|
||||
u = @yTest.users[0].val("TextTest",new Y.Text("my awesome Text")).val("TextTest")
|
||||
@yTest.flushAll()
|
||||
last_task = null
|
||||
observer1 = (changes)->
|
||||
expect(changes.length).to.equal(1)
|
||||
change = changes[0]
|
||||
expect(change.type).to.equal("delete")
|
||||
expect(change.object).to.equal(u)
|
||||
expect(change.position).to.equal(1)
|
||||
expect(change.length).to.equal(1)
|
||||
expect(change.changedBy).to.equal('0')
|
||||
last_task = "observer1"
|
||||
u.observe observer1
|
||||
u.delete 1, 1
|
||||
expect(last_task).to.equal("observer1")
|
||||
u.unobserve observer1
|
||||
|
||||
observer2 = (changes)->
|
||||
expect(changes.length).to.equal(1)
|
||||
change = changes[0]
|
||||
expect(change.type).to.equal("delete")
|
||||
expect(change.object).to.equal(u)
|
||||
expect(change.position).to.equal(0)
|
||||
expect(change.length).to.equal(1)
|
||||
expect(change.changedBy).to.equal('1')
|
||||
last_task = "observer2"
|
||||
u.observe observer2
|
||||
v = @yTest.users[1].val("TextTest")
|
||||
v.delete 0, 1
|
||||
@yTest.flushAll()
|
||||
expect(last_task).to.equal("observer2")
|
||||
u.unobserve observer2
|
||||
|
||||
it "can handle many engines, many operations, concurrently (random)", ->
|
||||
console.log("testiy deleted this TODO:dtrn")
|
||||
@yTest.run()
|
||||
|
||||
it "handles double-late-join", ->
|
||||
test = new TextTest("double")
|
||||
test.run()
|
||||
@yTest.run()
|
||||
u1 = test.users[0]
|
||||
u2 = @yTest.users[1]
|
||||
ops1 = u1._model.HB._encode()
|
||||
ops2 = u2._model.HB._encode()
|
||||
u1._model.engine.applyOp ops2, true
|
||||
u2._model.engine.applyOp ops1, true
|
||||
compare = (o1, o2)->
|
||||
if o1._name? and o1._name isnt o2._name
|
||||
throw new Error "different types"
|
||||
else if o1._name is "Object"
|
||||
for name, val of o1.val()
|
||||
compare(val, o2.val(name))
|
||||
else if o1._name?
|
||||
compare(o1.val(), o2.val())
|
||||
else if o1 isnt o2
|
||||
throw new Error "different values"
|
||||
compare u1, u2
|
||||
expect(test.getContent(0)).to.deep.equal(@yTest.getContent(1))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,479 +0,0 @@
|
||||
chai = require('chai')
|
||||
expect = chai.expect
|
||||
should = chai.should()
|
||||
sinon = require('sinon')
|
||||
sinonChai = require('sinon-chai')
|
||||
_ = require("underscore")
|
||||
$ = require('jquery')
|
||||
|
||||
chai.use(sinonChai)
|
||||
|
||||
Y = require "../lib/y.coffee"
|
||||
Y.Test = require "../../y-test/lib/y-test.coffee"
|
||||
|
||||
Y.List = require "../lib/Types/List"
|
||||
Y.Xml = require "../lib/Types/Xml"
|
||||
Y.Text = require "../lib/Types/Text"
|
||||
|
||||
Test = require "./TestSuite"
|
||||
|
||||
class XmlTest extends Test
|
||||
|
||||
constructor: (suffix)->
|
||||
super suffix, Y
|
||||
@doSomething_amount *= 20
|
||||
|
||||
makeNewUser: (userId)->
|
||||
conn = new Y.Test userId
|
||||
super new Y conn
|
||||
|
||||
initUsers: (u)->
|
||||
u.val("xml",new Y.Xml("div"))
|
||||
|
||||
type: "XmlTest"
|
||||
|
||||
compare: (o1, o2, depth)->
|
||||
if o1.constructor is Y.Xml
|
||||
super o1._model, o2._model, depth
|
||||
else
|
||||
super
|
||||
|
||||
getRandomRoot: (user_num, root, depth = @max_depth)->
|
||||
root ?= @users[user_num].val("xml")
|
||||
if depth is 0 or _.random(0,1) is 1 # take root
|
||||
root
|
||||
else # take child
|
||||
elems = null
|
||||
if root._name is "Xml"
|
||||
elems = root.getChildren()
|
||||
else
|
||||
return root
|
||||
|
||||
elems = elems.filter (elem)->
|
||||
elem._name is "Xml"
|
||||
if elems.length is 0
|
||||
root
|
||||
else
|
||||
p = elems[_.random(0, elems.length-1)]
|
||||
@getRandomRoot user_num, p, depth--
|
||||
|
||||
getRandomXmlElement: ()->
|
||||
if _.random(0,1) is 0
|
||||
new Y.Xml(@getRandomKey())
|
||||
else
|
||||
@getRandomText()
|
||||
|
||||
getGeneratingFunctions: (user_num)->
|
||||
that = @
|
||||
super(user_num).concat [
|
||||
f : (y)=> # set Attribute
|
||||
y.attr(that.getRandomKey(), that.getRandomText())
|
||||
types: [Y.Xml]
|
||||
,
|
||||
f : (y)-> # DELETE Attribute
|
||||
keys = Object.keys(y.attr())
|
||||
y.removeAttr(keys[_.random(0,keys.length-1)])
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # Add Class
|
||||
y.addClass(that.getRandomKey())
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # toggleClass
|
||||
y.toggleClass(that.getRandomKey())
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # Remove Class
|
||||
keys = y.attr("class").split(" ")
|
||||
y.removeClass(keys[_.random(0,keys.length-1)])
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # append XML
|
||||
child = that.getRandomXmlElement()
|
||||
y.append(child)
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # pepend XML
|
||||
child = that.getRandomXmlElement()
|
||||
y.prepend child
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # after XML
|
||||
if y.getParent()?
|
||||
child = that.getRandomXmlElement()
|
||||
y.after child
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # before XML
|
||||
if y.getParent()?
|
||||
child = that.getRandomXmlElement()
|
||||
y.before child
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # empty
|
||||
y.empty()
|
||||
types : [Y.Xml]
|
||||
,
|
||||
f : (y)-> # remove
|
||||
if y.getParent()?
|
||||
y.remove()
|
||||
types : [Y.Xml]
|
||||
]
|
||||
|
||||
describe "Y-Xml", ->
|
||||
@timeout 500000
|
||||
|
||||
beforeEach (done)->
|
||||
@yTest = new XmlTest()
|
||||
@users = @yTest.users
|
||||
|
||||
@u1 = @users[1].val("xml")
|
||||
@u2 = @users[2].val("xml")
|
||||
@u3 = @users[3].val("xml")
|
||||
done()
|
||||
|
||||
it "can handle many engines, many operations, concurrently (random)", ->
|
||||
console.log "" # TODO
|
||||
@yTest.run()
|
||||
console.log(@yTest.users[0].val("xml")+"")
|
||||
|
||||
it "has a working test suite", ->
|
||||
@yTest.compareAll()
|
||||
|
||||
it "handles double-late-join", ->
|
||||
test = new XmlTest("double")
|
||||
test.run()
|
||||
@yTest.run()
|
||||
u1 = test.users[0]
|
||||
u2 = @yTest.users[1]
|
||||
ops1 = u1._model.HB._encode()
|
||||
ops2 = u2._model.HB._encode()
|
||||
u1._model.engine.applyOp ops2, true
|
||||
u2._model.engine.applyOp ops1, true
|
||||
|
||||
it "Create Xml Element", ->
|
||||
@u1.attr("stuff", "true")
|
||||
console.log(@u1.toString())
|
||||
@yTest.compareAll()
|
||||
|
||||
describe "has method ", ->
|
||||
it "attr", ->
|
||||
@u1.attr("attr", "newAttr")
|
||||
@u1.attr("other_attr", "newAttr")
|
||||
@yTest.compareAll()
|
||||
expect(@u2.attr("attr")).to.equal("newAttr")
|
||||
expect(@u2.attr().other_attr).to.equal("newAttr")
|
||||
|
||||
it "addClass", ->
|
||||
@u1.addClass("newClass")
|
||||
@u2.addClass("otherClass")
|
||||
@yTest.compareAll()
|
||||
expect(@u1.attr("class")).to.equal("newClass otherClass") # 1 < 2 and therefore this is the proper order
|
||||
|
||||
|
||||
it "append", ->
|
||||
child = new Y.Xml("child")
|
||||
child2 = new Y.Xml("child2")
|
||||
@u1.append child
|
||||
@u1.append child2
|
||||
expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
|
||||
@yTest.compareAll()
|
||||
|
||||
it "prepend", ->
|
||||
child = new Y.Xml("child")
|
||||
child2 = new Y.Xml("child2")
|
||||
@u1.prepend child2
|
||||
@u1.prepend child
|
||||
expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
|
||||
@yTest.compareAll()
|
||||
|
||||
it "after", ->
|
||||
child = new Y.Xml("child")
|
||||
@u1.append child
|
||||
child.after new Y.Xml("right-child")
|
||||
expect(@u1.toString()).to.equal("<div><child></child><right-child></right-child></div>")
|
||||
@yTest.compareAll()
|
||||
|
||||
it "before", ->
|
||||
child = new Y.Xml("child")
|
||||
@u1.append child
|
||||
child.before new Y.Xml("left-child")
|
||||
expect(@u1.toString()).to.equal("<div><left-child></left-child><child></child></div>")
|
||||
@yTest.compareAll()
|
||||
|
||||
it "empty", ->
|
||||
child = new Y.Xml("child")
|
||||
@u1.append child
|
||||
child.before new Y.Xml("left-child")
|
||||
expect(@u1.toString()).to.equal("<div><left-child></left-child><child></child></div>")
|
||||
@yTest.compareAll()
|
||||
@u1.empty()
|
||||
expect(@u1.toString()).to.equal("<div></div>")
|
||||
@yTest.compareAll()
|
||||
|
||||
it "remove", ->
|
||||
child = new Y.Xml("child")
|
||||
child2 = new Y.Xml("child2")
|
||||
@u1.prepend child2
|
||||
@u1.prepend child
|
||||
expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
|
||||
@yTest.compareAll()
|
||||
child2.remove()
|
||||
expect(@u1.toString()).to.equal("<div><child></child></div>")
|
||||
|
||||
it "removeAttr", ->
|
||||
@u1.attr("dtrn", "stuff")
|
||||
@u1.attr("dutrianern", "stuff")
|
||||
@yTest.compareAll()
|
||||
@u2.removeAttr("dtrn")
|
||||
@yTest.compareAll()
|
||||
expect(@u3.attr("dtrn")).to.be.undefined
|
||||
|
||||
it "removeClass", ->
|
||||
@u1.addClass("dtrn")
|
||||
@u1.addClass("iExist")
|
||||
@yTest.compareAll()
|
||||
@u2.removeClass("dtrn")
|
||||
@yTest.compareAll()
|
||||
expect(@u3.attr("class")).to.equal("iExist")
|
||||
|
||||
it "toggleClass", ->
|
||||
@u1.addClass("dtrn")
|
||||
@u1.addClass("iExist")
|
||||
@yTest.compareAll()
|
||||
@u2.removeClass("dtrn")
|
||||
@yTest.compareAll()
|
||||
expect(@u3.attr("class")).to.equal("iExist")
|
||||
@u3.toggleClass("iExist")
|
||||
@u3.toggleClass("wraa")
|
||||
@yTest.compareAll()
|
||||
expect(@u1.attr("class")).to.equal("wraa")
|
||||
|
||||
it "getParent", ->
|
||||
child = new Y.Xml("child")
|
||||
@u1.prepend(child)
|
||||
expect(@u1).to.equal(child.getParent())
|
||||
|
||||
it "getChildren", ->
|
||||
child = new Y.Xml("child")
|
||||
@u1.prepend(child)
|
||||
expect(@u1.getChildren()[0]).to.equal(child)
|
||||
|
||||
if not window?
|
||||
describe "skip DOM tests (only in browser environment)", ->
|
||||
it "", ->
|
||||
else
|
||||
describe "DOM binding ", ->
|
||||
beforeEach (done)->
|
||||
@dom = @u1.getDom()
|
||||
@j = $(@dom)
|
||||
done()
|
||||
|
||||
it "can transform to a new real Dom element", ->
|
||||
expect(@dom).to.not.be.undefined
|
||||
|
||||
it "supports dom.insertBefore", ->
|
||||
newdom = $("<p>dtrn</p>")[0]
|
||||
newdom2 = $("<p>dtrn2</p>")[0]
|
||||
@dom.insertBefore(newdom2, null)
|
||||
@dom.insertBefore(newdom, newdom2)
|
||||
expect(@u1+"").to.equal("<div><p>dtrn</p><p>dtrn2</p></div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><p>dtrn</p><p>dtrn2</p></div>")
|
||||
|
||||
it "supports dom.appendChild", ->
|
||||
newdom = $("<p>dtrn</p>")[0]
|
||||
@dom.appendChild(newdom)
|
||||
expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
|
||||
|
||||
it "supports dom.setAttribute", ->
|
||||
@dom.setAttribute("test_attribute", "newVal")
|
||||
expect(@u1.attr("test_attribute")).to.equal("newVal")
|
||||
expect(@dom.getAttribute("test_attribute")).to.equal("newVal")
|
||||
|
||||
it "supports dom.removeAttribute", ->
|
||||
@dom.setAttribute("test_attribute", "newVal")
|
||||
expect(@u1.attr("test_attribute")).to.equal("newVal")
|
||||
expect(@dom.getAttribute("test_attribute")).to.equal("newVal")
|
||||
@dom.removeAttribute("test_attribute")
|
||||
expect(@u1.attr("test_attribute")).to.be.undefined
|
||||
attr = @dom.getAttribute("test_attribute")
|
||||
expect(attr?).to.be.false
|
||||
|
||||
it "supports dom.removeChild", ->
|
||||
newdom = $("<p>dtrn</p>")[0]
|
||||
@dom.appendChild(newdom)
|
||||
expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
|
||||
|
||||
@dom.removeChild(newdom)
|
||||
expect(@dom.childNodes.length).to.equal(0)
|
||||
expect(@u1.getChildren().length).to.equal(0)
|
||||
|
||||
it "supports dom.replaceChild", ->
|
||||
dom = $("<p>dtrn</p>")[0]
|
||||
@dom.appendChild(dom)
|
||||
expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
|
||||
|
||||
newdom = $("<p>replaced</p>")[0]
|
||||
@dom.replaceChild(newdom, dom)
|
||||
expect(@dom.outerHTML).to.equal("<div><p>replaced</p></div>")
|
||||
expect(@u1+"").to.equal("<div><p>replaced</p></div>")
|
||||
|
||||
it "supports dom.classList.add", ->
|
||||
@dom.classList.add "classy"
|
||||
@dom.classList.add "moreclassy"
|
||||
expect(@u1.attr("class")).to.equal("classy moreclassy")
|
||||
expect(@dom.getAttribute("class")).to.equal("classy moreclassy")
|
||||
|
||||
|
||||
it "supports dom.textContent", ->
|
||||
dom = $("<p>dtrn</p>")[0]
|
||||
@dom.appendChild(dom)
|
||||
expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
|
||||
|
||||
@dom.textContent = ""
|
||||
expect(@u1+"").to.equal("<div></div>")
|
||||
expect(@dom.outerHTML).to.equal("<div></div>")
|
||||
|
||||
it "suppports dom.textContent (non empty string)", ->
|
||||
dom = $("<p>dtrn</p>")[0]
|
||||
@dom.appendChild(dom)
|
||||
expect(@u1+"").to.equal("<div><p>dtrn</p></div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><p>dtrn</p></div>")
|
||||
|
||||
@dom.textContent = "stuff"
|
||||
expect(@u1+"").to.equal("<div>stuff</div>")
|
||||
expect(@dom.outerHTML).to.equal("<div>stuff</div>")
|
||||
|
||||
it "supports jquery.addClass", ->
|
||||
@j.addClass("testedy tested")
|
||||
expect(@dom.getAttribute("class")).to.equal("testedy tested")
|
||||
|
||||
it "supports jquery.after", ->
|
||||
d = $("<span></span>")
|
||||
@dom.appendChild(d[0], null)
|
||||
d.after("<div>after</div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><span></span><div>after</div></div>")
|
||||
expect(@u1+"").to.equal("<div><span></span><div>after</div></div>")
|
||||
|
||||
it "supports jquery.append", ->
|
||||
d = $("<span></span>")[0]
|
||||
@j.append(d)
|
||||
d = $("<div></div>")[0]
|
||||
@j.append(d)
|
||||
expect(@dom.outerHTML).to.equal("<div><span></span><div></div></div>")
|
||||
expect(@u1+"").to.equal("<div><span></span><div></div></div>")
|
||||
|
||||
it "supports jquery.appendTo", ->
|
||||
$("<b>appendedTo</b>").appendTo(@dom)
|
||||
$("<p>").appendTo(@dom)
|
||||
expect(@dom.outerHTML).to.equal("<div><b>appendedTo</b><p></p></div>")
|
||||
expect(@u1+"").to.equal("<div><b>appendedTo</b><p></p></div>")
|
||||
|
||||
it "supports jquery.before", ->
|
||||
newdom = $("<p>")
|
||||
$(@dom).append(newdom)
|
||||
newdom.before("<div>before</div>")
|
||||
expect(@dom.outerHTML).to.equal("<div><div>before</div><p></p></div>")
|
||||
expect(@u1+"").to.equal("<div><div>before</div><p></p></div>")
|
||||
|
||||
it "supports jquery.detach", ->
|
||||
d = $("<p>")
|
||||
@j.append(d)
|
||||
d.detach()
|
||||
expect(@dom.outerHTML).to.equal("<div></div>")
|
||||
expect(@u1+"").to.equal("<div></div>")
|
||||
|
||||
it "supports jquery.empty", ->
|
||||
d = $("<p />")
|
||||
d.appendTo(@dom)
|
||||
d = $("<div />")
|
||||
d.appendTo(@dom)
|
||||
@j.empty()
|
||||
expect(@dom.outerHTML).to.equal("<div></div>")
|
||||
expect(@u1+"").to.equal("<div></div>")
|
||||
|
||||
it "supports jquery.insertAfter", ->
|
||||
d = $("<span>")
|
||||
d.appendTo(@dom)
|
||||
$("<p>after</p>").insertAfter(d)
|
||||
expect(@dom.outerHTML).to.equal("<div><span></span><p>after</p></div>")
|
||||
expect(@u1+"").to.equal("<div><span></span><p>after</p></div>")
|
||||
|
||||
it "supports jquery.insertBefore", ->
|
||||
d = $("<span>")
|
||||
d.appendTo(@j)
|
||||
$("<p>before</p>").insertBefore(d)
|
||||
expect(@dom.outerHTML).to.equal("<div><p>before</p><span></span></div>")
|
||||
expect(@u1+"").to.equal("<div><p>before</p><span></span></div>")
|
||||
|
||||
it "supports jquery.prepend", ->
|
||||
@j.prepend("<p>prepended2</p>")
|
||||
@j.prepend("<p>prepended1</p>")
|
||||
expect(@dom.outerHTML).to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
|
||||
expect(@u1+"").to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
|
||||
|
||||
it "supports jquery.prependTo", ->
|
||||
$("<p>prepended2</p>").prependTo(@j)
|
||||
$("<p>prepended1</p>").prependTo(@j)
|
||||
expect(@dom.outerHTML).to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
|
||||
expect(@u1+"").to.equal("<div><p>prepended1</p><p>prepended2</p></div>")
|
||||
|
||||
it "supports jquery.remove", ->
|
||||
d = $("<div />")
|
||||
d.prependTo(@j)
|
||||
d.remove()
|
||||
expect(@dom.outerHTML).to.equal("<div></div>")
|
||||
expect(@u1+"").to.equal("<div></div>")
|
||||
|
||||
it "supports jquery.removeAttr", ->
|
||||
@dom.setAttribute("test_attribute", "newVal")
|
||||
expect(@u1.attr("test_attribute")).to.equal("newVal")
|
||||
expect(@dom.getAttribute("test_attribute")).to.equal("newVal")
|
||||
|
||||
@j.removeAttr("test_attribute")
|
||||
expect(@u1.attr("test_attribute")).to.be.undefined
|
||||
expect(@j.attr("test_attribute")).to.be.undefined
|
||||
|
||||
it "supports jquery.removeClass", ->
|
||||
@j.addClass("testedy tested")
|
||||
expect(@dom.getAttribute("class")).to.equal("testedy tested")
|
||||
|
||||
@j.removeClass("testedy")
|
||||
expect(@dom.getAttribute("class")).to.equal("tested")
|
||||
expect(@u1.hasClass("testedy")).to.be.false
|
||||
|
||||
it "supports jquery.attr", ->
|
||||
@j.attr("atone", "yeah")
|
||||
expect(@u1.attr("atone")).to.equal("yeah")
|
||||
expect(@j.attr("atone")).to.equal("yeah")
|
||||
|
||||
it "supports jquery.replaceAll", ->
|
||||
d = $("<p />")
|
||||
d.appendTo(@dom)
|
||||
d = $("<p />")
|
||||
d.appendTo(@dom)
|
||||
$("<span>").replaceAll($(@dom).find("p"))
|
||||
expect(@dom.outerHTML).to.equal("<div><span></span><span></span></div>")
|
||||
expect(@u1+"").to.equal("<div><span></span><span></span></div>")
|
||||
|
||||
it "supports jquery.replaceWith", ->
|
||||
d = $("<span>")
|
||||
@j.prepend(d)
|
||||
d = $("<span>")
|
||||
@j.prepend(d)
|
||||
d = $("<span>")
|
||||
@j.prepend(d)
|
||||
d = @j.find("span")
|
||||
d.replaceWith("<div></div>")
|
||||
|
||||
expect(@dom.outerHTML).to.equal("<div><div></div><div></div><div></div></div>")
|
||||
expect(@u1+"").to.equal("<div><div></div><div></div><div></div></div>")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,196 +0,0 @@
|
||||
chai = require('chai')
|
||||
expect = chai.expect
|
||||
should = chai.should()
|
||||
sinon = require('sinon')
|
||||
sinonChai = require('sinon-chai')
|
||||
_ = require("underscore")
|
||||
$ = require("jquery")
|
||||
document?.$ = $ # for browser
|
||||
require 'coffee-errors'
|
||||
|
||||
chai.use(sinonChai)
|
||||
|
||||
Y = require "../lib/index"
|
||||
Connector = require "../../y-test/lib/y-test.coffee"
|
||||
|
||||
Test = require "./TestSuite"
|
||||
class XmlTest extends Test
|
||||
|
||||
type: "XmlTest"
|
||||
|
||||
makeNewUser: (user, conn)->
|
||||
super new Y.XmlFramework user, conn
|
||||
|
||||
getRandomRoot: (user_num)->
|
||||
@users[user_num].getSharedObject()
|
||||
|
||||
getContent: (user_num)->
|
||||
@users[user_num].val()
|
||||
|
||||
|
||||
describe "XmlFramework", ->
|
||||
beforeEach (done)->
|
||||
@timeout 50000
|
||||
@yTest = new XmlTest()
|
||||
###
|
||||
|
||||
@users = @yTest.users
|
||||
###
|
||||
test_users = []
|
||||
connector = (new Connector 0, test_users)
|
||||
@test_user = @yTest.makeNewUser 0, connector
|
||||
test_users.push @test_user
|
||||
# test_user_listen listens to the actions of test_user. He will update his dom when he receives from test_user.
|
||||
@test_user_listen = @yTest.makeNewUser 2, connector
|
||||
test_users.push @test_user_listen
|
||||
@test_user2 = @yTest.makeNewUser 1, (Connector_uninitialized [])
|
||||
|
||||
$("#test_dom").replaceWith('<div id="test_dom" test_attribute="the test" class="stuffy" style="color: blue"><p id="replaceme">replace me</p><p id="removeme">remove me</p><p>This is a test object for <b>XmlFramework</b></p><span class="span_element"><p>span</p></span></div>')
|
||||
@$dom = $("#test_dom")
|
||||
@dom = @$dom[0]
|
||||
@test_user.val(@dom)
|
||||
@test_user_listen.getConnector().flushAll()
|
||||
@test_user_listen_dom = @test_user_listen.val()
|
||||
|
||||
@check = ()=>
|
||||
dom_ = @dom.outerHTML
|
||||
# now test if other collaborators can parse the HB and result in the same content
|
||||
hb = @test_user.HB._encode()
|
||||
@test_user2.engine.applyOps(hb)
|
||||
dom2 = @test_user2.val()
|
||||
expect(dom_).to.equal(dom2.outerHTML)
|
||||
@test_user_listen.getConnector().flushAll()
|
||||
expect(dom_).to.equal(@test_user_listen_dom.outerHTML)
|
||||
done()
|
||||
|
||||
it "can transform to a new real Dom element", ->
|
||||
dom_ = @test_user.val(true)
|
||||
expect(dom_ isnt @dom).to.be.true
|
||||
|
||||
it "supports dom.insertBefore", ->
|
||||
newdom = $("<p>dtrn</p>")[0]
|
||||
newdom2 = $("<p>dtrn2</p>")[0]
|
||||
n = $("#removeme")[0]
|
||||
@dom.insertBefore(newdom, null)
|
||||
@dom.insertBefore(newdom2, n)
|
||||
@check()
|
||||
|
||||
it "supports dom.appendChild", ->
|
||||
newdom = $("<p>dtrn</p>")[0]
|
||||
@dom.appendChild(newdom)
|
||||
@check()
|
||||
|
||||
it "supports dom.setAttribute", ->
|
||||
@dom.setAttribute("test_attribute", "newVal")
|
||||
@check()
|
||||
|
||||
it "supports dom.removeAttribute", ->
|
||||
@dom.removeAttribute("test_attribute")
|
||||
@check()
|
||||
|
||||
it "supports dom.removeChild", ->
|
||||
@dom.removeChild($("#removeme")[0])
|
||||
expect($("#removeme").length).to.equal(0)
|
||||
@check()
|
||||
|
||||
it "supports dom.replaceChild", ->
|
||||
newdom = $("<p>replaced</p>")[0]
|
||||
replace = $("#replaceme")[0]
|
||||
@dom.replaceChild(newdom,replace)
|
||||
expect($("#replaceme").length).to.equal(0)
|
||||
@check()
|
||||
|
||||
it "supports dom.classList.add", ->
|
||||
@dom.classList.add "classy"
|
||||
@check()
|
||||
|
||||
|
||||
it "supports dom.textcontent", -> #TODO!!!!
|
||||
@dom.classList.add "classy"
|
||||
@check()
|
||||
|
||||
it "supports jquery.addClass", ->
|
||||
@$dom.addClass("testy")
|
||||
@check()
|
||||
|
||||
it "supports jquery.after", ->
|
||||
d = $("#test_dom p")
|
||||
d.after("<div class=\"inserted_after\">after</div>")
|
||||
@check()
|
||||
|
||||
it "supports jquery.append", ->
|
||||
d = $("#test_dom p")
|
||||
d.after("<b>appended</b>")
|
||||
@check()
|
||||
|
||||
it "supports jquery.appendTo", ->
|
||||
$("<b>appendedTo</b>").appendTo("#test_dom p")
|
||||
$("p").appendTo("#test_dom")
|
||||
@check()
|
||||
|
||||
it "supports jquery.before", ->
|
||||
d = $("#test_dom p")
|
||||
d.before("<div>before</div>")
|
||||
@check()
|
||||
|
||||
it "supports jquery.detach", ->
|
||||
d = $(".inserted_after")
|
||||
d.detach()
|
||||
@check()
|
||||
|
||||
it "supports jquery.empty", ->
|
||||
d = $("#test_dom p")
|
||||
d.empty()
|
||||
@check()
|
||||
|
||||
it "supports jquery.insertAfter", ->
|
||||
$("<p>after span</p>").insertAfter(".span_element")
|
||||
@check()
|
||||
|
||||
it "supports jquery.insertBefore", ->
|
||||
$("<p>before span</p>").insertBefore(".span_element")
|
||||
@check()
|
||||
|
||||
it "supports jquery.prepend", ->
|
||||
d = $("#test_dom div")
|
||||
d.prepend("<p>prepended</p>")
|
||||
@check()
|
||||
|
||||
it "supports jquery.prependTo", ->
|
||||
$("<p atone=false attwo=\"dtrn\" class=\"attr_node sudo su\">prepended to</p>").prependTo("#test_dom div")
|
||||
@check()
|
||||
|
||||
it "supports jquery.remove", ->
|
||||
d = $("#test_dom b")
|
||||
d.remove()
|
||||
@check()
|
||||
|
||||
it "supports jquery.removeAttr", ->
|
||||
d = $(".attr_node")
|
||||
d.removeAttr("attwo")
|
||||
@check()
|
||||
|
||||
it "supports jquery.removeClass", ->
|
||||
d = $(".attr_node")
|
||||
d.removeClass("sudo")
|
||||
@check()
|
||||
|
||||
it "supports jquery.attr", ->
|
||||
d = $(".attr_node")
|
||||
d.attr("atone", true)
|
||||
@check()
|
||||
|
||||
it "supports jquery.replaceAll", ->
|
||||
$("<span>New span content </span>").replaceAll("#test_dom div")
|
||||
@check()
|
||||
|
||||
it "supports jquery.replaceWith", ->
|
||||
d = $("#test_dom span")
|
||||
d.replaceWith("<div>me is div again </div>")
|
||||
@check()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -9,12 +9,11 @@ chai.use(sinonChai)
|
||||
|
||||
Y = require "../lib/y.coffee"
|
||||
Y.Test = require "../../y-test/lib/y-test.coffee"
|
||||
Y.Text = require "../lib/Types/Text"
|
||||
Y.List = require "../lib/Types/List"
|
||||
Y.Text = require "../../y-text/lib/y-text"
|
||||
Y.List = require "../../y-list/lib/y-list"
|
||||
|
||||
Test = require "./TestSuite"
|
||||
|
||||
class JsonTest extends Test
|
||||
TestSuite = require "./TestSuite"
|
||||
class ObjectTest extends TestSuite
|
||||
|
||||
constructor: (suffix)->
|
||||
super suffix, Y
|
||||
@ -23,7 +22,7 @@ class JsonTest extends Test
|
||||
conn = new Y.Test userId
|
||||
super new Y conn
|
||||
|
||||
type: "JsonTest"
|
||||
type: "ObjectTest"
|
||||
|
||||
getRandomRoot: (user_num, root, depth = @max_depth)->
|
||||
root ?= @users[user_num]
|
||||
@ -67,11 +66,9 @@ class JsonTest extends Test
|
||||
y.val(@getRandomKey(), new Y.Text(@getRandomText()))
|
||||
types: [Y.Object]
|
||||
,
|
||||
f : (y)=> # SET PROPERTY (primitive)
|
||||
l = y.val().length
|
||||
y.val(_.random(0, l-1), @getRandomText())
|
||||
null
|
||||
types : [Y.List]
|
||||
f : (y)=> # SET PROPERTY List
|
||||
y.val(@getRandomKey(), new Y.List(@getRandomText().split("")))
|
||||
types: [Y.Object]
|
||||
,
|
||||
f : (y)=> # Delete Array Element
|
||||
list = y.val()
|
||||
@ -82,17 +79,22 @@ class JsonTest extends Test
|
||||
,
|
||||
f : (y)=> # insert Object mutable
|
||||
l = y.val().length
|
||||
y.val(_.random(0, l-1), new Y.Object(@getRamdomObject()))
|
||||
y.insert(_.random(0, l-1), new Y.Object(@getRandomObject()))
|
||||
types: [Y.List]
|
||||
,
|
||||
f : (y)=> # insert Text mutable
|
||||
l = y.val().length
|
||||
y.val(_.random(0, l-1), new Y.Text(@getRandomText()))
|
||||
y.insert(_.random(0, l-1), new Y.Text(@getRandomText()))
|
||||
types : [Y.List]
|
||||
,
|
||||
f : (y)=> # insert List mutable
|
||||
l = y.val().length
|
||||
y.insert(_.random(0, l-1), new Y.List(@getRandomText().split("")))
|
||||
types : [Y.List]
|
||||
,
|
||||
f : (y)=> # insert Number (primitive object)
|
||||
l = y.val().length
|
||||
y.val(_.random(0,l-1), _.random(0,42))
|
||||
y.insert(_.random(0,l-1), _.random(0,42))
|
||||
types : [Y.List]
|
||||
,
|
||||
f : (y)=> # SET Object Property (circular)
|
||||
@ -101,18 +103,32 @@ class JsonTest extends Test
|
||||
,
|
||||
f : (y)=> # insert Object mutable (circular)
|
||||
l = y.val().length
|
||||
y.val(_.random(0, l-1), @getRandomRoot user_num)
|
||||
y.insert(_.random(0, l-1), @getRandomRoot user_num)
|
||||
types: [Y.List]
|
||||
,
|
||||
f : (y)=> # INSERT TEXT
|
||||
y
|
||||
pos = _.random 0, (y.val().length-1)
|
||||
y.insert pos, @getRandomText()
|
||||
null
|
||||
types: [Y.Text]
|
||||
,
|
||||
f : (y)-> # DELETE TEXT
|
||||
if y.val().length > 0
|
||||
pos = _.random 0, (y.val().length-1) # TODO: put here also arbitrary number (test behaviour in error cases)
|
||||
length = _.random 0, (y.val().length - pos)
|
||||
ops1 = y.delete pos, length
|
||||
undefined
|
||||
types : [Y.Text]
|
||||
]
|
||||
###
|
||||
|
||||
###
|
||||
module.exports = ObjectTest
|
||||
|
||||
describe "JsonFramework", ->
|
||||
describe "Object Test", ->
|
||||
@timeout 500000
|
||||
|
||||
beforeEach (done)->
|
||||
@yTest = new JsonTest()
|
||||
@yTest = new ObjectTest()
|
||||
@users = @yTest.users
|
||||
|
||||
@test_user = @yTest.makeNewUser "test_user"
|
||||
@ -126,7 +142,7 @@ describe "JsonFramework", ->
|
||||
@yTest.compareAll()
|
||||
|
||||
it "handles double-late-join", ->
|
||||
test = new JsonTest("double")
|
||||
test = new ObjectTest("double")
|
||||
test.run()
|
||||
@yTest.run()
|
||||
u1 = test.users[0]
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user