/* globals Node */
+var privateKey = '_smartxml';
+
var DocumentNode = function(nativeNode, document) {
if(!document) {
throw new Error('undefined document for a node');
clone.find('*').addBack().each(function() {
var el = this,
clonedData = $(this).data();
-
+ $(el).removeData(privateKey);
_.pairs(clonedData).forEach(function(pair) {
var key = pair[0],
value = pair[1];
},
getIndex: function() {
+ var parent;
+
if(this.isRoot()) {
return 0;
}
- return this.parent().indexOf(this);
+
+ parent = this.parent();
+ return parent ? parent.indexOf(this) : undefined;
},
getNearestElementNode: function() {
var ElementNode = function(nativeNode, document) {
DocumentNode.call(this, nativeNode, document);
+ $(nativeNode).data(privateKey, {node: this});
};
ElementNode.prototype = Object.create(DocumentNode.prototype);
if(key) {
return this._$.data(key);
}
- return this._$.data();
+ var toret = _.clone(this._$.data());
+ delete toret[privateKey];
+ return toret;
},
getTagName: function() {
return node && (node.nativeNode === this.nativeNode || node._$.parents().index(this._$) !== -1);
},
+ getFirstTextNode: function() {
+ return this._getTextNode('first');
+ },
+
getLastTextNode: function() {
+ return this._getTextNode('last');
+ },
+
+ _getTextNode: function(which) {
var contents = this.contents(),
toret;
-
- contents.reverse().some(function(node) {
+ if(which === 'last') {
+ contents = contents.reverse();
+ }
+ contents.some(function(node) {
if(node.nodeType === Node.TEXT_NODE) {
toret = node;
return true;
var TextNode = function(nativeNode, document) {
DocumentNode.call(this, nativeNode, document);
+ this._data = Object.create({});
+ nativeNode.__smartxmlTextNodeInstance = this;
};
TextNode.prototype = Object.create(DocumentNode.prototype);
$.extend(TextNode.prototype, {
nodeType: Node.TEXT_NODE,
+ setData: function(arg1, arg2) {
+ if(arguments.length === 2) {
+ if(_.isUndefined(arg2)) {
+ delete this._data[arg1];
+ } else {
+ this._data[arg1] = arg2;
+ }
+ } else {
+ this._data = _.extend({}, arg1);
+ }
+ },
+
+ getData: function(key) {
+ if(key) {
+ return this._data[key];
+ }
+ return this._data;
+ },
+
getText: function() {
return this.nativeNode.data;
},
var parseXML = function(xml) {
var toret = $($.trim(xml));
- if(!toret.length) {
+ if(toret.length !== 1) {
throw new Error('Unable to parse XML: ' + xml);
}
return toret[0];
TextNodeFactory: TextNode,
createDocumentNode: function(from) {
- if(!(from instanceof Node)) {
+ var cached;
+
+ if(from instanceof Node) {
+ /* globals Text */
+ cached = from instanceof Text ? from.__smartxmlTextNodeInstance : ($(from).data(privateKey) || {}).node;
+ if(cached instanceof DocumentNode) {
+ return cached;
+ }
+ } else {
if(typeof from === 'string') {
from = parseXML(from);
this.normalizeXML(from);
if(transformations.length > 1) {
// In case of real transactions we don't want to run undo on all of transformations if we don't have to.
- stopAt = undefined;
transformations.some(function(t, idx) {
if(!t.undo && t.getChangeRoot().sameNode(doc.root)) {
stopAt = idx;
getNodeByPath: function(path) {
var toret = this.root;
- path.forEach(function(idx) {
+ path.some(function(idx) {
toret = toret.contents()[idx];
+ if(!toret) {
+ return true;
+ }
});
return toret;
},