8 var TEXT_NODE = Node.TEXT_NODE;
11 var DocumentNode = function(nativeNode, document) {
13 throw new Error('undefined document for a node');
15 this.document = document;
16 this.nativeNode = nativeNode;
17 this._$ = $(nativeNode);
20 $.extend(DocumentNode.prototype, {
21 detach: function() { this._$.detach(); },
23 sameNode: function(otherNode) {
24 return this.nativeNode === otherNode.nativeNode;
28 return this.nativeNode.parentNode ? this.document.createElementNode(this.nativeNode.parentNode) : null;
31 before: function(node) {
32 this._$.before(node.nativeNode);
35 wrapWith: function(node) {
43 var ElementNode = function(nativeNode, document) {
44 DocumentNode.call(this, nativeNode, document);
47 $.extend(ElementNode.prototype, DocumentNode.prototype, {
48 nodeType: Node.ELEMENT_NODE,
50 getTagName: function() {
51 return this.nativeNode.tagName.toLowerCase();
54 contents: function() {
56 document = this.document;
57 this._$.contents().each(function() {
58 if(this.nodeType === Node.ELEMENT_NODE) {
59 toret.push(document.createElementNode(this));
61 else if(this.nodeType === Node.TEXT_NODE) {
62 toret.push(document.createTextNode(this));
68 indexOf: function(node) {
69 return this._$.contents().index(node._$);
72 getAttr: function(name) {
73 return this._$.attr(name);
76 setAttr: function(name, value) {
77 this._$.attr(name, value);
80 getAttrs: function() {
82 for(var i = 0; i < this.nativeNode.attributes.length; i++) {
83 toret.push(this.nativeNode.attributes[i]);
88 append: function(documentNode) {
89 this._$.append(documentNode.nativeNode);
92 unwrapContent: function() {
93 var parent = this.parent();
98 var parentContents = parent.contents(),
99 myContents = this.contents(),
100 myIdx = parent.indexOf(this);
102 if(myContents.length === 0) {
103 return this.detach();
106 var moveLeftRange, moveRightRange, leftMerged;
108 if(myIdx > 0 && (parentContents[myIdx-1].nodeType === TEXT_NODE) && (myContents[0].nodeType === TEXT_NODE)) {
109 parentContents[myIdx-1].appendText(myContents[0].getText());
110 myContents[0].detach();
111 moveLeftRange = true;
117 if(!(leftMerged && myContents.length === 1)) {
118 if(myIdx < parentContents.length - 1 && (parentContents[myIdx+1].nodeType === TEXT_NODE) && (myContents[myContents.length-1].nodeType === TEXT_NODE)) {
119 parentContents[myIdx+1].prependText(myContents[myContents.length-1].getText());
120 myContents[myContents.length-1].detach();
121 moveRightRange = true;
125 var childrenLength = this.contents().length;
126 this.contents().forEach(function(child) {
133 element1: parent.contents()[myIdx + (moveLeftRange ? -1 : 0)],
134 element2: parent.contents()[myIdx + childrenLength-1 + (moveRightRange ? 1 : 0)]
139 var wrapper = $('<div>');
140 wrapper.append(this._$);
141 return wrapper.html();
145 var TextNode = function(nativeNode, document) {
146 DocumentNode.call(this, nativeNode, document);
149 $.extend(TextNode.prototype, DocumentNode.prototype, {
150 nodeType: Node.TEXT_NODE,
152 getText: function() {
153 return this.nativeNode.data;
156 appendText: function(text) {
157 this.nativeNode.data = this.nativeNode.data + text;
160 prependText: function(text) {
161 this.nativeNode.data = text + this.nativeNode.data;
166 var parseXML = function(xml) {
170 var Document = function(xml) {
171 var $document = $(parseXML(xml));
174 Object.defineProperty(this, 'root', {get: function() {
175 return doc.createElementNode($document[0]);
178 $.extend(Document.prototype, {
179 ElementNodeFactory: ElementNode,
180 TextNodeFactory: TextNode,
182 createElementNode: function(nativeNode) {
183 return new this.ElementNodeFactory(nativeNode, this);
186 createTextNode: function(nativeNode) {
187 return new this.TextNodeFactory(nativeNode, this);
191 return this.root.toXML();
197 documentFromXML: function(xml) {
198 return new Document(parseXML(xml));
201 elementNodeFromXML: function(xml) {
202 return this.documentFromXML(xml).root;
206 DocumentNode: DocumentNode,
207 ElementNode: ElementNode