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]);
 
 177     Object.defineProperty(this, 'dom', {get: function() {
 
 181 $.extend(Document.prototype, {
 
 182     ElementNodeFactory: ElementNode,
 
 183     TextNodeFactory: TextNode,
 
 185     createElementNode: function(nativeNode) {
 
 186         return new this.ElementNodeFactory(nativeNode, this);
 
 189     createTextNode: function(nativeNode) {
 
 190         return new this.TextNodeFactory(nativeNode, this);
 
 194         return this.root.toXML();
 
 200     documentFromXML: function(xml) {
 
 201         return new Document(parseXML(xml));
 
 204     elementNodeFromXML: function(xml) {
 
 205         return this.documentFromXML(xml).root;
 
 209     DocumentNode: DocumentNode,
 
 210     ElementNode: ElementNode