8 var TEXT_NODE = Node.TEXT_NODE;
11 var DocumentNode = function(nativeNode, document) {
12 this.document = document;
13 this.nativeNode = nativeNode;
14 this._$ = $(nativeNode);
17 $.extend(DocumentNode.prototype, {
18 detach: function() { this._$.detach(); },
20 sameNode: function(otherNode) {
21 return this.nativeNode === otherNode.nativeNode;
25 return this.nativeNode.parentNode ? this.document.createElementNode(this.nativeNode.parentNode) : null;
28 before: function(node) {
29 this._$.before(node.nativeNode);
32 wrapWith: function(node) {
40 var ElementNode = function(nativeNode, document) {
41 DocumentNode.call(this, nativeNode, document);
44 $.extend(ElementNode.prototype, DocumentNode.prototype, {
45 nodeType: Node.ELEMENT_NODE,
47 getTagName: function() {
48 return this.nativeNode.tagName.toLowerCase();
51 contents: function() {
53 document = this.document;
54 this._$.contents().each(function() {
55 if(this.nodeType === Node.ELEMENT_NODE) {
56 toret.push(document.createElementNode(this));
58 else if(this.nodeType === Node.TEXT_NODE) {
59 toret.push(document.createTextNode(this));
65 indexOf: function(node) {
66 return this._$.contents().index(node._$);
69 getAttr: function(name) {
70 return this._$.attr(name);
73 setAttr: function(name, value) {
74 this._$.attr(name, value);
77 getAttrs: function() {
79 for(var i = 0; i < this.nativeNode.attributes.length; i++) {
80 toret.push(this.nativeNode.attributes[i]);
85 append: function(documentNode) {
86 this._$.append(documentNode.nativeNode);
89 unwrapContent: function() {
90 var parent = this.parent();
95 var parentContents = parent.contents(),
96 myContents = this.contents(),
97 myIdx = parent.indexOf(this);
99 if(myContents.length === 0) {
100 return this.detach();
103 var moveLeftRange, moveRightRange, leftMerged;
105 if(myIdx > 0 && (parentContents[myIdx-1].nodeType === TEXT_NODE) && (myContents[0].nodeType === TEXT_NODE)) {
106 parentContents[myIdx-1].appendText(myContents[0].getText());
107 myContents[0].detach();
108 moveLeftRange = true;
114 if(!(leftMerged && myContents.length === 1)) {
115 if(myIdx < parentContents.length - 1 && (parentContents[myIdx+1].nodeType === TEXT_NODE) && (myContents[myContents.length-1].nodeType === TEXT_NODE)) {
116 parentContents[myIdx+1].prependText(myContents[myContents.length-1].getText());
117 myContents[myContents.length-1].detach();
118 moveRightRange = true;
122 var childrenLength = this.contents().length;
123 this.contents().forEach(function(child) {
130 element1: parent.contents()[myIdx + (moveLeftRange ? -1 : 0)],
131 element2: parent.contents()[myIdx + childrenLength-1 + (moveRightRange ? 1 : 0)]
137 var TextNode = function(nativeNode, document) {
138 DocumentNode.call(this, nativeNode, document);
141 $.extend(TextNode.prototype, DocumentNode.prototype, {
142 nodeType: Node.TEXT_NODE,
144 getText: function() {
145 return this.nativeNode.data;
148 appendText: function(text) {
149 this.nativeNode.data = this.nativeNode.data + text;
152 prependText: function(text) {
153 this.nativeNode.data = text + this.nativeNode.data;
158 var parseXML = function(xml) {
162 var Document = function(xml) {
163 var $document = $(parseXML(xml));
166 Object.defineProperty(this, 'root', {get: function() {
167 return doc.createElementNode($document[0]);
170 $.extend(Document.prototype, {
171 ElementNodeFactory: ElementNode,
172 TextNodeFactory: TextNode,
174 createElementNode: function(nativeNode) {
175 return new this.ElementNodeFactory(nativeNode, this);
178 createTextNode: function(nativeNode) {
179 return new this.TextNodeFactory(nativeNode, this);
185 documentFromXML: function(xml) {
186 return new Document(parseXML(xml));
189 elementNodeFromXML: function(xml) {
190 return this.documentFromXML(xml).root;
194 DocumentNode: DocumentNode,
195 ElementNode: ElementNode