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 return this.nativeNode.parentNode ? new ElementNode(this.nativeNode.parentNode) : null;
38 before: function(node) {
39 this._$.before(node.nativeNode);
42 wrapWith: function(node) {
49 var ElementNode = function(nativeNode) {
50 DocumentNode.apply(this, arguments);
53 $.extend(ElementNode.prototype, DocumentNode.prototype, {
54 nodeType: Node.ELEMENT_NODE,
56 getTagName: function() {
57 return this.nativeNode.tagName.toLowerCase();
60 contents: function() {
62 this._$.contents().each(function() {
63 if(this.nodeType === Node.ELEMENT_NODE)
64 toret.push(new ElementNode(this));
65 else if(this.nodeType === Node.TEXT_NODE)
66 toret.push(new TextNode(this));
71 indexOf: function(node) {
72 return this._$.contents().index(node._$);
75 getAttr: function(name) {
76 return this._$.attr(name);
79 setAttr: function(name, value) {
80 this._$.attr(name, value);
83 append: function(documentNode) {
84 this._$.append(documentNode.nativeNode);
87 unwrapContent: function() {
88 var parent = this.parent();
92 var parentContents = parent.contents(),
93 myContents = this.contents(),
94 myIdx = parent.indexOf(this);
96 if(myContents.length === 0)
99 var moveLeftRange, moveRightRange, leftMerged;
101 if(myIdx > 0 && (parentContents[myIdx-1].nodeType === TEXT_NODE) && (myContents[0].nodeType === TEXT_NODE)) {
102 parentContents[myIdx-1].appendText(myContents[0].getText());
103 myContents[0].detach();
104 moveLeftRange = true;
110 if(!(leftMerged && myContents.length === 1)) {
111 if(myIdx < parentContents.length - 1 && (parentContents[myIdx+1].nodeType === TEXT_NODE) && (myContents[myContents.length-1].nodeType === TEXT_NODE)) {
112 parentContents[myIdx+1].prependText(myContents[myContents.length-1].getText());
113 myContents[myContents.length-1].detach();
114 moveRightRange = true;
118 var childrenLength = this.contents().length;
119 this.contents().forEach(function(child) {
126 element1: parent.contents()[myIdx + (moveLeftRange ? -1 : 0)],
127 element2: parent.contents()[myIdx + childrenLength-1 + (moveRightRange ? 1 : 0)]
133 var TextNode = function(nativeNode) {
134 DocumentNode.apply(this, arguments);
137 $.extend(TextNode.prototype, DocumentNode.prototype, {
138 nodeType: Node.TEXT_NODE,
140 getText: function() {
141 return this.nativeNode.data;
144 appendText: function(text) {
145 this.nativeNode.data = this.nativeNode.data + text;
148 prependText: function(text) {
149 this.nativeNode.data = text + this.nativeNode.data;
155 documentFromXML: function(xml) {
156 return new Document(parseXML(xml));
159 elementNodeFromXML: function(xml) {
160 return new ElementNode(parseXML(xml));