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 append: function(documentNode) {
75 this._$.append(documentNode.nativeNode);
78 unwrapContent: function() {
79 var parent = this.parent();
83 var parentContents = parent.contents(),
84 myContents = this.contents(),
85 myIdx = parent.indexOf(this);
87 if(myContents.length === 0)
90 var moveLeftRange, moveRightRange, leftMerged;
92 if(myIdx > 0 && (parentContents[myIdx-1].nodeType === TEXT_NODE) && (myContents[0].nodeType === TEXT_NODE)) {
93 parentContents[myIdx-1].appendText(myContents[0].getText());
94 myContents[0].detach();
101 if(!(leftMerged && myContents.length === 1)) {
102 if(myIdx < parentContents.length - 1 && (parentContents[myIdx+1].nodeType === TEXT_NODE) && (myContents[myContents.length-1].nodeType === TEXT_NODE)) {
103 parentContents[myIdx+1].prependText(myContents[myContents.length-1].getText());
104 myContents[myContents.length-1].detach();
105 moveRightRange = true;
109 var childrenLength = this.contents().length;
110 this.contents().forEach(function(child) {
117 element1: parent.contents()[myIdx + (moveLeftRange ? -1 : 0)],
118 element2: parent.contents()[myIdx + childrenLength-1 + (moveRightRange ? 1 : 0)]
124 var TextNode = function(nativeNode) {
125 DocumentNode.apply(this, arguments);
128 $.extend(TextNode.prototype, DocumentNode.prototype, {
129 nodeType: Node.TEXT_NODE,
131 getText: function() {
132 return this.nativeNode.data;
135 appendText: function(text) {
136 this.nativeNode.data = this.nativeNode.data + text;
139 prependText: function(text) {
140 this.nativeNode.data = text + this.nativeNode.data;
145 var parseXML = function(xml) {
149 var Document = function(xml) {
150 var $document = $(parseXML(xml));
153 Object.defineProperty(this, 'root', {get: function() {
154 return doc.createElementNode($document[0]);
157 $.extend(Document.prototype, {
158 ElementNodeFactory: ElementNode,
159 TextNodeFactory: TextNode,
161 createElementNode: function(nativeNode) {
162 return new this.ElementNodeFactory(nativeNode, this);
165 createTextNode: function(nativeNode) {
166 return new this.TextNodeFactory(nativeNode, this);
172 documentFromXML: function(xml) {
173 return new Document(parseXML(xml));
176 elementNodeFromXML: function(xml) {
177 return this.documentFromXML(xml).root;
181 DocumentNode: DocumentNode,
182 ElementNode: ElementNode