TBEã®ãéžæç¯å²ã®ãªã³ã¯ãå šãŠã¿ãã§éãããªã©ã®æ©èœã§å©çšããŠãããéžæç¯å²å ã®ãªã³ã¯ãåéãããåŠçã«ã€ããŠã®è§£èª¬ã§ããDOM2 Rangeã®compareBoundaryPointsã®äœ¿ãæ¹ã®è§£èª¬ãå«ãã§ããŸãã®ã§ãããã ãèŠãŠãOKã§ãã
Mozillaã§ã¯ãCtrlããŒãæŒããªããtableã®ã»ã«ãã¯ãªãã¯ããããšã§ãé£ç¶ããŠããªãã»ã«ãè€æ°éžæããããšãã§ããŸãããã®ãããªå Žåãäžã€ã®ãéžæç¯å²ãªããžã§ã¯ããããè€æ°ã®RangeãåãåºããŠåŠçããªããŠã¯ãªããŸããã
Rangeã®äžã«å«ãŸãããªã³ã¯ãåéããã«ããã£ãŠã¯ãã©ããã£ãŠRangeã®äžã«ãããªã³ã¯ã ããåéããããåé¡ã«ãªããŸãããŸããéšåéžæããããªã³ã¯ã®æ±ãã«ã工倫ãå¿ èŠã§ãã
ãããã®ç¹ã«ã€ããŠãããã解説ããŸãã
Mozillaã§ã¯ãWindowãªããžã§ã¯ãã®getSelection()
ã¡ãœããã«ãã£ãŠéžæç¯å²ãªããžã§ã¯ãïŒnsISelectionïŒãååŸããããšãã§ããŸãã
ãã®ãªããžã§ã¯ãã«ã¯rangeCount
ãšããããããã£ãšgetRangeAt()
ãšããã¡ãœãããããããããã䜿ã£ãŠDOM2 Rangeã®Rangeãªããžã§ã¯ããååŸã§ããŸãã以äžã«äŸã瀺ããŸãã
function getSelectionLinksInFrame(aWindow)
{
var links = [];
var selection = aWindow.getSelection();
// äœãéžæãããŠããªãå Žåã¯ãäœãããªãã
if (!selection || !selection.rangeCount) return links;
const count = selection.rangeCount;
var selectionRange;
for (var i = 0; i < count; i++)
{
selectionRange = selection.getRangeAt(i);
...
}
return link;
}
ããããå ã®åŠçã¯ãããããŠååŸãããããããã®Rangeãã«ã€ããŠè¡ãããšã«ãªããŸãã
ãªããéžæç¯å²ãªããžã§ã¯ãã¯ãå§ç¹ãçµç¹ãããåŸã«ããïŒïŒäžããäžãžåããŠéžæãããïŒããšããå ŽåãããåŸãŸãããDOM2 Rangeã®ãªããžã§ã¯ãã«ã€ããŠã¯åžžã«ãå§ç¹ã¯çµç¹ãããåããšãªããŸãïŒä»æ§äžãå§ç¹ãçµç¹ããåŸã«ãªãããšã¯ããåŸãªãïŒããã£ãŠãéžæç¯å²ãªããžã§ã¯ããšRangeãªããžã§ã¯ããšã§å§ç¹ãšçµç¹ãå ¥ãæ¿ããããšããããŸãã
ãéžæç¯å²ã®ãªã³ã¯ã®ãªã³ã¯å URLãé åãšããŠè¿ãããªã©ã®ãããªåçŽãªåŠçã®å Žåãå ã®DOMããªãŒãšRangeãšãåãé¢ããŠããŸããšãéåžžã«æ¥œã«åŠçã§ããŸãã
var documentFragment = selectionRange.cloneContents();
var elements = documentFragment.getElementsByTagName('*');
for (var i = 0; i < elements.length; i++)
if (elements[i].href)
links.push(elements[i]);
Rangeã®cloneContents()
ã¡ãœããã¯ãRangeã®å
容ãå«ãã å
šãæ°ããææžçãçæããŸãããã£ãŠããã®äžã§ãå
šãŠã®èŠçŽ ãã«ã€ããŠåŠçãè¡ãã°ãããã¯åæã«ãéžæç¯å²ã«å«ãŸããèŠçŽ ã ãã«ã€ããŠã®åŠçãã«ããªãããã§ãããŸããéšåéžæãããããŒãã¯èŠªèŠçŽ ãå«ããŠãéå§ã¿ã°ãè£å®ããããããªåœ¢ã§ææžçã«çµã¿èŸŒãŸããŸãã®ã§ããéäžããããéäžãŸã§ãéžæããããªã³ã¯ã«ã€ããŠãåé¡ãªãååŸã§ããŸãã
ãªããããã§ã¯åçŽã«ãhrefãšããããããã£ãæã£ãŠããããªã³ã¯ãšèŠãªãããšã«ããŠããŸãã
ãéžæç¯å²ã®ãªã³ã¯ãå šãŠæ¢èšªåã«ããããªã©ã®ãããªå ã®DOMããªãŒãžã®å€æŽã䌎ãåŠçãå¿ èŠãšããå Žåãåè¿°ã®æ¹æ³ã¯äœ¿ããŸããã®ã§ããDOMããªãŒã®èµ°æ»ãããã®ããŒããRangeå ã«ãããã©ããã®å€æããªã©ãèªåã§è¡ããªããŠã¯ãªããŸããã
DOM2 Rangeã«ã¯ãRangeã®å
é ãšæ«å°Ÿããããã®ããŒãã®å
±éã®èŠªãšãªã£ãŠããããŒãããè¿ãcommonAncestorContainer
ãšããããããã£ããããŸãããããã¯ä»åã¯åœ¹ã«ç«ã¡ãŸãããããã䜿ã£ãŠrange.commonAncestorContainer.getElementsByTagName('*')
ãªã©ãšæžããŠããŸã£ãããéžæç¯å²å€ã®èŠçŽ ããŒããŸã§ååŸããŠããŸãããã§ãããã¿ãããããæ¬æ¥èµ°æ»ããªããŠã¯ãªããªãããŒãã®äœååãã®æ°ã®ããŒããååŸããŠããŸããããŸãããã«ãŒãåŠçãäœéãªJavaScriptã§ã¯çŸå®³ãã£ãŠäžå©ç¡ãã§ãã
ãšããããã§ãDOMããªãŒãå°éã«èµ°æ»ããããšãèããŸãããã
var node = selectionRange.startContainer;
traceTree:
while (true)
{
if (/* nodeãrangeã®å€ã«ããå Žåãã«ãŒããæãã */) {
break;
}
else if (node.href)
links.push(node);
if (node.hasChildNodes()) { // åèŠçŽ ãããå ŽåãåèŠçŽ ã®èµ°æ»ã«ç§»ã
node = node.firstChild;
}
else { // åèŠçŽ ããªãå Žåã次ã®èŠçŽ ã«ç§»ã
// 次ã®èŠçŽ ããªãå Žåã芪èŠçŽ ã®æ¬¡ã®èŠçŽ ã«ç§»ã
while (!node.nextSibling)
{
// æåŸã®èŠçŽ ã«å°éããŠããŸã£ãããã«ãŒããæãã
node = node.parentNode;
if (!node) break traceTree;
}
node = node.nextSibling;
}
}
ãããŸã§ã¯ç°¡åã§ãããåé¡ã¯ããã®ããŒããRangeã®äžã«å«ãŸããŠãããã©ãããã©ããã£ãŠèª¿ã¹ããã§ãã
DOM2 Rangeã®Rangeãªããžã§ã¯ãã¯ããã®ããŒããRangeã®äžã«ãããã©ãããã調ã¹ãæ©èœã¯ãããŸãããããã®ä»£ããããäºã€ã®Rangeã®äœçœ®é¢ä¿ãæ¯èŒãããæ©èœãæã£ãŠããŸãããããcompareBoundaryPoints()
ãšããã¡ãœããã§ããããã䜿ãã°ããŒããšRangeã®äœçœ®é¢ä¿ã調ã¹ãããšãã§ããŸãã
ããããã®ã¡ãœãããåŒæ°ã®æ±ããå«ããŠäœ¿ãæ¹ãéåžžã«ãããããã§ããä»æ§æžïŒåæïŒã®èª¬æçãèªãã§ãããã©ã£ã¡ã®å§ç¹ãã©ã£ã¡ã®çµç¹ãããåã«ããããšããé ã®æªãåã«ã¯ãªã«ããªã«ãããµãããªç解ã§ããŸããã§ãããå³ã䜿ã£ãŠè§£èª¬ããæ¹ããã³ãããã·ã§ãããšããããšã§âŠâŠ
var nodeRange = aWindow.document.createRange();
nodeRange.selectNode(node);
ãã®ããã«ããŠååŸãããåŠç察象ã®ããŒãã ããå«ãRangeãã§ããnodeRange
ãšãå
ã®ãéžæç¯å²ã®Rangeãã§ããselectionRange
ãšã®äœçœ®é¢ä¿ãæ¯èŒããŠã¿ãŸãããã
ãŸãã¯ãnodeRange
ãselectionRange
ãããåã®äœçœ®ã«ããå Žåã
ã³ãŒã | ã³ãŒãã®æå³ | è¿ãå€ | è¿ãå€ã®æå³ |
---|---|---|---|
nodeRange ããselectionRange ãèŠãå Žå |
|||
nodeRange.compareBoundaryPoints( Range.START_TO_START, selectionRange ) |
äºã€ã®Rangeã®å§ç¹å士ã®äœçœ®ãæ¯èŒ | -1 | nodeRange ã®å§ç¹ã¯ãselectionRange ã®å§ç¹ãããåã«ãã |
nodeRange.compareBoundaryPoints( Range.START_TO_END, selectionRange ) |
selectionRange ã®å§ç¹ãšãnodeRange ã®çµç¹ãæ¯èŒ |
-1 or 0 | nodeRange ã®çµç¹ã¯ãselectionRange ã®å§ç¹ãããåããŸãã¯ãåãäœçœ®ã«ãã |
nodeRange.compareBoundaryPoints( Range.END_TO_START, selectionRange ) |
selectionRange ã®çµç¹ãšãnodeRange ã®å§ç¹ãæ¯èŒ |
-1 | nodeRange ã®å§ç¹ã¯ãselectionRange ã®çµç¹ãããåã«ãã |
nodeRange.compareBoundaryPoints( Range.END_TO_END, selectionRange ) |
äºã€ã®Rangeã®çµç¹å士ã®äœçœ®ãæ¯èŒ | -1 | nodeRange ã®çµç¹ã¯ãselectionRange ã®çµç¹ãããåã«ãã |
selectionRange ããnodeRange ãèŠãå Žå |
|||
selectionRange.compareBoundaryPoints( Range.START_TO_START, nodeRange ) |
äºã€ã®Rangeã®å§ç¹å士ã®äœçœ®ãæ¯èŒ | 1 | selectionRange ã®å§ç¹ã¯ãnodeRange ã®å§ç¹ãããåŸã«ãã |
selectionRange.compareBoundaryPoints( Range.START_TO_END, nodeRange ) |
nodeRange ã®å§ç¹ãšãselectionRange ã®çµç¹ãæ¯èŒ |
1 | selectionRange ã®çµç¹ã¯ãnodeRange ã®å§ç¹ãããåŸã«ãã |
selectionRange.compareBoundaryPoints( Range.END_TO_START, nodeRange ) |
nodeRange ã®çµç¹ãšãselectionRange ã®å§ç¹ãæ¯èŒ |
1 or 0 | selectionRange ã®å§ç¹ã¯ãnodeRange ã®çµç¹ãããåŸããŸãã¯ãåãäœçœ®ã«ãã |
selectionRange.compareBoundaryPoints( Range.END_TO_END, nodeRange ) |
äºã€ã®Rangeã®çµç¹å士ã®äœçœ®ãæ¯èŒ | 1 | selectionRange ã®çµç¹ã¯ãnodeRange ã®çµç¹ãããåŸã«ãã |
次ã«ãnodeRange
ãselectionRange
ã«å«ãŸããŠããå Žåã
ã³ãŒã | ã³ãŒãã®æå³ | è¿ãå€ | è¿ãå€ã®æå³ |
---|---|---|---|
nodeRange ããselectionRange ãèŠãå Žå |
|||
nodeRange.compareBoundaryPoints( Range.START_TO_START, selectionRange ) |
äºã€ã®Rangeã®å§ç¹å士ã®äœçœ®ãæ¯èŒ | 1 or 0 | nodeRange ã®å§ç¹ã¯ãselectionRange ã®å§ç¹ãããåŸããŸãã¯ãåãäœçœ®ã«ãã |
nodeRange.compareBoundaryPoints( Range.START_TO_END, selectionRange ) |
selectionRange ã®å§ç¹ãšãnodeRange ã®çµç¹ãæ¯èŒ |
1 | nodeRange ã®çµç¹ã¯ãselectionRange ã®å§ç¹ãããåŸã«ãã |
nodeRange.compareBoundaryPoints( Range.END_TO_START, selectionRange ) |
selectionRange ã®çµç¹ãšãnodeRange ã®å§ç¹ãæ¯èŒ |
-1 | nodeRange ã®å§ç¹ã¯ãselectionRange ã®çµç¹ãããåã«ãã |
nodeRange.compareBoundaryPoints( Range.END_TO_END, selectionRange ) |
äºã€ã®Rangeã®çµç¹å士ã®äœçœ®ãæ¯èŒ | -1 or 0 | nodeRange ã®çµç¹ã¯ãselectionRange ã®çµç¹ãããåããŸãã¯ãåãäœçœ®ã«ãã |
selectionRange ããnodeRange ãèŠãå Žå |
|||
selectionRange.compareBoundaryPoints( Range.START_TO_START, nodeRange ) |
äºã€ã®Rangeã®å§ç¹å士ã®äœçœ®ãæ¯èŒ | -1 or 0 | selectionRange ã®å§ç¹ã¯ãnodeRange ã®å§ç¹ãããåããŸãã¯ãåãäœçœ®ã«ãã |
selectionRange.compareBoundaryPoints( Range.START_TO_END, nodeRange ) |
nodeRange ã®å§ç¹ãšãselectionRange ã®çµç¹ãæ¯èŒ |
1 | selectionRange ã®çµç¹ã¯ãnodeRange ã®å§ç¹ãããåŸã«ãã |
selectionRange.compareBoundaryPoints( Range.END_TO_START, nodeRange ) |
nodeRange ã®çµç¹ãšãselectionRange ã®å§ç¹ãæ¯èŒ |
-1 | selectionRange ã®å§ç¹ã¯ãnodeRange ã®çµç¹ãããåã«ãã |
selectionRange.compareBoundaryPoints( Range.END_TO_END, nodeRange ) |
äºã€ã®Rangeã®çµç¹å士ã®äœçœ®ãæ¯èŒ | 1 or 0 | selectionRange ã®çµç¹ã¯ãnodeRange ã®çµç¹ãããåŸããŸãã¯ãåãäœçœ®ã«ãã |
æåŸã«ãnodeRange
ãselectionRange
ãããåŸã®äœçœ®ã«ããå Žåã
ã³ãŒã | ã³ãŒãã®æå³ | è¿ãå€ | è¿ãå€ã®æå³ |
---|---|---|---|
nodeRange ããselectionRange ãèŠãå Žå |
|||
nodeRange.compareBoundaryPoints( Range.START_TO_START, selectionRange ) |
äºã€ã®Rangeã®å§ç¹å士ã®äœçœ®ãæ¯èŒ | 1 | nodeRange ã®å§ç¹ã¯ãselectionRange ã®å§ç¹ãããåŸã«ãã |
nodeRange.compareBoundaryPoints( Range.START_TO_END, selectionRange ) |
selectionRange ã®å§ç¹ãšãnodeRange ã®çµç¹ãæ¯èŒ |
1 | nodeRange ã®çµç¹ã¯ãselectionRange ã®å§ç¹ãããåŸã«ãã |
nodeRange.compareBoundaryPoints( Range.END_TO_START, selectionRange ) |
selectionRange ã®çµç¹ãšãnodeRange ã®å§ç¹ãæ¯èŒ |
1 or 0 | nodeRange ã®å§ç¹ã¯ãselectionRange ã®çµç¹ãããåŸããŸãã¯ãåãäœçœ®ã«ãã |
nodeRange.compareBoundaryPoints( Range.END_TO_END, selectionRange ) |
äºã€ã®Rangeã®çµç¹å士ã®äœçœ®ãæ¯èŒ | 1 | nodeRange ã®çµç¹ã¯ãselectionRange ã®çµç¹ãããåŸã«ãã |
selectionRange ããnodeRange ãèŠãå Žå |
|||
selectionRange.compareBoundaryPoints( Range.START_TO_START, nodeRange ) |
äºã€ã®Rangeã®å§ç¹å士ã®äœçœ®ãæ¯èŒ | -1 | selectionRange ã®å§ç¹ã¯ãnodeRange ã®å§ç¹ãããåã«ãã |
selectionRange.compareBoundaryPoints( Range.START_TO_END, nodeRange ) |
nodeRange ã®å§ç¹ãšãselectionRange ã®çµç¹ãæ¯èŒ |
-1 or 0 | selectionRange ã®çµç¹ã¯ãnodeRange ã®å§ç¹ãããåããŸãã¯ãåãäœçœ®ã«ãã |
selectionRange.compareBoundaryPoints( Range.END_TO_START, nodeRange ) |
nodeRange ã®çµç¹ãšãselectionRange ã®å§ç¹ãæ¯èŒ |
-1 | selectionRange ã®å§ç¹ã¯ãnodeRange ã®çµç¹ãããåã«ãã |
selectionRange.compareBoundaryPoints( Range.END_TO_END, nodeRange ) |
äºã€ã®Rangeã®çµç¹å士ã®äœçœ®ãæ¯èŒ | -1 | selectionRange ã®çµç¹ã¯ãnodeRange ã®çµç¹ãããåã«ãã |
åè¿°ã®è¡šã«åŸããšããnodeRangeãselectionRangeã®äžã«ãããã©ãããã¯ä»¥äžã®ããã«ããã°å€å¥ã§ããããšã«ãªããŸãã
var node = selectionRange.startContainer;
var nodeRange = aWindow.document.createRange();
traceTree:
while (true)
{
// nodeRangeã®çµç¹ãselectionRangeã®äžã«ããå Žå
if (nodeRange.compareBoundaryPoints(Range.START_TO_END, selectionRange) > -1) {
// nodeRangeã®å§ç¹ãselectionRangeã®å€ã«ããå ŽåïŒnodeRangeãselectionRangeãããåŸã«ããïŒ
if (nodeRange.compareBoundaryPoints(Range.END_TO_START, selectionRange) > 0) {
// éžæç¯å²ã®èµ°æ»ãçµããã®ã§ãã«ãŒããæãã
break;
}
else if (node.href)
links.push(node);
}
ïŒç¥ïŒ
ããŠã以äžã®ãããªå ŽåãæåãšæåŸã®ãªã³ã¯ã¯ã©ã®ããã«æ±ãã¹ãã§ããããïŒ
<ul>
<li><a href="01.html">æåã®ãããããéžæâããªã³ã¯</a></li>
<li><a href="02.html">çãäžã®ãªã³ã¯</a></li>
<li><a href="03.html">ãâãããŸã§éžæãæåŸã®ãªã³ã¯</a></li>
</ul>
æåã®ãªã³ã¯ã¯ãéäžãããšã¯ããéžæãããŠããŸãããããéžæãããŠããããšèŠãªããŠããã§ãããããããåè¿°ãŸã§ã®åŠçã§ã¯ãããã¯ãéžæç¯å²å€ã®ãªã³ã¯ããšããŠæ±ãããŠããŸããŸãã
æåŸã®ãªã³ã¯ã¯ãäžå¿éžæç¯å²ã«å«ãŸããŠã¯ããŸãããå 容ã®ããã¹ãã¯äžæåãéžæãããŠããŸãããããã¯è¡éžæãããæãªã©ã«ããèµ·ããçŸè±¡ã§ãïŒåæ§ã®çŸè±¡ããéžæç¯å²ã®å é ã§ãèµ·ããåŸãŸãïŒãåè¿°ãŸã§ã®åŠçã§ã¯ããã®ãéžæãããŠããããã«ã¯èŠããªãããªã³ã¯ãŸã§ãããéžæç¯å²å ã®ãªã³ã¯ããšããŠæ±ãããŠããŸããŸãã
ãšããããšã§ããããã«å¯ŸããäŸå€åŠçãè¡ããªããŠã¯ãªããŸããã
ãªã³ã¯ã®èŠçŽ ããŒããã®ãã®ã¯éžæç¯å²å€ãšèŠãªãããŠããŠãããªã³ã¯å ã®ããã¹ãããŒãã¯éžæç¯å²å ã«ãããšèªèãããŠããã®ã§ããããå©çšããŸããããã€ãŸããèµ°æ»ããŠããããŒããã®ãã®ã ãã§ãªããããŒãã®ç¥å èŠçŽ ã«ãªã³ã¯ãããã°ãããåéãããšããããšã§ãã
function getParentLink(aNode)
{
var node = aNode;
while (!node.href && node.parentNode)
node = node.parentNode;
return node.href ? node : null ;
}
var link;
var node = selectionRange.startContainer;
var nodeRange = aWindow.document.createRange();
traceTree:
while (true)
{
if (nodeRange.compareBoundaryPoints(Range.START_TO_END, selectionRange) > -1) {
if (nodeRange.compareBoundaryPoints(Range.END_TO_START, selectionRange) > 0) {
break;
}
else if (link = getParentLink(node))
links.push(link);
}
// æ¢ã«ãªã³ã¯ãšããŠåŠçããå Žåã¯ãåèŠçŽ ã®èµ°æ»ãã¹ããããã
if (node.hasChildNodes() && !link) {
node = node.firstChild;
}
else {
ïŒç¥ïŒ
ããã¹ãããŒãã®ãéžæç¯å²ã«å«ãŸããŠããéšåã®é·ãã0ã§ãããã©ããã調ã¹ãã°ããã®ãªã³ã¯ããéžæãããŠããããã«ã¯èŠããªãããã©ããç¥ãããšãã§ããŸããããã«ã¯ãRangeã®startOffset
ãšendOffset
ãšããããããã£ãå©çšããŸãã
if (nodeRange.compareBoundaryPoints(Range.END_TO_START, selectionRange) > 0) {
// ããªã³ã¯ããã¹ãã®çŽåŸããçµäºã¿ã°ã®çŽåãã«éžæç¯å²ã®å§ç¹ãããå Žåãæåã®ãªã³ã¯ãé€å€ãã
if (
links.length &&
selectionRange.startContent.nodeType != Node.ELEMENT_NODE &&
selectionRange.startOffset == selectionRange.startContainer.nodeValue.length &&
links[0] == getParentLink(selectionRange.startContainer)
)
links.splice(0, 1);
// ããªã³ã¯ããã¹ãã®çŽåããéå§ã¿ã°ã®çŽåŸãã«éžæç¯å²ã®çµç¹ãããå ŽåãæåŸã®ãªã³ã¯ãé€å€ãã
if (
links.length &&
selectionRange.endContainer.nodeType != Node.ELEMENT_NODE &&
selectionRange.endOffset == 0 &&
links[links.length-1] == getParentLink(selectionRange.endContainer)
)
links.splice(links.length-1, 1);
break;
}ïŒç¥ïŒ
以äžã§ããéžæç¯å²ã®ãªã³ã¯ãåéãããåŠçã¯ã§ããããã§ãããããŸã§ã®ãŸãšãã以äžã«ç€ºããŸãããæ¹å€ãäºæ¬¡å©çšãäžåå¶éããŸããã®ã§ã奜ãã«äœ¿ã£ãŠãã ããã
function getSelectionLinksInFrame(aWindow)
{
var links = [];
var selection = aWindow.getSelection();
if (!selection || !selection.rangeCount) return links;
const count = selection.rangeCount;
var range,
node,
link,
nodeRange = aWindow.document.createRange();
for (var i = 0; i < count; i++)
{
selectionRange = selection.getRangeAt(i);
node = selectionRange.startContainer;
traceTree:
while (true)
{
nodeRange.selectNode(node);
if (nodeRange.compareBoundaryPoints(Range.START_TO_END, selectionRange) > -1) {
if (nodeRange.compareBoundaryPoints(Range.END_TO_START, selectionRange) > 0) {
if (
links.length &&
selectionRange.startContent.nodeType != Node.ELEMENT_NODE &&
selectionRange.startOffset == selectionRange.startContainer.nodeValue.length &&
links[0] == getParentLink(selectionRange.startContainer)
)
links.splice(0, 1);
if (
links.length &&
selectionRange.endContainer.nodeType != Node.ELEMENT_NODE &&
selectionRange.endOffset == 0 &&
links[links.length-1] == getParentLink(selectionRange.endContainer)
)
links.splice(links.length-1, 1);
break;
}
else if (link = getParentLink(node))
links.push(link);
}
if (node.hasChildNodes() && !link) {
node = node.firstChild;
}
else {
while (!node.nextSibling)
{
node = node.parentNode;
if (!node) break traceTree;
}
node = node.nextSibling;
}
}
}
nodeRange.detach();
return links;
}
function getParentLink(aNode)
{
var node = aNode;
while (!node.href && node.parentNode)
node = node.parentNode;
return node.href ? node : null ;
}