completed the xml tests - and lots of them run successfully
This commit is contained in:
File diff suppressed because one or more lines are too long
+3
-2
File diff suppressed because one or more lines are too long
@@ -433,7 +433,8 @@ module.exports = function() {
|
|||||||
position: this.getPosition(),
|
position: this.getPosition(),
|
||||||
object: this.parent.getCustomType(),
|
object: this.parent.getCustomType(),
|
||||||
length: 1,
|
length: 1,
|
||||||
changedBy: o.uid.creator
|
changedBy: o.uid.creator,
|
||||||
|
oldValue: this.val()
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|||||||
+4
-311
@@ -1,50 +1,11 @@
|
|||||||
var dont_proxy, json_types_uninitialized, proxy_token, _proxy,
|
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; },
|
__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;
|
__hasProp = {}.hasOwnProperty;
|
||||||
|
|
||||||
json_types_uninitialized = require("./JsonTypes");
|
json_types_uninitialized = require("./JsonTypes");
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
_proxy = function(f_name, f) {
|
|
||||||
var old_f;
|
|
||||||
old_f = this[f_name];
|
|
||||||
if (old_f != null) {
|
|
||||||
return this[f_name] = function() {
|
|
||||||
var args, that, _ref;
|
|
||||||
if (!proxy_token && !((_ref = this._y) != null ? _ref.isDeleted() : void 0)) {
|
|
||||||
that = this;
|
|
||||||
args = arguments;
|
|
||||||
return dont_proxy(function() {
|
|
||||||
f.apply(that, args);
|
|
||||||
return old_f.apply(that, args);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return old_f.apply(this, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (typeof Element !== "undefined" && Element !== null) {
|
|
||||||
Element.prototype._proxy = _proxy;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = function(HB) {
|
module.exports = function(HB) {
|
||||||
var TextNodeType, XmlType, json_types, parser, types;
|
var XmlType, json_types, parser, types;
|
||||||
json_types = json_types_uninitialized(HB);
|
json_types = json_types_uninitialized(HB);
|
||||||
types = json_types.types;
|
types = json_types.types;
|
||||||
parser = json_types.parser;
|
parser = json_types.parser;
|
||||||
@@ -52,234 +13,11 @@ module.exports = function(HB) {
|
|||||||
__extends(XmlType, _super);
|
__extends(XmlType, _super);
|
||||||
|
|
||||||
function XmlType(uid, _at_tagname, attributes, elements, _at_xml) {
|
function XmlType(uid, _at_tagname, attributes, elements, _at_xml) {
|
||||||
var attr, d, element, i, n, word, _i, _j, _len, _ref, _ref1, _ref2;
|
|
||||||
this.tagname = _at_tagname;
|
this.tagname = _at_tagname;
|
||||||
this.xml = _at_xml;
|
this.xml = _at_xml;
|
||||||
|
|
||||||
/* In case you make this instanceof Insert again
|
|
||||||
if prev? and (not next?) and prev.type?
|
|
||||||
* adjust what you actually mean. you want to insert after prev, then
|
|
||||||
* next is not defined. but we only insert after non-deleted elements.
|
|
||||||
* This is also handled in TextInsert.
|
|
||||||
while prev.isDeleted()
|
|
||||||
prev = prev.prev_cl
|
|
||||||
next = prev.next_cl
|
|
||||||
*/
|
|
||||||
XmlType.__super__.constructor.call(this, uid);
|
|
||||||
if (((_ref = this.xml) != null ? _ref._y : void 0) != null) {
|
|
||||||
d = new types.Delete(void 0, this.xml._y);
|
|
||||||
HB.addOperation(d).execute();
|
|
||||||
this.xml._y = null;
|
|
||||||
}
|
|
||||||
if ((attributes != null) && (elements != null)) {
|
|
||||||
this.saveOperation('attributes', attributes);
|
|
||||||
this.saveOperation('elements', elements);
|
|
||||||
} else if ((attributes == null) && (elements == null)) {
|
|
||||||
this.attributes = new types.JsonType();
|
|
||||||
this.attributes.setMutableDefault('immutable');
|
|
||||||
HB.addOperation(this.attributes).execute();
|
|
||||||
this.elements = new types.WordType();
|
|
||||||
this.elements.parent = this;
|
|
||||||
HB.addOperation(this.elements).execute();
|
|
||||||
} else {
|
|
||||||
throw new Error("Either define attribute and elements both, or none of them");
|
|
||||||
}
|
|
||||||
if (this.xml != null) {
|
|
||||||
this.tagname = this.xml.tagName;
|
|
||||||
for (i = _i = 0, _ref1 = this.xml.attributes.length; 0 <= _ref1 ? _i < _ref1 : _i > _ref1; i = 0 <= _ref1 ? ++_i : --_i) {
|
|
||||||
attr = xml.attributes[i];
|
|
||||||
this.attributes.val(attr.name, attr.value);
|
|
||||||
}
|
|
||||||
_ref2 = this.xml.childNodes;
|
|
||||||
for (_j = 0, _len = _ref2.length; _j < _len; _j++) {
|
|
||||||
n = _ref2[_j];
|
|
||||||
if (n.nodeType === n.TEXT_NODE) {
|
|
||||||
word = new TextNodeType(void 0, n);
|
|
||||||
HB.addOperation(word).execute();
|
|
||||||
this.elements.push(word);
|
|
||||||
} else if (n.nodeType === n.ELEMENT_NODE) {
|
|
||||||
element = new XmlType(void 0, void 0, void 0, void 0, n);
|
|
||||||
HB.addOperation(element).execute();
|
|
||||||
this.elements.push(element);
|
|
||||||
} else {
|
|
||||||
throw new Error("I don't know Node-type " + n.nodeType + "!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.setXmlProxy();
|
|
||||||
}
|
|
||||||
void 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlType.prototype.type = "XmlType";
|
XmlType.prototype.setXmlProxy = function() {};
|
||||||
|
|
||||||
XmlType.prototype.applyDelete = function(op) {
|
|
||||||
if ((this.insert_parent != null) && !this.insert_parent.isDeleted()) {
|
|
||||||
return this.insert_parent.applyDelete(op);
|
|
||||||
} else {
|
|
||||||
this.attributes.applyDelete();
|
|
||||||
this.elements.applyDelete();
|
|
||||||
return XmlType.__super__.applyDelete.apply(this, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
XmlType.prototype.cleanup = function() {
|
|
||||||
return XmlType.__super__.cleanup.call(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
XmlType.prototype.setXmlProxy = function() {
|
|
||||||
var findNode, insertBefore, removeChild, renewClassList, that;
|
|
||||||
this.xml._y = this;
|
|
||||||
that = this;
|
|
||||||
this.elements.on('insert', function(event, op) {
|
|
||||||
var newNode, right, rightNode;
|
|
||||||
if (op.creator !== HB.getUserId() && this === that.elements) {
|
|
||||||
newNode = op.content.val();
|
|
||||||
right = op.next_cl;
|
|
||||||
while ((right != null) && right.isDeleted()) {
|
|
||||||
right = right.next_cl;
|
|
||||||
}
|
|
||||||
rightNode = null;
|
|
||||||
if (right.type !== 'Delimiter') {
|
|
||||||
rightNode = right.val().val();
|
|
||||||
}
|
|
||||||
return dont_proxy(function() {
|
|
||||||
return that.xml.insertBefore(newNode, rightNode);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.elements.on('delete', function(event, op) {
|
|
||||||
var del_op, deleted;
|
|
||||||
del_op = op.deleted_by[0];
|
|
||||||
if ((del_op != null) && del_op.creator !== HB.getUserId() && this === that.elements) {
|
|
||||||
deleted = op.content.val();
|
|
||||||
return dont_proxy(function() {
|
|
||||||
return that.xml.removeChild(deleted);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.attributes.on(['add', 'update'], function(event, property_name, op) {
|
|
||||||
if (op.creator !== HB.getUserId() && this === that.attributes) {
|
|
||||||
return dont_proxy(function() {
|
|
||||||
var newval;
|
|
||||||
newval = op.val().val();
|
|
||||||
if (newval != null) {
|
|
||||||
return that.xml.setAttribute(property_name, op.val().val());
|
|
||||||
} else {
|
|
||||||
return that.xml.removeAttribute(property_name);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
findNode = function(child) {
|
|
||||||
var elem;
|
|
||||||
if (child == null) {
|
|
||||||
throw new Error("you must specify a parameter!");
|
|
||||||
}
|
|
||||||
child = child._y;
|
|
||||||
elem = that.elements.beginning.next_cl;
|
|
||||||
while (elem.type !== 'Delimiter' && elem.content !== child) {
|
|
||||||
elem = elem.next_cl;
|
|
||||||
}
|
|
||||||
if (elem.type === 'Delimiter') {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
insertBefore = function(insertedNode_s, adjacentNode) {
|
|
||||||
var child, element, inserted_nodes, next, prev, _results;
|
|
||||||
next = null;
|
|
||||||
if (adjacentNode != null) {
|
|
||||||
next = findNode(adjacentNode);
|
|
||||||
}
|
|
||||||
prev = null;
|
|
||||||
if (next) {
|
|
||||||
prev = next.prev_cl;
|
|
||||||
} else {
|
|
||||||
prev = this._y.elements.end.prev_cl;
|
|
||||||
while (prev.isDeleted()) {
|
|
||||||
prev = prev.prev_cl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
inserted_nodes = null;
|
|
||||||
if (insertedNode_s.nodeType === insertedNode_s.DOCUMENT_FRAGMENT_NODE) {
|
|
||||||
child = insertedNode_s.lastChild;
|
|
||||||
_results = [];
|
|
||||||
while (child != null) {
|
|
||||||
element = new XmlType(void 0, void 0, void 0, void 0, child);
|
|
||||||
HB.addOperation(element).execute();
|
|
||||||
that.elements.insertAfter(prev, element);
|
|
||||||
_results.push(child = child.previousSibling);
|
|
||||||
}
|
|
||||||
return _results;
|
|
||||||
} else {
|
|
||||||
element = new XmlType(void 0, void 0, void 0, void 0, insertedNode_s);
|
|
||||||
HB.addOperation(element).execute();
|
|
||||||
return that.elements.insertAfter(prev, element);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
this.xml._proxy('insertBefore', insertBefore);
|
|
||||||
this.xml._proxy('appendChild', insertBefore);
|
|
||||||
this.xml._proxy('removeAttribute', function(name) {
|
|
||||||
return that.attributes.val(name, void 0);
|
|
||||||
});
|
|
||||||
this.xml._proxy('setAttribute', function(name, value) {
|
|
||||||
return that.attributes.val(name, value);
|
|
||||||
});
|
|
||||||
renewClassList = function(newclass) {
|
|
||||||
var dont_do_it, elem, value, _i, _len;
|
|
||||||
dont_do_it = false;
|
|
||||||
if (newclass != null) {
|
|
||||||
for (_i = 0, _len = this.length; _i < _len; _i++) {
|
|
||||||
elem = this[_i];
|
|
||||||
if (newclass === elem) {
|
|
||||||
dont_do_it = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
value = Array.prototype.join.call(this, " ");
|
|
||||||
if ((newclass != null) && !dont_do_it) {
|
|
||||||
value += " " + newclass;
|
|
||||||
}
|
|
||||||
return that.attributes.val('class', value);
|
|
||||||
};
|
|
||||||
_proxy.call(this.xml.classList, 'add', renewClassList);
|
|
||||||
_proxy.call(this.xml.classList, 'remove', renewClassList);
|
|
||||||
this.xml.__defineSetter__('className', function(val) {
|
|
||||||
return this.setAttribute('class', val);
|
|
||||||
});
|
|
||||||
this.xml.__defineGetter__('className', function() {
|
|
||||||
return that.attributes.val('class');
|
|
||||||
});
|
|
||||||
this.xml.__defineSetter__('textContent', function(val) {
|
|
||||||
var elem, remove, text_node;
|
|
||||||
elem = that.xml.firstChild;
|
|
||||||
while (elem != null) {
|
|
||||||
remove = elem;
|
|
||||||
elem = elem.nextSibling;
|
|
||||||
that.xml.removeChild(remove);
|
|
||||||
}
|
|
||||||
if (val !== "") {
|
|
||||||
text_node = document.createTextNode(val);
|
|
||||||
return that.xml.appendChild(text_node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
removeChild = function(node) {
|
|
||||||
var d, elem;
|
|
||||||
elem = findNode(node);
|
|
||||||
if (!elem) {
|
|
||||||
throw new Error("You are only allowed to delete existing (direct) child elements!");
|
|
||||||
}
|
|
||||||
d = new types.Delete(void 0, elem);
|
|
||||||
HB.addOperation(d).execute();
|
|
||||||
return node._y = null;
|
|
||||||
};
|
|
||||||
this.xml._proxy('removeChild', removeChild);
|
|
||||||
return this.xml._proxy('replaceChild', function(insertedNode, replacedNode) {
|
|
||||||
insertBefore.call(this, insertedNode, replacedNode);
|
|
||||||
return removeChild.call(this, replacedNode);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
XmlType.prototype.val = function(enforce) {
|
XmlType.prototype.val = function(enforce) {
|
||||||
var a, attr, attr_name, e, n, text_node, value;
|
var a, attr, attr_name, e, n, text_node, value;
|
||||||
@@ -351,54 +89,9 @@ module.exports = function(HB) {
|
|||||||
return XmlType;
|
return XmlType;
|
||||||
|
|
||||||
})(types.Insert);
|
})(types.Insert);
|
||||||
parser['XmlType'] = function(json) {
|
return parser['XmlType'] = function(json) {
|
||||||
var attributes, elements, tagname, uid;
|
var attributes, elements, tagname, uid;
|
||||||
uid = json['uid'], attributes = json['attributes'], elements = json['elements'], tagname = json['tagname'];
|
uid = json['uid'], attributes = json['attributes'], elements = json['elements'], tagname = json['tagname'];
|
||||||
return new XmlType(uid, tagname, attributes, elements, void 0);
|
return new XmlType(uid, tagname, attributes, elements, void 0);
|
||||||
};
|
};
|
||||||
TextNodeType = (function(_super) {
|
|
||||||
__extends(TextNodeType, _super);
|
|
||||||
|
|
||||||
function TextNodeType(uid, content) {
|
|
||||||
var d;
|
|
||||||
if (content._y != null) {
|
|
||||||
d = new types.Delete(void 0, content._y);
|
|
||||||
HB.addOperation(d).execute();
|
|
||||||
content._y = null;
|
|
||||||
}
|
|
||||||
content._y = this;
|
|
||||||
TextNodeType.__super__.constructor.call(this, uid, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
TextNodeType.prototype.applyDelete = function(op) {
|
|
||||||
if ((this.insert_parent != null) && !this.insert_parent.isDeleted()) {
|
|
||||||
return this.insert_parent.applyDelete(op);
|
|
||||||
} else {
|
|
||||||
return TextNodeType.__super__.applyDelete.apply(this, arguments);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TextNodeType.prototype.type = "TextNodeType";
|
|
||||||
|
|
||||||
TextNodeType.prototype._encode = function() {
|
|
||||||
var json;
|
|
||||||
json = {
|
|
||||||
'type': this.type,
|
|
||||||
'uid': this.getUid(),
|
|
||||||
'content': this.content.textContent
|
|
||||||
};
|
|
||||||
return json;
|
|
||||||
};
|
|
||||||
|
|
||||||
return TextNodeType;
|
|
||||||
|
|
||||||
})(types.ImmutableObject);
|
|
||||||
parser['TextNodeType'] = function(json) {
|
|
||||||
var content, textnode, uid;
|
|
||||||
uid = json['uid'], content = json['content'];
|
|
||||||
textnode = document.createTextNode(content);
|
|
||||||
return new TextNodeType(uid, textnode);
|
|
||||||
};
|
|
||||||
types['XmlType'] = XmlType;
|
|
||||||
return json_types;
|
|
||||||
};
|
};
|
||||||
|
|||||||
+304
-36
@@ -1,78 +1,131 @@
|
|||||||
var YXml;
|
var YXml, dont_proxy, initialize_proxies, proxies_are_initialized, proxy_token;
|
||||||
|
|
||||||
YXml = (function() {
|
YXml = (function() {
|
||||||
function YXml(tagname, attributes) {
|
function YXml(tag_or_dom, attributes) {
|
||||||
var a, a_name, c, c_name, _classes, _i, _len, _ref;
|
var a, a_name, c, c_name, tagname, _classes, _i, _len, _ref;
|
||||||
if (attributes == null) {
|
if (attributes == null) {
|
||||||
attributes = {};
|
attributes = {};
|
||||||
}
|
}
|
||||||
this._xml = {};
|
if (tag_or_dom == null) {
|
||||||
this._xml.tagname = tagname;
|
|
||||||
if (attributes.constructor !== Object) {
|
} else if (tag_or_dom.constructor === String) {
|
||||||
throw new Error("The attributes must be specified as a Object");
|
tagname = tag_or_dom;
|
||||||
}
|
this._xml = {};
|
||||||
for (a_name in attributes) {
|
this._xml.children = [];
|
||||||
a = attributes[a_name];
|
this._xml.tagname = tagname;
|
||||||
if (a.constructor !== String) {
|
if (attributes.constructor !== Object) {
|
||||||
throw new Error("The attributes must be of type String!");
|
throw new Error("The attributes must be specified as a Object");
|
||||||
}
|
}
|
||||||
}
|
for (a_name in attributes) {
|
||||||
this._xml.attributes = attributes;
|
a = attributes[a_name];
|
||||||
this._xml.classes = {};
|
if (a.constructor !== String) {
|
||||||
_classes = this._xml.attributes["class"];
|
throw new Error("The attributes must be of type String!");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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 = {};
|
||||||
}
|
}
|
||||||
void 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
YXml.prototype._name = "Xml";
|
YXml.prototype._name = "Xml";
|
||||||
|
|
||||||
YXml.prototype._getModel = function(Y, ops) {
|
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._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 = new ops.MapManager(this).execute();
|
||||||
this._model.val("attributes", new Y.Object(this._xml.attributes));
|
this._model.val("attributes", new Y.Object(this._xml.attributes));
|
||||||
this._model.val("classes", new Y.Object(this._xml.classes));
|
this._model.val("classes", new Y.Object(this._xml.classes));
|
||||||
this._model.val("tagname", this._xml.tagname);
|
this._model.val("tagname", this._xml.tagname);
|
||||||
this._model.val("children", new Y.List());
|
this._model.val("children", new Y.List(this._xml.children));
|
||||||
if (this._xml.parent != null) {
|
if (this._xml.parent != null) {
|
||||||
this._model.val("parent", this._xml.parent);
|
this._model.val("parent", this._xml.parent);
|
||||||
}
|
}
|
||||||
|
if (this._dom != null) {
|
||||||
|
this.getDom();
|
||||||
|
}
|
||||||
|
this._setModel(this._model);
|
||||||
}
|
}
|
||||||
this._setModel(this._model);
|
|
||||||
return this._model;
|
return this._model;
|
||||||
};
|
};
|
||||||
|
|
||||||
YXml.prototype._setModel = function(_at__model) {
|
YXml.prototype._setModel = function(_at__model) {
|
||||||
this._model = _at__model;
|
this._model = _at__model;
|
||||||
delete this._xml;
|
this._model.observe(function(events) {
|
||||||
return this._model.observe(function(events) {
|
var c, children, event, i, parent, _i, _len, _ref, _results;
|
||||||
var c, children, event, i, parent, _i, _j, _len, _len1, _ref;
|
_results = [];
|
||||||
for (_i = 0, _len = events.length; _i < _len; _i++) {
|
for (_i = 0, _len = events.length; _i < _len; _i++) {
|
||||||
event = events[_i];
|
event = events[_i];
|
||||||
if (event.name === "parent" && event.type !== "add") {
|
if (event.name === "parent" && event.type !== "add") {
|
||||||
parent = event.oldValue;
|
parent = event.oldValue;
|
||||||
children = (_ref = parent._model.val("children")) != null ? _ref.val() : void 0;
|
children = (_ref = parent._model.val("children")) != null ? _ref.val() : void 0;
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
for (i = _j = 0, _len1 = children.length; _j < _len1; i = ++_j) {
|
_results.push((function() {
|
||||||
c = children[i];
|
var _j, _len1, _results1;
|
||||||
if (c === this) {
|
_results1 = [];
|
||||||
parent._model.val("children")["delete"](i);
|
for (i = _j = 0, _len1 = children.length; _j < _len1; i = ++_j) {
|
||||||
break;
|
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 void 0;
|
return _results;
|
||||||
});
|
});
|
||||||
|
return delete this._xml;
|
||||||
};
|
};
|
||||||
|
|
||||||
YXml.prototype._setParent = function(parent) {
|
YXml.prototype._setParent = function(parent) {
|
||||||
@@ -294,10 +347,225 @@ YXml = (function() {
|
|||||||
return this._model.val("children").val();
|
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, 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") {
|
||||||
|
newNode = event.value.getDom();
|
||||||
|
children = that._dom.childNodes;
|
||||||
|
if (children.length > 0) {
|
||||||
|
rightNode = children[0];
|
||||||
|
} else {
|
||||||
|
rightNode = null;
|
||||||
|
}
|
||||||
|
event.value._setParent(that);
|
||||||
|
_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;
|
||||||
|
});
|
||||||
|
this._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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this._dom;
|
||||||
|
};
|
||||||
|
|
||||||
return YXml;
|
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 insertBefore, removeChild, replaceChild, that, _proxy;
|
||||||
|
_proxy = function(f_name, f, source) {
|
||||||
|
var old_f;
|
||||||
|
if (source == null) {
|
||||||
|
source = Element.prototype;
|
||||||
|
}
|
||||||
|
old_f = source[f_name];
|
||||||
|
return source[f_name] = function() {
|
||||||
|
if ((this._y_xml == null) || proxy_token) {
|
||||||
|
return old_f.apply(this, arguments);
|
||||||
|
} else {
|
||||||
|
return f.apply(this._y_xml, arguments);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
that = this;
|
||||||
|
this._dom.classList.add = function(c) {
|
||||||
|
return that.addClass(c);
|
||||||
|
};
|
||||||
|
this._dom.classList.remove = function(c) {
|
||||||
|
return that.removeClass(c);
|
||||||
|
};
|
||||||
|
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, this._dom);
|
||||||
|
replaceChild = function(insertedNode, replacedNode) {
|
||||||
|
insertBefore.call(this, insertedNode, replacedNode);
|
||||||
|
return removeChild.call(this, replacedNode);
|
||||||
|
};
|
||||||
|
return _proxy('replaceChild', replaceChild, this._dom);
|
||||||
|
};
|
||||||
|
|
||||||
if (typeof window !== "undefined" && window !== null) {
|
if (typeof window !== "undefined" && window !== null) {
|
||||||
if (window.Y != null) {
|
if (window.Y != null) {
|
||||||
window.Y.Xml = YXml;
|
window.Y.Xml = YXml;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+9774
-78
File diff suppressed because one or more lines are too long
@@ -2,7 +2,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Test Yjs!</title>
|
<title>Test Yjs!</title>
|
||||||
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
|
<link rel="stylesheet" href="../../node_modules/mocha/mocha.css" />
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="mocha"></div>
|
<div id="mocha"></div>
|
||||||
|
|||||||
@@ -487,6 +487,7 @@ module.exports = ()->
|
|||||||
object: @parent.getCustomType() # TODO: You can combine getPosition + getParent in a more efficient manner! (only left Delimiter will hold @parent)
|
object: @parent.getCustomType() # TODO: You can combine getPosition + getParent in a more efficient manner! (only left Delimiter will hold @parent)
|
||||||
length: 1
|
length: 1
|
||||||
changedBy: o.uid.creator
|
changedBy: o.uid.creator
|
||||||
|
oldValue: @val()
|
||||||
]
|
]
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,34 +1,7 @@
|
|||||||
|
|
||||||
json_types_uninitialized = require "./JsonTypes"
|
json_types_uninitialized = require "./JsonTypes"
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
_proxy = (f_name, f)->
|
|
||||||
old_f = @[f_name]
|
|
||||||
if old_f?
|
|
||||||
@[f_name] = ()->
|
|
||||||
if not proxy_token and not @_y?.isDeleted()
|
|
||||||
that = this
|
|
||||||
args = arguments
|
|
||||||
dont_proxy ()->
|
|
||||||
f.apply that, args
|
|
||||||
old_f.apply that, args
|
|
||||||
else
|
|
||||||
old_f.apply this, arguments
|
|
||||||
#else
|
|
||||||
# @[f_name] = f
|
|
||||||
Element?.prototype._proxy = _proxy
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = (HB)->
|
module.exports = (HB)->
|
||||||
@@ -46,202 +19,10 @@ module.exports = (HB)->
|
|||||||
class XmlType extends types.Insert
|
class XmlType extends types.Insert
|
||||||
|
|
||||||
constructor: (uid, @tagname, attributes, elements, @xml)->
|
constructor: (uid, @tagname, attributes, elements, @xml)->
|
||||||
### In case you make this instanceof Insert again
|
|
||||||
if prev? and (not next?) and prev.type?
|
|
||||||
# adjust what you actually mean. you want to insert after prev, then
|
|
||||||
# next is not defined. but we only insert after non-deleted elements.
|
|
||||||
# This is also handled in TextInsert.
|
|
||||||
while prev.isDeleted()
|
|
||||||
prev = prev.prev_cl
|
|
||||||
next = prev.next_cl
|
|
||||||
###
|
|
||||||
|
|
||||||
super(uid)
|
|
||||||
|
|
||||||
|
|
||||||
if @xml?._y?
|
|
||||||
d = new types.Delete undefined, @xml._y
|
|
||||||
HB.addOperation(d).execute()
|
|
||||||
@xml._y = null
|
|
||||||
|
|
||||||
if attributes? and elements?
|
|
||||||
@saveOperation 'attributes', attributes
|
|
||||||
@saveOperation 'elements', elements
|
|
||||||
else if (not attributes?) and (not elements?)
|
|
||||||
@attributes = new types.JsonType()
|
|
||||||
@attributes.setMutableDefault 'immutable'
|
|
||||||
HB.addOperation(@attributes).execute()
|
|
||||||
@elements = new types.WordType()
|
|
||||||
@elements.parent = @
|
|
||||||
HB.addOperation(@elements).execute()
|
|
||||||
else
|
|
||||||
throw new Error "Either define attribute and elements both, or none of them"
|
|
||||||
|
|
||||||
if @xml?
|
|
||||||
@tagname = @xml.tagName
|
|
||||||
for i in [0...@xml.attributes.length]
|
|
||||||
attr = xml.attributes[i]
|
|
||||||
@attributes.val(attr.name, attr.value)
|
|
||||||
for n in @xml.childNodes
|
|
||||||
if n.nodeType is n.TEXT_NODE
|
|
||||||
word = new TextNodeType(undefined, n)
|
|
||||||
HB.addOperation(word).execute()
|
|
||||||
@elements.push word
|
|
||||||
else if n.nodeType is n.ELEMENT_NODE
|
|
||||||
element = new XmlType undefined, undefined, undefined, undefined, n
|
|
||||||
HB.addOperation(element).execute()
|
|
||||||
@elements.push element
|
|
||||||
else
|
|
||||||
throw new Error "I don't know Node-type #{n.nodeType}!!"
|
|
||||||
@setXmlProxy()
|
|
||||||
undefined
|
|
||||||
|
|
||||||
#
|
|
||||||
# Identifies this class.
|
|
||||||
# Use it in order to check whether this is an xml-type or something else.
|
|
||||||
#
|
|
||||||
type: "XmlType"
|
|
||||||
|
|
||||||
applyDelete: (op)->
|
|
||||||
if @insert_parent? and not @insert_parent.isDeleted()
|
|
||||||
@insert_parent.applyDelete op
|
|
||||||
else
|
|
||||||
@attributes.applyDelete()
|
|
||||||
@elements.applyDelete()
|
|
||||||
super
|
|
||||||
|
|
||||||
cleanup: ()->
|
|
||||||
super()
|
|
||||||
|
|
||||||
setXmlProxy: ()->
|
setXmlProxy: ()->
|
||||||
@xml._y = @
|
|
||||||
that = @
|
|
||||||
|
|
||||||
@elements.on 'insert', (event, op)->
|
|
||||||
if op.creator isnt HB.getUserId() and this is that.elements
|
|
||||||
newNode = op.content.val()
|
|
||||||
right = op.next_cl
|
|
||||||
while right? and right.isDeleted()
|
|
||||||
right = right.next_cl
|
|
||||||
rightNode = null
|
|
||||||
if right.type isnt 'Delimiter'
|
|
||||||
rightNode = right.val().val()
|
|
||||||
dont_proxy ()->
|
|
||||||
that.xml.insertBefore newNode, rightNode
|
|
||||||
@elements.on 'delete', (event, op)->
|
|
||||||
del_op = op.deleted_by[0]
|
|
||||||
if del_op? and del_op.creator isnt HB.getUserId() and this is that.elements
|
|
||||||
deleted = op.content.val()
|
|
||||||
dont_proxy ()->
|
|
||||||
that.xml.removeChild deleted
|
|
||||||
|
|
||||||
@attributes.on ['add', 'update'], (event, property_name, op)->
|
|
||||||
if op.creator isnt HB.getUserId() and this is that.attributes
|
|
||||||
dont_proxy ()->
|
|
||||||
newval = op.val().val()
|
|
||||||
if newval?
|
|
||||||
that.xml.setAttribute(property_name, op.val().val())
|
|
||||||
else
|
|
||||||
that.xml.removeAttribute(property_name)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Here are all methods that proxy the behavior of the xml
|
|
||||||
|
|
||||||
# you want to find a specific child element. Since they are carried by an Insert-Type, you want to find that Insert-Operation.
|
|
||||||
# @param child {DomElement} Dom element.
|
|
||||||
# @return {InsertType} This carries the XmlType that represents the DomElement (child). false if i couldn't find it.
|
|
||||||
#
|
|
||||||
findNode = (child)->
|
|
||||||
if not child?
|
|
||||||
throw new Error "you must specify a parameter!"
|
|
||||||
child = child._y
|
|
||||||
elem = that.elements.beginning.next_cl
|
|
||||||
while elem.type isnt 'Delimiter' and elem.content isnt child
|
|
||||||
elem = elem.next_cl
|
|
||||||
if elem.type is 'Delimiter'
|
|
||||||
false
|
|
||||||
else
|
|
||||||
elem
|
|
||||||
|
|
||||||
insertBefore = (insertedNode_s, adjacentNode)->
|
|
||||||
next = null
|
|
||||||
if adjacentNode?
|
|
||||||
next = findNode adjacentNode
|
|
||||||
prev = null
|
|
||||||
if next
|
|
||||||
prev = next.prev_cl
|
|
||||||
else
|
|
||||||
prev = @_y.elements.end.prev_cl
|
|
||||||
while prev.isDeleted()
|
|
||||||
prev = prev.prev_cl
|
|
||||||
inserted_nodes = null
|
|
||||||
if insertedNode_s.nodeType is insertedNode_s.DOCUMENT_FRAGMENT_NODE
|
|
||||||
child = insertedNode_s.lastChild
|
|
||||||
while child?
|
|
||||||
element = new XmlType undefined, undefined, undefined, undefined, child
|
|
||||||
HB.addOperation(element).execute()
|
|
||||||
that.elements.insertAfter prev, element
|
|
||||||
child = child.previousSibling
|
|
||||||
else
|
|
||||||
element = new XmlType undefined, undefined, undefined, undefined, insertedNode_s
|
|
||||||
HB.addOperation(element).execute()
|
|
||||||
that.elements.insertAfter prev, element
|
|
||||||
|
|
||||||
@xml._proxy 'insertBefore', insertBefore
|
|
||||||
@xml._proxy 'appendChild', insertBefore
|
|
||||||
@xml._proxy 'removeAttribute', (name)->
|
|
||||||
that.attributes.val(name, undefined)
|
|
||||||
@xml._proxy 'setAttribute', (name, value)->
|
|
||||||
that.attributes.val name, value
|
|
||||||
|
|
||||||
renewClassList = (newclass)->
|
|
||||||
dont_do_it = false
|
|
||||||
if newclass?
|
|
||||||
for elem in this
|
|
||||||
if newclass is elem
|
|
||||||
dont_do_it = true
|
|
||||||
value = Array.prototype.join.call this, " "
|
|
||||||
if newclass? and not dont_do_it
|
|
||||||
value += " "+newclass
|
|
||||||
that.attributes.val('class', value )
|
|
||||||
_proxy.call @xml.classList, 'add', renewClassList
|
|
||||||
_proxy.call @xml.classList, 'remove', renewClassList
|
|
||||||
@xml.__defineSetter__ 'className', (val)->
|
|
||||||
@setAttribute('class', val)
|
|
||||||
@xml.__defineGetter__ 'className', ()->
|
|
||||||
that.attributes.val('class')
|
|
||||||
@xml.__defineSetter__ 'textContent', (val)->
|
|
||||||
# remove all nodes
|
|
||||||
elem = that.xml.firstChild
|
|
||||||
while elem?
|
|
||||||
remove = elem
|
|
||||||
elem = elem.nextSibling
|
|
||||||
that.xml.removeChild remove
|
|
||||||
|
|
||||||
# insert word content
|
|
||||||
if val isnt ""
|
|
||||||
text_node = document.createTextNode val
|
|
||||||
that.xml.appendChild text_node
|
|
||||||
|
|
||||||
removeChild = (node)->
|
|
||||||
elem = findNode node
|
|
||||||
if not elem
|
|
||||||
throw new Error "You are only allowed to delete existing (direct) child elements!"
|
|
||||||
d = new types.Delete undefined, elem
|
|
||||||
HB.addOperation(d).execute()
|
|
||||||
node._y = null
|
|
||||||
@xml._proxy 'removeChild', removeChild
|
|
||||||
@xml._proxy 'replaceChild', (insertedNode, replacedNode)->
|
|
||||||
insertBefore.call this, insertedNode, replacedNode
|
|
||||||
removeChild.call this, replacedNode
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val: (enforce = false)->
|
val: (enforce = false)->
|
||||||
if document?
|
if document?
|
||||||
@@ -314,53 +95,3 @@ module.exports = (HB)->
|
|||||||
} = json
|
} = json
|
||||||
|
|
||||||
new XmlType uid, tagname, attributes, elements, undefined
|
new XmlType uid, tagname, attributes, elements, undefined
|
||||||
|
|
||||||
#
|
|
||||||
# @nodoc
|
|
||||||
# Defines an object that is cannot be changed. You can use this to set an immutable string, or a number.
|
|
||||||
#
|
|
||||||
class TextNodeType extends types.ImmutableObject
|
|
||||||
|
|
||||||
#
|
|
||||||
# @param {Object} uid A unique identifier. If uid is undefined, a new uid will be created.
|
|
||||||
# @param {Object} content
|
|
||||||
#
|
|
||||||
constructor: (uid, content)->
|
|
||||||
if content._y?
|
|
||||||
d = new types.Delete undefined, content._y
|
|
||||||
HB.addOperation(d).execute()
|
|
||||||
content._y = null
|
|
||||||
content._y = @
|
|
||||||
super uid, content
|
|
||||||
|
|
||||||
applyDelete: (op)->
|
|
||||||
if @insert_parent? and not @insert_parent.isDeleted()
|
|
||||||
@insert_parent.applyDelete op
|
|
||||||
else
|
|
||||||
super
|
|
||||||
|
|
||||||
|
|
||||||
type: "TextNodeType"
|
|
||||||
|
|
||||||
#
|
|
||||||
# Encode this operation in such a way that it can be parsed by remote peers.
|
|
||||||
#
|
|
||||||
_encode: ()->
|
|
||||||
json = {
|
|
||||||
'type': @type
|
|
||||||
'uid' : @getUid()
|
|
||||||
'content' : @content.textContent
|
|
||||||
}
|
|
||||||
json
|
|
||||||
|
|
||||||
parser['TextNodeType'] = (json)->
|
|
||||||
{
|
|
||||||
'uid' : uid
|
|
||||||
'content' : content
|
|
||||||
} = json
|
|
||||||
textnode = document.createTextNode content
|
|
||||||
new TextNodeType uid, textnode
|
|
||||||
|
|
||||||
types['XmlType'] = XmlType
|
|
||||||
|
|
||||||
json_types
|
|
||||||
|
|||||||
+206
-25
@@ -1,42 +1,72 @@
|
|||||||
class YXml
|
class YXml
|
||||||
|
|
||||||
constructor: (tagname, attributes = {})->
|
constructor: (tag_or_dom, attributes = {})->
|
||||||
@_xml = {}
|
if not tag_or_dom?
|
||||||
#TODO: How to force the user to specify parameters?
|
# nop
|
||||||
#if not tagname?
|
else if tag_or_dom.constructor is String
|
||||||
# throw new Error "You must specify a tagname"
|
tagname = tag_or_dom
|
||||||
@_xml.tagname = tagname
|
@_xml = {}
|
||||||
if attributes.constructor isnt Object
|
@_xml.children = []
|
||||||
throw new Error "The attributes must be specified as a Object"
|
#TODO: How to force the user to specify parameters?
|
||||||
for a_name, a of attributes
|
#if not tagname?
|
||||||
if a.constructor isnt String
|
# throw new Error "You must specify a tagname"
|
||||||
throw new Error "The attributes must be of type String!"
|
@_xml.tagname = tagname
|
||||||
@_xml.attributes = attributes
|
if attributes.constructor isnt Object
|
||||||
@_xml.classes = {}
|
throw new Error "The attributes must be specified as a Object"
|
||||||
_classes = @_xml.attributes.class
|
for a_name, a of attributes
|
||||||
delete @_xml.attributes.class
|
if a.constructor isnt String
|
||||||
if _classes?
|
throw new Error "The attributes must be of type String!"
|
||||||
for c_name, c in _classes.split(" ")
|
@_xml.attributes = attributes
|
||||||
if c.length > 0
|
@_xml.classes = {}
|
||||||
@_xml.classes[c_name] = c
|
_classes = @_xml.attributes.class
|
||||||
undefined
|
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"
|
_name: "Xml"
|
||||||
|
|
||||||
_getModel: (Y, ops)->
|
_getModel: (Y, ops)->
|
||||||
if not @_model?
|
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 = new ops.MapManager(@).execute()
|
||||||
@_model.val("attributes", new Y.Object(@_xml.attributes))
|
@_model.val("attributes", new Y.Object(@_xml.attributes))
|
||||||
@_model.val("classes", new Y.Object(@_xml.classes))
|
@_model.val("classes", new Y.Object(@_xml.classes))
|
||||||
@_model.val("tagname", @_xml.tagname)
|
@_model.val("tagname", @_xml.tagname)
|
||||||
@_model.val("children", new Y.List())
|
@_model.val("children", new Y.List(@_xml.children))
|
||||||
if @_xml.parent?
|
if @_xml.parent?
|
||||||
@_model.val("parent", @_xml.parent)
|
@_model.val("parent", @_xml.parent)
|
||||||
@_setModel @_model
|
|
||||||
|
if @_dom?
|
||||||
|
@getDom() # two way bind dom to this xml type
|
||||||
|
|
||||||
|
@_setModel @_model
|
||||||
|
|
||||||
@_model
|
@_model
|
||||||
|
|
||||||
_setModel: (@_model)->
|
_setModel: (@_model)->
|
||||||
delete @_xml
|
|
||||||
@_model.observe (events)->
|
@_model.observe (events)->
|
||||||
for event in events
|
for event in events
|
||||||
if event.name is "parent" and event.type isnt "add"
|
if event.name is "parent" and event.type isnt "add"
|
||||||
@@ -47,8 +77,7 @@ class YXml
|
|||||||
if c is @
|
if c is @
|
||||||
parent._model.val("children").delete i
|
parent._model.val("children").delete i
|
||||||
break
|
break
|
||||||
undefined
|
delete @_xml
|
||||||
|
|
||||||
|
|
||||||
_setParent: (parent)->
|
_setParent: (parent)->
|
||||||
if parent instanceof YXml
|
if parent instanceof YXml
|
||||||
@@ -260,6 +289,158 @@ class YXml
|
|||||||
getChildren: ()->
|
getChildren: ()->
|
||||||
@_model.val("children").val()
|
@_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"
|
||||||
|
newNode = event.value.getDom()
|
||||||
|
children = that._dom.childNodes
|
||||||
|
if children.length > 0
|
||||||
|
rightNode = children[0]
|
||||||
|
else
|
||||||
|
rightNode = null
|
||||||
|
event.value._setParent that
|
||||||
|
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
|
||||||
|
@_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
|
||||||
|
@_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)->
|
||||||
|
old_f = source[f_name]
|
||||||
|
source[f_name] = ()->
|
||||||
|
if (not @_y_xml?) or proxy_token
|
||||||
|
old_f.apply this, arguments
|
||||||
|
else
|
||||||
|
f.apply @_y_xml, arguments
|
||||||
|
|
||||||
|
that = this
|
||||||
|
@_dom.classList.add = (c)->
|
||||||
|
that.addClass c
|
||||||
|
@_dom.classList.remove = (c)->
|
||||||
|
that.removeClass c
|
||||||
|
|
||||||
|
@_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, @_dom
|
||||||
|
replaceChild = (insertedNode, replacedNode)->
|
||||||
|
insertBefore.call this, insertedNode, replacedNode
|
||||||
|
removeChild.call this, replacedNode
|
||||||
|
_proxy 'replaceChild', replaceChild, @_dom
|
||||||
|
|
||||||
if window?
|
if window?
|
||||||
if window.Y?
|
if window.Y?
|
||||||
|
|||||||
+222
-9
@@ -4,6 +4,7 @@ should = chai.should()
|
|||||||
sinon = require('sinon')
|
sinon = require('sinon')
|
||||||
sinonChai = require('sinon-chai')
|
sinonChai = require('sinon-chai')
|
||||||
_ = require("underscore")
|
_ = require("underscore")
|
||||||
|
$ = require('jquery')
|
||||||
|
|
||||||
chai.use(sinonChai)
|
chai.use(sinonChai)
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ class XmlTest extends Test
|
|||||||
super new Y conn
|
super new Y conn
|
||||||
|
|
||||||
initUsers: (u)->
|
initUsers: (u)->
|
||||||
u.val("xml",new Y.Xml("root"))
|
u.val("xml",new Y.Xml("div"))
|
||||||
|
|
||||||
type: "XmlTest"
|
type: "XmlTest"
|
||||||
|
|
||||||
@@ -175,7 +176,7 @@ describe "Y-Xml", ->
|
|||||||
child2 = new Y.Xml("child2")
|
child2 = new Y.Xml("child2")
|
||||||
@u1.append child
|
@u1.append child
|
||||||
@u1.append child2
|
@u1.append child2
|
||||||
expect(@u1.toString()).to.equal("<root><child></child><child2></child2></root>")
|
expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
|
|
||||||
it "prepend", ->
|
it "prepend", ->
|
||||||
@@ -183,31 +184,31 @@ describe "Y-Xml", ->
|
|||||||
child2 = new Y.Xml("child2")
|
child2 = new Y.Xml("child2")
|
||||||
@u1.prepend child2
|
@u1.prepend child2
|
||||||
@u1.prepend child
|
@u1.prepend child
|
||||||
expect(@u1.toString()).to.equal("<root><child></child><child2></child2></root>")
|
expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
|
|
||||||
it "after", ->
|
it "after", ->
|
||||||
child = new Y.Xml("child")
|
child = new Y.Xml("child")
|
||||||
@u1.append child
|
@u1.append child
|
||||||
child.after new Y.Xml("right-child")
|
child.after new Y.Xml("right-child")
|
||||||
expect(@u1.toString()).to.equal("<root><child></child><right-child></right-child></root>")
|
expect(@u1.toString()).to.equal("<div><child></child><right-child></right-child></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
|
|
||||||
it "before", ->
|
it "before", ->
|
||||||
child = new Y.Xml("child")
|
child = new Y.Xml("child")
|
||||||
@u1.append child
|
@u1.append child
|
||||||
child.before new Y.Xml("left-child")
|
child.before new Y.Xml("left-child")
|
||||||
expect(@u1.toString()).to.equal("<root><left-child></left-child><child></child></root>")
|
expect(@u1.toString()).to.equal("<div><left-child></left-child><child></child></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
|
|
||||||
it "empty", ->
|
it "empty", ->
|
||||||
child = new Y.Xml("child")
|
child = new Y.Xml("child")
|
||||||
@u1.append child
|
@u1.append child
|
||||||
child.before new Y.Xml("left-child")
|
child.before new Y.Xml("left-child")
|
||||||
expect(@u1.toString()).to.equal("<root><left-child></left-child><child></child></root>")
|
expect(@u1.toString()).to.equal("<div><left-child></left-child><child></child></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
@u1.empty()
|
@u1.empty()
|
||||||
expect(@u1.toString()).to.equal("<root></root>")
|
expect(@u1.toString()).to.equal("<div></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
|
|
||||||
it "remove", ->
|
it "remove", ->
|
||||||
@@ -215,10 +216,10 @@ describe "Y-Xml", ->
|
|||||||
child2 = new Y.Xml("child2")
|
child2 = new Y.Xml("child2")
|
||||||
@u1.prepend child2
|
@u1.prepend child2
|
||||||
@u1.prepend child
|
@u1.prepend child
|
||||||
expect(@u1.toString()).to.equal("<root><child></child><child2></child2></root>")
|
expect(@u1.toString()).to.equal("<div><child></child><child2></child2></div>")
|
||||||
@yTest.compareAll()
|
@yTest.compareAll()
|
||||||
child2.remove()
|
child2.remove()
|
||||||
expect(@u1.toString()).to.equal("<root><child></child></root>")
|
expect(@u1.toString()).to.equal("<div><child></child></div>")
|
||||||
|
|
||||||
it "removeAttr", ->
|
it "removeAttr", ->
|
||||||
@u1.attr("dtrn", "stuff")
|
@u1.attr("dtrn", "stuff")
|
||||||
@@ -258,4 +259,216 @@ describe "Y-Xml", ->
|
|||||||
@u1.prepend(child)
|
@u1.prepend(child)
|
||||||
expect(@u1.getChildren()[0]).to.equal(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
|
||||||
|
expect(@dom.getAttribute("test_attribute")).to.be.undefined
|
||||||
|
|
||||||
|
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(newdom)
|
||||||
|
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(dom,newdom)
|
||||||
|
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(newdom)
|
||||||
|
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(newdom)
|
||||||
|
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("testy")
|
||||||
|
@j.addClass("testedy tested")
|
||||||
|
expect(@dom.getAttribute("class")).to.equal("testy 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]
|
||||||
|
@dom.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)
|
||||||
|
$j.detach("p")
|
||||||
|
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>after</p>").insertAfter(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("testy")
|
||||||
|
@j.addClass("testedy tested")
|
||||||
|
expect(@dom.getAttribute("class")).to.equal("testy testedy tested")
|
||||||
|
|
||||||
|
@j.removeClass("testedy")
|
||||||
|
expect(@dom.getAttribute("class")).to.equal("testy tested")
|
||||||
|
expect(@u1.hasClass("testedy")).to.be.false
|
||||||
|
|
||||||
|
it "supports jquery.attr", ->
|
||||||
|
@j.attr("atone", "yeah")
|
||||||
|
expect(@u1.attr("atone")).to.equal("yeah")
|
||||||
|
|
||||||
|
it "supports jquery.replaceAll", ->
|
||||||
|
$("<span>New span content </span>").replaceAll("#test_dom div")
|
||||||
|
@check()
|
||||||
|
|
||||||
|
it "supports jquery.replaceWith", ->
|
||||||
|
d = $("span")
|
||||||
|
@j.prepend(d)
|
||||||
|
d = $("span")
|
||||||
|
@j.prepend(d)
|
||||||
|
d = $("span")
|
||||||
|
@j.prepend(d)
|
||||||
|
d = @j.getElementsByTagName("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
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user