8 var TEXT_NODE = Node.TEXT_NODE, ELEMENT_NODE = Node.ELEMENT_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) {
39 var ElementNode = function(nativeNode) {
40 DocumentNode.apply(this, arguments);
43 $.extend(ElementNode.prototype, DocumentNode.prototype, {
44 nodeType: Node.ELEMENT_NODE,
46 getTagName: function() {
47 return this.nativeNode.tagName.toLowerCase();
50 contents: function() {
52 document = this.document;
53 this._$.contents().each(function() {
54 if(this.nodeType === Node.ELEMENT_NODE)
55 toret.push(document.createElementNode(this));
56 else if(this.nodeType === Node.TEXT_NODE)
57 toret.push(document.createTextNode(this));
62 indexOf: function(node) {
63 return this._$.contents().index(node._$);
66 getAttr: function(name) {
67 return this._$.attr(name);
70 setAttr: function(name, value) {
71 this._$.attr(name, value);
74 getAttrs: function() {
76 for(var i = 0; i < this.nativeNode.attributes.length; i++) {
77 toret.push(this.nativeNode.attributes[i]);
82 append: function(documentNode) {
83 this._$.append(documentNode.nativeNode);
86 unwrapContent: function() {
87 var parent = this.parent();
91 var parentContents = parent.contents(),
92 myContents = this.contents(),
93 myIdx = parent.indexOf(this);
95 if(myContents.length === 0)
98 var moveLeftRange, moveRightRange, leftMerged;
100 if(myIdx > 0 && (parentContents[myIdx-1].nodeType === TEXT_NODE) && (myContents[0].nodeType === TEXT_NODE)) {
101 parentContents[myIdx-1].appendText(myContents[0].getText());
102 myContents[0].detach();
103 moveLeftRange = true;
109 if(!(leftMerged && myContents.length === 1)) {
110 if(myIdx < parentContents.length - 1 && (parentContents[myIdx+1].nodeType === TEXT_NODE) && (myContents[myContents.length-1].nodeType === TEXT_NODE)) {
111 parentContents[myIdx+1].prependText(myContents[myContents.length-1].getText());
112 myContents[myContents.length-1].detach();
113 moveRightRange = true;
117 var childrenLength = this.contents().length;
118 this.contents().forEach(function(child) {
125 element1: parent.contents()[myIdx + (moveLeftRange ? -1 : 0)],
126 element2: parent.contents()[myIdx + childrenLength-1 + (moveRightRange ? 1 : 0)]
132 var TextNode = function(nativeNode) {
133 DocumentNode.apply(this, arguments);
136 $.extend(TextNode.prototype, DocumentNode.prototype, {
137 nodeType: Node.TEXT_NODE,
139 getText: function() {
140 return this.nativeNode.data;
143 appendText: function(text) {
144 this.nativeNode.data = this.nativeNode.data + text;
147 prependText: function(text) {
148 this.nativeNode.data = text + this.nativeNode.data;
153 var parseXML = function(xml) {
157 var Document = function(xml) {
158 var $document = $(parseXML(xml));
161 Object.defineProperty(this, 'root', {get: function() {
162 return doc.createElementNode($document[0]);
165 $.extend(Document.prototype, {
166 ElementNodeFactory: ElementNode,
167 TextNodeFactory: TextNode,
169 createElementNode: function(nativeNode) {
170 return new this.ElementNodeFactory(nativeNode, this);
173 createTextNode: function(nativeNode) {
174 return new this.TextNodeFactory(nativeNode, this);
180 documentFromXML: function(xml) {
181 return new Document(parseXML(xml));
184 elementNodeFromXML: function(xml) {
185 return this.documentFromXML(xml).root;
189 DocumentNode: DocumentNode,
190 ElementNode: ElementNode