• atwiki
  • TEST
  • Simple Implementation of DOM Range in JavaScript

TEST

Simple Implementation of DOM Range in JavaScript

最終更新:

eriax

- view
管理者のみ編集可

制限

  • なし。無理矢理 1200 行内に収める。

ソースコード

/*@cc_on@*/
if ('undefined' === typeof Array.prototype.map) {
  Array.prototype.map = function (callbackfn) {
    var thisArg = arguments[1];
    if ('function' !== typeof callbackfn) {
      throw new Error;  // TypeError
    }
    var count = this.length;
    var result = new Array(count);
    var i;
    for (i = 0; i < count; i++) {
      if (i in this) {
        result[i] = callbackfn.call(thisArg, this[i], i, this);
      }
    }
    return result;
  };
}

if ('undefined' === typeof Array.map) {
  Array.map = function (call, map) {
    return function (arg, callbackfn) {
      return call.apply(map, arguments);
    };
  }(
    Function.prototype.call,
    Array.prototype.map);
}

////////////////////////////////////////////////////////////////////////

function As_DOM_Object(arg) {
  if (arguments.length > 0) {
    var name;
    for (name in arg) {
      if (arg.hasOwnProperty(name)) {
        this[name] = arg[name];
      }
    }
  }
}

(function () {
  this.constructor = As_DOM_Object;
}).call(As_DOM_Object.prototype);

////////////////////////////////////////////////////////////////////////

(function () {
  // RangeExceptionCode
  this.BAD_BOUNDARYPOINTS_ERR = 1;
  this.INVALID_NODE_TYPE_ERR = 2;
}).call(As_DOM_RangeException);

function As_DOM_RangeException(code) {
  if (arguments.length > 0) {
    if (arg) {
      As_DOM_Object.apply(this, arguments);
    }
  }
}

As_DOM_RangeException.prototype = new As_DOM_Object;

(function () {
  this.constructor = As_DOM_RangeException;
  this.code = null;
}).call(As_DOM_RangeException.prototype);

////////////////////////////////////////////////////////////////////////

(function () {
  // CompareHow
  this.START_TO_START = 0;
  this.START_TO_END = 1;
  this.END_TO_END = 2;
  this.END_TO_START = 3;
  // NodeType
  this.ELEMENT_NODE = 1;
  this.ATTRIBUTE_NODE = 2;
  this.TEXT_NODE = 3;
  this.CDATA_SECTION_NODE = 4;
  this.ENTITY_REFERENCE_NODE = 5;
  this.ENTITY_NODE = 6;
  this.PROCESSING_INSTRUCTION_NODE = 7;
  this.COMMENT_NODE = 8;
  this.DOCUMENT_NODE = 9;
  this.DOCUMENT_TYPE_NODE = 10;
  this.DOCUMENT_FRAGMENT_NODE = 11;
  this.NOTATION_NODE = 12;
  // DocumentPosition
  this.DOCUMENT_POSITION_DISCONNECTED = 0x01;
  this.DOCUMENT_POSITION_PRECEDING = 0x02;
  this.DOCUMENT_POSITION_FOLLOWING = 0x04;
  this.DOCUMENT_POSITION_CONTAINS = 0x08;
  this.DOCUMENT_POSITION_CONTAINED_BY = 0x10;
  this.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC = 0x20;
}).call(As_DOM_Range);

function As_DOM_Range(arg) {
  if (arguments.length > 0) {
    if (arg) {
      As_DOM_Object.apply(this, arguments);
    }
  }
}

(function () {
  this.constructor = As_DOM_Range;
  this.startContainer = null;
  this.startOffset = null;
  this.endContainer = null;
  this.endOffset = null;
  this.collapsed = null;
  this.commonAncestorContainer = null;
  // extension
  this.detached = false;
  this.ownerDocument = null;
}).call(As_DOM_Range.prototype);

(function () {
  var XML_S = /^[\u0009\u000A\u000D\u0020]*$/;
  this['[NodeGetTextContent:1]'] = function (node) {
    var txt;
    if ('undefined' !== typeof (txt = node.textContent)) {
      return txt;
    }
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
      /*@{if('undefined'!==typeof(s=node.innerText)||'undefined'!==typeof(s=node.innerHTML)){return s}}@*/
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      var doc = node.ownerDocument;
      var impl = doc.implementation;
      /*@{if(impl.hasFeature('MS-DOM','1.0')){if('undefined'!==typeof(s=node.text)){return s}}}@*/
      if (impl.hasFeature('Range', '2.0')) {
        var range = doc.createRange();
        range.selectNodeContents(node);
        txt = range.toString();
        range.detach();
        return txt;
      }
      return this['[NodeGetTextContent:2]'](node);
    case As_DOM_Range.TEXT_NODE:
      try {
        if (!node.isElementContentWhitespace()) {
          return node.data;
        }
        return '';
      }
      catch (err) {
        if (!XML_S.test(node.data)) {
          return node.data;
        }
        return '';
      }
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      return node.nodeValue;
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      return null;
    }
  };
  this['[NodeGetTextContent:2]'] = function (node) {
    switch (node.nodeType) {
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
      return node.nodeValue;
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      if (node.hasChildNodes()) {
        return Array.prototype.concat.apply([], Array.map(node.childNodes, arguments.callee)).join('');
      }
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      return '';
    }
  };
  this['[NodeGetContextRoot]'] = function (node) {
    var n;
    do {
      n = node;
    } while ((node = node.parentNode));
    return n;
  };
  this['[NodeGetChildIndex]'] = function (node) {
    var i = 0;
    for (i = 0; node = node.previousSibling; i += 1);
    return i;
  };
  this['[NodeGetMaxOffset]'] = function (node) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      return node.childNodes.length;
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      return node.length;
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
      return node.data.length;
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error;
    }
  };
  this['[NodeContainsOther]'] = function (node, other) {
    /*@{if('undefined'!==typeof node.contains&&'undefined'!==typeof other.contains){return node.contains(other)}}@*/
    if (node === other) {
      return false;
    }
    try {
      return (0 !== (node.compareDocumentPosition(other) & Node.DOCUMENT_POSITION_CONTAINED_BY));
    }
    catch (err) {
      while ((other = other.parentNode)) {
        if (node === other) {
          break;
        }
      }
      return Boolean(other);
    }
  };
  this['[NodeCompareDocumentPosition:1]'] = function (node, other) {
    if (node === other) {
      return 0;
    }
    if (this['[NodeGetContextRoot]'](node) !== this['[NodeGetContextRoot]'](other)) {
      return As_DOM_Range.DOCUMENT_POSITION_DISCONNECTED | As_DOM_Range.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
    }
    /*@{if('undefined'!==typeof node.contains&&'undefined'!==typeof other.contains){if(node.contains(other)){return 0x04|0x10}if(other.contains(node)){return 0x02|0x08}}if('undefined'!==typeof node.sourceIndex&&'undefined'!==typeof other.sourceIndex){if(node.sourceIndex<other.sourceIndex){return 0x04}if(node.sourceIndex>other.sourceIndex){return 0x02}}}@*/
    return this['[NodeCompareDocumentPosition:2]'](node, other);
  };
  this['[NodeCompareDocumentPosition:2]'] = function (node, other) {
    var path1 = this['[NodeGetSnapshotOffsets]'](node);
    var path2 = this['[NodeGetSnapshotOffsets]'](other);
    var p1;
    var p2;
    while (true) {
      p1 = path1.pop();
      p2 = path2.pop();
      if (p1 < p2) {
        return As_DOM_Range.DOCUMENT_POSITION_FOLLOWING;
      }
      if (p1 > p2) {
        return As_DOM_Range.DOCUMENT_POSITION_PRECEDING;
      }
      if (path1.length === 0) {
        return As_DOM_Range.DOCUMENT_POSITION_FOLLOWING | As_DOM_Range.DOCUMENT_POSITION_CONTAINED_BY;
      }
      if (path2.length === 0) {
        return As_DOM_Range.DOCUMENT_POSITION_PRECEDING | As_DOM_Range.DOCUMENT_POSITION_CONTAINS;
      }
    }
  };
  this['[NodeGetSnapshotOffsets]'] = function (node, from) {
    var root = from || this.ownerDocument;
    var path = [];
    for (; node; node = node.parentNode) {
      if (node === root) {
        return path;
      }
      path[path.length] = this['[NodeGetChildIndex]'](node);
    }
    throw new Error;
  };
  this['[NodeGetOrderedSnapshotOffsets]'] = function (node, from) {
    return this['[NodeGetSnapshotOffsets]'](node, from).reverse();
  };
  this['[NodeIsValidContainer]'] = function (node) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      return true;
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
      return false;
    default:
      throw new Error; // RangeException.INVALID_NODEYPE_ERR(2)
    }
  };
  this['[NodeIsContextual]'] = function (node) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
      return true;
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
    case As_DOM_Range.NOTATION_NODE:
      return false;
    default:
      throw new Error; // RangeException.INVALID_NODEYPE_ERR(2)
    }
  };
  this['[OffsetIsValid]'] = function (node, offset) {
    return (offset >= 0) && (offset <= this['[NodeGetMaxOffset]'](node));
  };
  this['[NodeHasValidRoot]'] = function (node) {
    switch (this['[NodeGetContextRoot]'](node).nodeType) {
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      return true;
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
      return false;
    default:
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
  };
  this['[ComparePoints]'] = function (compareOffsets, getAncestorOffset) {
    return function (container1, offset1, container2, offset2) {
      var k;
      if (container1 === container2) {
        return compareOffsets.call(this, offset1, offset2);
      }
      try {
        k = container1.compareDocumentPosition(container2);
      }
      catch (err) {
        k = this['[NodeCompareDocumentPosition:1]'](container1, container2);
      }
      if (0 !== (k & As_DOM_Range.DOCUMENT_POSITION_CONTAINED_BY)) {
        return compareOffsets.call(this, offset1, getAncestorOffset.call(this, container2, container1)) || -1;
      }
      if (0 !== (k & As_DOM_Range.DOCUMENT_POSITION_CONTAINS)) {
        return compareOffsets.call(this, getAncestorOffset.call(this, container1, container2), offset2) || 1;
      }
      if (0 !== (k & As_DOM_Range.DOCUMENT_POSITION_FOLLOWING)) {
        return -1;
      }
      if (0 !== (k & As_DOM_Range.DOCUMENT_POSITION_PRECEDING)) {
        return 1;
      }
      throw new Error; // DOMException.WRONG_DOCUMENT_ERR(4)
    };
  }(
    function (n1, n2) {
      if (n1 < n2) {
        return -1;
      }
      if (n1 > n2) {
        return 1;
      }
      return 0;
    },
    function (n1, n2) {
      while (n1.parentNode !== n2) {
        n1 = n1.parentNode;
      }
      return this['[NodeGetChildIndex]'](n1);
    });
  this['[CollapseBoundary]'] = function () {
    var node = this.startContainer;
    if (this['[NodeGetMaxOffset]'](node) !== this.startOffset) {
      this.collapse(true);
    }
    do {
      if (!node || node === this.commonAncestorContainer) {
        this.collapse(true);
        return;
      }
      if (node.nextSibling) {
        this.setStartAfter(node);
        this.collapse(true);
        return;
      }
    }
    while ((node = node.parentNode));
  };
  this['[GetCommonAncestorContainer]'] = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (this.startContainer === this.endContainer) {
      return this.startContainer;
    }
    if (this['[NodeContainsOther]'](this.startContainer, this.endContainer)) {
      return this.startContainer;
    }
    if (this['[NodeContainsOther]'](this.endContainer, this.startContainer)) {
      return this.endContainer;
    }
    var endContainer = this.endContainer;
    var node = this.startContainer;
    while (!this['[NodeContainsOther]'](node, endContainer)) {
      node = node.parentNode;
    }
    return node;
  };
  this['[SetCommonAncestorContainer]'] = function (node) {
    this.commonAncestorContainer = node;
  };
  this['[NodeAppendContents]'] = function (node, arg) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      return node.appendChild(arg);
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      return this['[NodeReplaceBy]'](node, arg);
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
  };
  this['[NodeReplaceBy]'] = function (node, newNode) {
    /*@{if('undefined'!==typeof node.replaceNode){return node.replaceNode(newNode)}}@*/
    var n;
    if ((n = node.parentNode)) {
      return n.replaceChild(newNode, node);
    }
    if ((n = newNode.parentNode)) {
      n.removeChild(newNode);
    }
    return node;
  };
  this.setStart = function (refNode, offset) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeIsValidContainer]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    if (!this['[OffsetIsValid]'](refNode, offset)) {
      throw new Error; // DOMException.INDEX_SIZE_ERR(1)
    }
    this['[SetStart:1]'](refNode, offset);
  };
  this['[SetStart:1]'] = function (refNode, offset) {
    this['[SetStart:2]'](refNode, offset);
    this['[SetStart:3]']();
  };
  this['[SetStart:2]'] = function (refNode, offset) {
    this.startContainer = refNode;
    this.startOffset = offset;
  };
  this['[SetStart:3]'] = function (range) {
    if (this.compareBoundaryPoints(As_DOM_Range.END_TO_START, this) >= 0) {
      this.collapse(true);
    }
    else {
      this.collapsed = false;
      this['[SetCommonAncestorContainer]'](this['[GetCommonAncestorContainer]']());
    }
  };
  this.setEnd = function (refNode, offset) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeIsValidContainer]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    if (!this['[OffsetIsValid]'](refNode, offset)) {
      throw new Error; // DOMException.INDEX_SIZE_ERR(1)
    }
    this['[SetEnd:1]'](refNode, offset);
  };
  this['[SetEnd:1]'] = function (refNode, offset) {
    this['[SetEnd:2]'](refNode, offset);
    this['[SetEnd:3]']();
  };
  this['[SetEnd:2]'] = function (refNode, offset) {
    this.endContainer = refNode;
    this.endOffset = offset;
  };
  this['[SetEnd:3]'] = function () {
    if (this.compareBoundaryPoints(As_DOM_Range.START_TO_END, this) <= 0) {
      this.collapse(false);
    }
    else {
      this.collapsed = false;
      this['[SetCommonAncestorContainer]'](this['[GetCommonAncestorContainer]']());
    }
  };
  this.setStartBefore = function (refNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeHasValidRoot]'](refNode) || !this['[NodeIsContextual]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    this['[SetStart:1]'](refNode.parentNode, this['[NodeGetChildIndex]'](refNode));
  };
  this.setStartAfter = function (refNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeHasValidRoot]'](refNode) || !this['[NodeIsContextual]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    this['[SetStart:1]'](refNode.parentNode, this['[NodeGetChildIndex]'](refNode) + 1);
  };
  this.setEndBefore = function (refNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeHasValidRoot]'](refNode) || !this['[NodeIsContextual]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    this['[SetEnd:1]'](refNode.parentNode, this['[NodeGetChildIndex]'](refNode));
  };
  this.setEndAfter = function (refNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeHasValidRoot]'](refNode) || !this['[NodeIsContextual]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    this['[SetEnd:1]'](refNode.parentNode, this['[NodeGetChildIndex]'](refNode) + 1);
  };
  this.collapse = function (toStart) {
    this.collapsed = true;
    if (toStart) {
      this.endContainer = this.startContainer;
      this.endOffset = this.startOffset;
    }
    else {
      this.startContainer = this.endContainer;
      this.startOffset = this.endOffset;
    }
    this.commonAncestorContainer = this.startContainer;
  };
  this.selectNode = function (refNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeHasValidRoot]'](refNode) || !this['[NodeIsContextual]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    this['[SetStart:2]'](refNode.parentNode, this['[NodeGetChildIndex]'](refNode));
    this['[SetEnd:1]'](refNode.parentNode, this['[NodeGetChildIndex]'](refNode) + 1);
  };
  this.selectNodeContents = function (refNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    if (!this['[NodeHasValidRoot]'](refNode)) {
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
    this['[SetStart:2]'](refNode, 0);
    this['[SetEnd:1]'](refNode, this['[NodeGetMaxOffset]'](refNode));
  };
  this.compareBoundaryPoints = function (how, sourceRange) {
    switch (how) {
    case As_DOM_Range.START_TO_START:
      return this['[ComparePoints]'](this.startContainer, this.startOffset, sourceRange.startContainer, sourceRange.startOffset);
    case As_DOM_Range.START_TO_END:
      return this['[ComparePoints]'](this.endContainer, this.endOffset, sourceRange.startContainer, sourceRange.startOffset);
    case As_DOM_Range.END_TO_END:
      return this['[ComparePoints]'](this.endContainer, this.endOffset, sourceRange.endContainer, sourceRange.endOffset);
    case As_DOM_Range.END_TO_START:
      return this['[ComparePoints]'](this.startContainer, this.startOffset, sourceRange.endContainer, sourceRange.endOffset);
    default:
      throw new Error; // DOMException.NOT_SUPPORTED_ERR(9)
    }
  };
  this.detach = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    this.commonAncestorContainer = null;
    this.detached = true;
  };
  this.extractContents = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    var df = this['[ExtractContents:1]']();
    this['[CollapseBoundary]']();
    return df;
  };
  this['[ExtractContents:1]'] = function () {
    return function () {
      if (this.commonAncestorContainer === this.startContainer) {
        if (this.commonAncestorContainer === this.endContainer) {
          return this['[ExtractNodeContents]'](this.commonAncestorContainer, this.startOffset, this.endOffset);
        }
        var df = this.ownerDocument.createDocumentFragment();
        var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
        df.appendChild(this['[ExtractNodeContents]'](this.commonAncestorContainer, this.startOffset, offsets2[0]));
        processRight.call(this, df, offsets2[0], offsets2); // different from cloneContents
        return df;
      }
      if (this.commonAncestorContainer === this.endContainer) {
        var df = this.ownerDocument.createDocumentFragment();
        var offsets1 = this['[NodeGetOrderedSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
        processLeft.call(this, df, offsets1, this.endOffset);
        return df;
      }
      var df = this.ownerDocument.createDocumentFragment();
      var offsets1 = this['[NodeGetOrderedSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
      var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
      processLeft.call(this, df, offsets1, offsets2[0]);
      processRight.call(this, df, offsets1[0] + 1, offsets2); // different from cloneContents
      return df;
    };
    function processLeft(df, offsets1, endOffset) {
      var oldContent = this.commonAncestorContainer.childNodes[offsets1[0]];
      var newContent = df.appendChild(oldContent.cloneNode(false));
      var offset1Count = offsets1.length;
      var offset;
      var child;
      var i;
      for (i = 1; i < offset1Count; i++) {
        offset = offsets1[i];
        child = oldContent.childNodes[offset];
        newContent.appendChild(child.cloneNode(false));
        newContent.appendChild(this['[ExtractNodeContents]'](oldContent, offset + 1));
        newContent = newContent.firstChild;
        oldContent = child;
      }
      this['[NodeAppendContents]'](newContent, this['[ExtractNodeContents]'](this.startContainer, this.startOffset));
      df.appendChild(this['[ExtractNodeContents]'](this.commonAncestorContainer, offsets1[0] + 1, endOffset));
    }
    function processRight(df, startOffset, offsets2) {
      var oldContent = this.commonAncestorContainer.childNodes[startOffset];
      var newContent = df.appendChild(oldContent.cloneNode(false));
      var offset2Count = offsets2.length;
      var offset;
      var child;
      var i;
      for (i = 1; i < offset2Count; i++) {
        offset = offsets2[i];
        child = oldContent.childNodes[offset];
        newContent.appendChild(this['[ExtractNodeContents]'](oldContent, 0, offset));
        newContent.appendChild(child.cloneNode(false));
        newContent = newContent.lastChild;
        oldContent = child;
      }
      this['[NodeAppendContents]'](newContent, this['[ExtractNodeContents]'](this.endContainer, 0, this.endOffset));
    }
  }();
  this['[ExtractNodeContents]'] = function (node, startOffset, endOffset) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      var childNodes = node.childNodes;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = childNodes.length;
      }
      var count = endOffset - startOffset;
      var type = As_DOM_Range.DOCUMENT_TYPE_NODE;
      var df = this.ownerDocument.createDocumentFragment();
      var n;
      var i;
      for (i = 0; i < count; i++) {
        n = childNodes[startOffset];
        if (n.nodeType === type) {
          throw new Error; // DOMException.HIERARCHY_REQUEST_ERR(3)
        }
        df.appendChild(node.removeChild(n));
      }
      return df;
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      var cnt = this['[CloneNodeContents]'](node, startOffset, endOffset);
      this['[DeleteNodeContents]'](node, startOffset, endOffset);
      return cnt;
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
  };
  this.cloneContents = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    var df = this['CloneContents:1']();
    return df;
  };
  this['CloneContents:1'] = function () {
    return function () {
      if (this.commonAncestorContainer === this.startContainer) {
        if (this.commonAncestorContainer === this.endContainer) {
          return this['[CloneNodeContents]'](this.commonAncestorContainer, this.startOffset, this.endOffset);
        }
        var df = this.ownerDocument.createDocumentFragment();
        var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
        df.appendChild(this['[CloneNodeContents]'](this.commonAncestorContainer, this.startOffset, offsets2[0]));
        processRight.call(this, df, offsets2[0], offsets2); // different from extractContents
        return df;
      }
      if (this.commonAncestorContainer === this.endContainer) {
        var df = this.ownerDocument.createDocumentFragment();
        var offsets1 = this['[NodeGetOrderedSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
        processLeft.call(this, df, offsets1, this.endOffset);
        return df;
      }
      var df = this.ownerDocument.createDocumentFragment();
      var offsets1 = this['[NodeGetOrderedSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
      var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
      processLeft.call(this, df, offsets1, offsets2[0]);
      processRight.call(this, df, offsets2[0], offsets2); // different from extractContents
      return df;
    };
    function processLeft(df, offsets1, endOffset) {
      var oldContent = this.commonAncestorContainer.childNodes[offsets1[0]];
      var newContent = df.appendChild(oldContent.cloneNode(false));
      var offset1Count = offsets1.length;
      var offset;
      var child;
      var i;
      for (i = 1; i < offset1Count; i++) {
        offset = offsets1[i];
        child = oldContent.childNodes[offset];
        newContent.appendChild(child.cloneNode(false));
        newContent.appendChild(this['[CloneNodeContents]'](oldContent, offset + 1));
        newContent = newContent.firstChild;
        oldContent = child;
      }
      this['[NodeAppendContents]'](newContent, this['[CloneNodeContents]'](this.startContainer, this.startOffset));
      df.appendChild(this['[CloneNodeContents]'](this.commonAncestorContainer, offsets1[0] + 1, endOffset));
    }
    function processRight(df, startOffset, offsets2) {
      var oldContent = this.commonAncestorContainer.childNodes[startOffset];
      var newContent = df.appendChild(oldContent.cloneNode(false));
      var offset2Count = offsets2.length;
      var offset;
      var child;
      var i;
      for (i = 1; i < offset2Count; i++) {
        offset = offsets2[i];
        child = oldContent.childNodes[offset];
        newContent.appendChild(this['[CloneNodeContents]'](oldContent, 0, offset));
        newContent.appendChild(child.cloneNode(false));
        newContent = newContent.lastChild;
        oldContent = child;
      }
      this['[NodeAppendContents]'](newContent, this['[CloneNodeContents]'](this.endContainer, 0, this.endOffset));
    }
  }();
  this['[CloneNodeContents]'] = function (node, startOffset, endOffset) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      var childNodes = node.childNodes;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = childNodes.length;
      }
      var count = endOffset;
      var type = As_DOM_Range.DOCUMENT_TYPE_NODE;
      var df = this.ownerDocument.createDocumentFragment();
      var i;
      var n;
      for (i = startOffset; i < count; i++) {
        n = childNodes[i];
        if (n.nodeType === type) {
          throw new Error; // DOMException.HIERARCHY_REQUEST_ERR(3)
        }
        df.appendChild(n.cloneNode(true));
      }
      return df;
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      var cnt = node.cloneNode(false);
      var txt = cnt.data;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = txt.length;
      }
      cnt.data = txt.substring(startOffset, endOffset);
      return cnt;
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
  };
  this.deleteContents = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    this['[DeleteContents:1]']();
    this['[CollapseBoundary]']();
  };
  this['[DeleteContents:1]'] = function () {
    return function () {
      if (this.commonAncestorContainer === this.startContainer) {
        if (this.commonAncestorContainer === this.endContainer) {
          this['[DeleteNodeContents]'](this.commonAncestorContainer, this.startOffset, this.endOffset);
          return;
        }
        var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
        this['[DeleteNodeContents]'] (this.commonAncestorContainer, this.startOffset, offsets2[0]);
        processRight.call(this, offsets2[0], offsets2);
        return;
      }
      if (this.commonAncestorContainer === this.endContainer) {
        var offsets1 = this['[NodeGetOrderedSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
        processLeft.call(this, offsets1, this.endOffset);
        return;
      }
      var offsets1 = this['[NodeGetOrderedSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
      var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
      processLeft.call(this, offsets1, offsets2[0]);
      processRight.call(this, offsets1[0] + 1, offsets2);
      return;
    };
    function processLeft(offsets1, endOffset) {
      var child = this.commonAncestorContainer.childNodes[offsets1[0]];
      var offset1Count = offsets1.length;
      var offset;
      var i;
      for (i = 1; i < offset1Count; i++) {
        offset = offsets1[i];
        this['[DeleteNodeContents]'](child, offset + 1);
        child = child.childNodes[offset];
      }
      this['[DeleteNodeContents]'](this.startContainer, this.startOffset);
      this['[DeleteNodeContents]'](this.commonAncestorContainer, offsets1[0] + 1, endOffset);
    }
    function processRight(startOffset, offsets2) {
      var child = this.commonAncestorContainer.childNodes[startOffset];
      var offset2Count = offsets2.length;
      var offset;
      var i;
      for (i = 1; i < offset2Count; i++) {
        offset = offsets2[i];
        this['[DeleteNodeContents]'](child, 0, offset);
        child = child.childNodes[offset];
      }
      this['[DeleteNodeContents]'](this.endContainer, 0, this.endOffset);
    }
  }();
  this['[DeleteNodeContents]'] = function (node, startOffset, endOffset) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      var childNodes = node.childNodes;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = childNodes.length;
      }
      var count = endOffset - startOffset;
      var i;
      for (i = 0; i < count; i++) {
        node.removeChild(childNodes[startOffset]);
      }
      return;
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      var cnt = node.cloneNode(false);
      var txt = cnt.data;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = txt.length;
      }
      node.data = txt.substring(0, startOffset) + txt.substring(endOffset);
      return;
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
  };
  this.toString = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    var result = this['[ToString:1]']();
    return result;
  };
  this['[ToString:1]'] = function () {
    return function () {
      if (this.commonAncestorContainer === this.startContainer) {
        if (this.commonAncestorContainer === this.endContainer) {
          return this['[NodeGetString]'](this.commonAncestorContainer, this.startOffset, this.endOffset);
        }
        var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
        var result = [];
        result[result.length] = this['[NodeGetString]'](this.commonAncestorContainer, this.startOffset, offsets2[0]);
        processRight.call(this, result, offsets2[0], offsets2);
        return result.join('');
      }
      if (this.commonAncestorContainer === this.endContainer) {
        var offsets1 = this['[NodeGetSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
        var result = [];
        processLeft.call(this, result, offsets1, this.endOffset);
        return result.join('');
      }
      var offsets1 = this['[NodeGetSnapshotOffsets]'](this.startContainer, this.commonAncestorContainer);
      var offsets2 = this['[NodeGetOrderedSnapshotOffsets]'](this.endContainer, this.commonAncestorContainer);
      var result = [];
      processLeft.call(this, result, offsets1, offsets2[0]);
      processRight.call(this, result, this.startOffset, offsets2);
      return result.join('');
    };
    function processLeft(result, offsets1, endOffset) {
      var parent = this.startContainer;
      var offset1Count = offsets1.length - 1;
      var offset;
      var i;
      result[result.length] = this['[NodeGetString]'](parent, this.startOffset);
      for (i = 0; i < offset1Count; i++) {
        offset = offsets1[i];
        parent = parent.parentNode;
        result[result.length] = this['[NodeGetString]'](parent, offset + 1);
      }
      result[result.length] = this['[NodeGetString]'](this.commonAncestorContainer, offsets1[offset1Count] + 1, endOffset);
    }
    function processRight(result, startOffset, offsets2) {
      var child = this.commonAncestorContainer.childNodes[offsets2[0]];
      var offset2Count = offsets2.length;
      var offset;
      var i;
      for (i = 1; i < offset2Count; i++) {
        offset = offsets2[i];
        result[result.length] = this['[NodeGetString]'](child, 0, offset);
        child = child.childNodes[offset];
      }
      result[result.length] = this['[NodeGetString]'](this.endContainer, 0, this.endOffset);
    }
  }();
  this['[NodeGetString]'] = function (node, startOffset, endOffset) {
    switch (node.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      var childNodes = node.childNodes;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = childNodes.length;
      }
      var count = endOffset;
      var type1 = As_DOM_Range.PROCESSING_INSTRUCTION_NODE;
      var type2 = As_DOM_Range.COMMENT_NODE;
      var txt = [];
      var n;
      var i;
      for (i = startOffset; i < count; i++) {
        n = childNodes[i];
        switch (node.nodeType) {
        case type1:
        case type2:
          break;
        default:
          txt[txt.length] = this['[NodeGetTextContent:1]'](n);
        }
      }
      return txt.join('');
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      var txt = node.data;
      if (isNaN(startOffset)) {
        startOffset = 0;
      }
      if (isNaN(endOffset)) {
        endOffset = txt.length;
      }
      return txt.substring(startOffset, endOffset);
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODE_TYPE_ERR(2)
    }
  };
  this.insertNode = function (newNode) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    switch (newNode.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      break;
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODEYPE_ERR(2)
    }
    if (newNode.ownerDocument !== this.ownerDocument) {
      throw new Error; // DOMException.WRONG_DOCUMENT_ERR(4)
    }
    if (this['[NodeContainsOther]'](newNode, this.startContainer)) {
      throw new Error; // DOMException.HIERARCHY_REQUEST_ERR(3)
    }
    return this['[InsertNode:1]'](newNode);
  };
  this['[InsertNode:1]'] = function (newNode) {
    var startContainer = this.startContainer;
    switch (startContainer.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
      var target = startContainer.childNodes[this.startOffset]; /*@{ if (! target) target = null; }@*/
      var endContainer = this.endContainer;
      if (startContainer === endContainer) {
        var childNodes = endContainer.childNodes;
        var childCount = childNodes.length;
        startContainer.insertBefore(newNode, target);
        this.endOffset += childNodes.length - childCount;
      }
      else {
        startContainer.insertBefore(newNode, target);
      }
      return;
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
      var startOffset = this.startOffset;
      var endContainer = this.endContainer;
      var cnt = startContainer.splitText(startOffset);
      if (startContainer === endContainer) {
        this.endContainer = cnt;
        this.endOffset -= startOffset;
      }
      cnt.parentNode.insertBefore(newNode, cnt);
      return;
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.HIERARCHY_REQUEST_ERR(3)
    }
  };
  this.surroundContents = function (newParent) {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    switch (newParent.nodeType) {
    case As_DOM_Range.ELEMENT_NODE:
    case As_DOM_Range.TEXT_NODE:
    case As_DOM_Range.CDATA_SECTION_NODE:
    case As_DOM_Range.ENTITY_REFERENCE_NODE:
    case As_DOM_Range.PROCESSING_INSTRUCTION_NODE:
    case As_DOM_Range.COMMENT_NODE:
      break;
    case As_DOM_Range.ATTRIBUTE_NODE:
    case As_DOM_Range.ENTITY_NODE:
    case As_DOM_Range.DOCUMENT_TYPE_NODE:
    case As_DOM_Range.DOCUMENT_NODE:
    case As_DOM_Range.DOCUMENT_FRAGMENT_NODE:
    case As_DOM_Range.NOTATION_NODE:
    default:
      throw new Error; // RangeException.INVALID_NODEYPE_ERR(2)
    }
    if (newParent.ownerDocument !== this.ownerDocument) {
      throw new Error; // DOMException.WRONG_DOCUMENT_ERR(4)
    }
    if (this['[NodeContainsOther]'](newParent, this.startContainer)) {
      throw new Error; // DOMException.HIERARCHY_REQUEST_ERR(3)
    }
    return this['[SurroundContents:1]'](newParent);
  };
  this['[SurroundContents:1]'] = function (newParent) {
    if (this['[NodeContainsOther]'](newParent, this.endContainer)) {
      this.endContainer = newParent;
      this.endOffset = 0;
    }
    while (newParent.hasChildNodes()) {
      newParent.removeChild(newParent.lastChild);
    }
    //
    var df = this.extractContents();
    this.insertNode(newParent);
    newParent.appendChild(df);
    this.selectNode(newParent);
  };
  this.cloneRange = function () {
    if (this.detached) {
      throw new Error; // DOMException.INVALID_STATE_ERR(11)
    }
    //
    var range = new this.constructor(null);
    As_DOM_Object.call(range, this);
    return range;
  };
}).call(As_DOM_Range.prototype);

////////////////////////////////////////////////////////////////////////

var as_DOM_DocumentRange_createRange = function (doc) {
    return new As_DOM_Range({
      startContainer: doc,
      startOffset: 0,
      endContainer: doc,
      endOffset: 0,
      collapsed: true,
      commonAncestorContainer: doc,
      ownerDocument: doc,
      detached: false
    });
  };
  • 初出 2011-08-25/26/27
目安箱バナー