8 var TEXT_NODE = Node.TEXT_NODE, ELEMENT_NODE = Node.ELEMENT_NODE;
10 var parseXML = function(xml) {
14 var Document = function(nativeNode) {
15 var $document = $(nativeNode);
18 Object.defineProperty(this, 'root', {get: function() { return new ElementNode($document[0]);}});
22 var DocumentNode = function(nativeNode) {
23 this.nativeNode = nativeNode;
24 this._$ = $(nativeNode);
27 $.extend(DocumentNode.prototype, {
28 detach: function() { this._$.detach(); },
30 sameNode: function(otherNode) {
31 return this.nativeNode === otherNode.nativeNode;
35 var ElementNode = function(nativeNode) {
36 DocumentNode.apply(this, arguments);
39 $.extend(ElementNode.prototype, DocumentNode.prototype, {
40 nodeType: Node.ELEMENT_NODE,
42 getTagName: function() {
43 return this.nativeNode.tagName.toLowerCase();
46 contents: function() {
48 this._$.contents().each(function() {
49 if(this.nodeType === Node.ELEMENT_NODE)
50 toret.push(new ElementNode(this));
51 else if(this.nodeType === Node.TEXT_NODE)
52 toret.push(new TextNode(this));
57 indexOf: function(node) {
58 return this._$.contents().index(node._$);
62 return new ElementNode(this._$.parent());
65 getAttr: function(name) {
66 return this._$.attr(name);
69 setAttr: function(name, value) {
70 this._$.attr(name, value);
73 append: function(documentNode) {
74 this._$.append(documentNode.nativeNode);
77 before: function(node) {
78 this._$.before(node.nativeNode);
81 unwrapContent: function() {
82 var parent = this.parent();
86 var parentContents = parent.contents(),
87 myContents = this.contents(),
88 myIdx = parent.indexOf(this);
90 if(myContents.length === 0)
93 var moveLeftRange, moveRightRange, leftMerged;
95 if(myIdx > 0 && (parentContents[myIdx-1].nodeType === TEXT_NODE) && (myContents[0].nodeType === TEXT_NODE)) {
96 parentContents[myIdx-1].appendText(myContents[0].getText());
97 myContents[0].detach();
104 if(!(leftMerged && myContents.length === 1)) {
105 if(myIdx < parentContents.length - 1 && (parentContents[myIdx+1].nodeType === TEXT_NODE) && (myContents[myContents.length-1].nodeType === TEXT_NODE)) {
106 parentContents[myIdx+1].prependText(myContents[myContents.length-1].getText());
107 myContents[myContents.length-1].detach();
108 moveRightRange = true;
112 var childrenLength = this.contents().length;
113 this.contents().forEach(function(child) {
120 element1: parent.contents()[myIdx + (moveLeftRange ? -1 : 0)],
121 element2: parent.contents()[myIdx + childrenLength-1 + (moveRightRange ? 1 : 0)]
127 var TextNode = function(nativeNode) {
128 DocumentNode.apply(this, arguments);
131 $.extend(TextNode.prototype, DocumentNode.prototype, {
132 nodeType: Node.TEXT_NODE,
134 getText: function() {
135 return this.nativeNode.data;
138 appendText: function(text) {
139 this.nativeNode.data = this.nativeNode.data + text;
142 prependText: function(text) {
143 this.nativeNode.data = text + this.nativeNode.data;
149 documentFromXML: function(xml) {
150 return new Document(parseXML(xml));
153 elementNodeFromXML: function(xml) {
154 return new ElementNode(parseXML(xml));