2011-11-30 11 views
6

DOM4 compareDocumentPositionクロスブラウザ比較ドキュメントの位置

compareDocumentPositionを実装したいと思います。 Resigはgreat start at doing just thisを作りました。私は彼のコードを撮影し

function compareDocumentPosition(other) { 
    var ret = 0; 
    if (this.contains) { 
     if (this !== other && this.contains(other)) { 
      ret += 16; 
     } 
     if (this !== other && other.contains(this)) { 
      ret += 8; 
     } 
     if (this.sourceIndex >= 0 && other.sourceIndex >= 0) { 
      if (this.sourceIndex < other.sourceIndex) { 
       ret += 4; 
      } 
      if (this.sourceIndex > other.sourceIndex) { 
       ret += 2; 
      } 
     } else { 
      ret += 1; 
     } 
    } 
    return ret; 
} 

これはElementのために動作しますがTextDocumentFragmentのためにしませんが、それをneatenedました。 IE8は、それらのノード上.sourceIndexを与えないためです。 (これは、どちらか.containsを与えるものではありませんが、私はすでにその問題を修正しました)

どのように効率的にDOCUMENT_POSITION_FOLLOWINGDOCUMENT_POSITION_PRECEDINGに対応+=4+=2ビットを書きます。余分参考

これら二つをDOM4が

として定義ツリー順にAとBが同じツリー内であり、Aは、ツリー順にBの前に来る場合Aが物体Bに先行されるオブジェクトを定義しています。

オブジェクトAは、AとBが同じツリーにあり、Aがツリー順序でBの後に来る場合、オブジェクトBの後にあります。

ツリー順は前順、深さ優先探索です。

最近のほとんどのブラウザでは、この(IE9を含む)を実装します。だから、IE8で動作するものだけが必要です(私はIE6/7は気にしませんが、うまくいけば!)

答えて

10
function recursivelyWalk(nodes, cb) { 
    for (var i = 0, len = nodes.length; i < len; i++) { 
     var node = nodes[i]; 
     var ret = cb(node); 
     if (ret) { 
      return ret; 
     } 
     if (node.childNodes && node.childNodes.length) { 
      var ret = recursivelyWalk(node.childNodes, cb); 
      if (ret) { 
       return ret; 
      } 
     } 
    } 
} 

function testNodeForComparePosition(node, other) { 
    if (node === other) { 
     return true; 
    } 
} 

function compareDocumentPosition(other) { 
    function identifyWhichIsFirst(node) { 
     if (node === other) { 
      return "other"; 
     } else if (node === reference) { 
      return "reference"; 
     } 
    } 

    var reference = this, 
     referenceTop = this, 
     otherTop = other; 

    if (this === other) { 
     return 0; 
    } 
    while (referenceTop.parentNode) { 
     referenceTop = referenceTop.parentNode; 
    } 
    while (otherTop.parentNode) { 
     otherTop = otherTop.parentNode; 
    } 

    if (referenceTop !== otherTop) { 
     return Node.DOCUMENT_POSITION_DISCONNECTED; 
    } 

    var children = reference.childNodes; 
    var ret = recursivelyWalk(
     children, 
     testNodeForComparePosition.bind(null, other) 
    ); 
    if (ret) { 
     return Node.DOCUMENT_POSITION_CONTAINED_BY + 
      Node.DOCUMENT_POSITION_FOLLOWING; 
    } 

    var children = other.childNodes; 
    var ret = recursivelyWalk(
     children, 
     testNodeForComparePosition.bind(null, reference) 
    ); 
    if (ret) { 
     return Node.DOCUMENT_POSITION_CONTAINS + 
      Node.DOCUMENT_POSITION_PRECEDING; 
    } 

    var ret = recursivelyWalk(
     [referenceTop], 
     identifyWhichIsFirst 
    ); 
    if (ret === "other") { 
     return Node.DOCUMENT_POSITION_PRECEDING; 
    } else { 
     return Node.DOCUMENT_POSITION_FOLLOWING; 
    } 
} 

私は自分で書きました。私はこの実装がうまくいったと思ったが、それは私の他のコードのバグだった。かなりしっかりしているようだ。

+5

ああレイノス。私の質問に答えるためのおかげ – Raynos

+0

は大丈夫......?私がやりなさい –

+0

@TimDownは十分に眠っていました。 – Raynos

0

Raynosからの回答はトップスタートですが、すぐに実行することはできません。 Node.*が見つからないと.bindは、IE8では使用できません。ここで

コードは、Internet Explorer 8での使用のための準備ができている:

function recursivelyWalk(nodes, cb) { 
    for (var i = 0, len = nodes.length; i < len; i++) { 
     var node = nodes[i]; 
     var ret = cb(node); 
     if (ret) { 
      return ret; 
     } 
     if (node.childNodes && node.childNodes.length) { 
      var ret = recursivelyWalk(node.childNodes, cb); 
      if (ret) { 
       return ret; 
      } 
     } 
    } 
} 

function testNodeForComparePosition(node, other) { 
    if (node === other) { 
     return true; 
    } 
} 

var DOCUMENT_POSITION_DISCONNECTED = 1; 
var DOCUMENT_POSITION_PRECEDING = 2; 
var DOCUMENT_POSITION_FOLLOWING = 4; 
var DOCUMENT_POSITION_CONTAINS = 8; 
var DOCUMENT_POSITION_CONTAINED_BY = 16; 

function compareDocumentPosition(thisNode, other) { 
    function identifyWhichIsFirst(node) { 
     if (node === other) { 
      return "other"; 
     } else if (node === reference) { 
      return "reference"; 
     } 
    } 

    var reference = thisNode, 
     referenceTop = thisNode, 
     otherTop = other; 

    if (this === other) { 
     return 0; 
    } 
    while (referenceTop.parentNode) { 
     referenceTop = referenceTop.parentNode; 
    } 
    while (otherTop.parentNode) { 
     otherTop = otherTop.parentNode; 
    } 

    if (referenceTop !== otherTop) { 
     return DOCUMENT_POSITION_DISCONNECTED; 
    } 

    var children = reference.childNodes; 
    var ret = recursivelyWalk(
     children, 
     function(p) { 
      (function() { 
       var localOther = other; 
       return testNodeForComparePosition(localOther, p); 
      })(); 
     } 
    ); 
    if (ret) { 
     return DOCUMENT_POSITION_CONTAINED_BY + 
      DOCUMENT_POSITION_FOLLOWING; 
    } 

    var children = other.childNodes; 
    var ret = recursivelyWalk(
     children, 
     function(p) { 
      (function() { 
       var localOther = reference; 
       return testNodeForComparePosition(localOther, p); 
      })(); 
     } 
    ); 
    if (ret) { 
     return DOCUMENT_POSITION_CONTAINS + 
      DOCUMENT_POSITION_PRECEDING; 
    } 

    var ret = recursivelyWalk(
     [referenceTop], 
     identifyWhichIsFirst 
    ); 
    if (ret === "other") { 
     return DOCUMENT_POSITION_PRECEDING; 
    } else { 
     return DOCUMENT_POSITION_FOLLOWING; 
    } 
} 

あなたはこのようにそれを呼び出す:あなたは素晴らしい、

compareDocumentPosition(sourceElement, elementToTest) 

(それはsourceElement.compareDocumentPosition(elementToTest)を呼び出すようなものだ)

関連する問題