outsourced all types (except for object type)

This commit is contained in:
DadaMonad 2015-02-27 18:01:21 +00:00
parent c663230c1b
commit 96ed8b0f98
33 changed files with 94032 additions and 63591 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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();

View File

@ -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);
};
};

View File

@ -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;
}

View File

@ -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 += '&nbsp;');
} 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;
}

View File

@ -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;
}

View File

@ -42,4 +42,4 @@ if (typeof window !== "undefined" && window !== null) {
window.Y = createY;
}
createY.Object = require("./Types/Object");
createY.Object = require("./ObjectType");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -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

File diff suppressed because one or more lines are too long

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

File diff suppressed because one or more lines are too long

32117
build/test/xml-test.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -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', ->

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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 += '&nbsp;'
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

View File

@ -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 classs 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

View File

@ -36,4 +36,4 @@ module.exports = createY
if window?
window.Y = createY
createY.Object = require "./Types/Object"
createY.Object = require "./ObjectType"

View File

@ -13,7 +13,6 @@
"keywords": [
"OT",
"collaboration",
"Yata",
"synchronization",
"ShareJS",
"Coweb",

View File

@ -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!"

View File

@ -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))

View File

@ -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>")

View File

@ -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()

View File

@ -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

2
y.js

File diff suppressed because one or more lines are too long