armag3ddon: Befindet sich ein Element in einem bestimmten anderen?

Hallo!

Mein Problem ist folgendermaßen:
Ich will per Javascript auf einer Website alle Links hervorheben, indem ich hinter ihnen direkt einen kleinen Hinweistext "Link" einfüge (da man die Links ansonsten nur schwer erkennen kann).
Hier der bisherige Script dazu:

function HighlightLinks()
{
 for (var i = 0 ; i < document.links.length ; i++)
 {
  if(document.links[i].href)
  {
   var span = document.createElement("span");
   var spantext = document.createTextNode(" Link");
   span.appendChild(spantext);
   document.links[i].parentNode.insertBefore(span, document.links[i].nextSibling);
   span.className="Minilink"
  }
 }
}

Mein Problem:
Auf der Seite gibt es eindeutige Navigationsleiste, in der die Links erkennbar sind. Diese sollen also keinen Hinweistext bekommen. Alle Links, die so einen erhalten sollen befinden sich in einem DIV-Element mit der Id "inhalt". Ich wüsste eine Lösung dazu, die allerdings einer umständlichen Schleife bedarf. Gibt es also eine einfache Möglichkeit abzufragen, ob sich ein Element in einem bestimmten anderen befindet?

  1. Hallo,

    function HighlightLinks(){
       var i=0;
       var a=document.getElementById('inhalt').getElementsByTagName('a');

    for(i in a){
          if(a[i].href && (a[i].href!='' || a[i].href!='#')){

    var span = document.createElement("span");
          var spantext = document.createTextNode(" Link");
          span.appendChild(spantext);
          span.className="Minilink"
          a[i].parentNode.insertBefore(span,a[i].nextSibling);
        }
    }

    }

    Gruß aus Berlin!
    eddi

    1. Hach ja, auf so eine einfache Lösung bin ich natürlich wieder nicht gekommen ;)

      Besten Dank auch und Gruß zurück aus Bremen!

  2. Hello out there!

    Ich will per Javascript auf einer Website alle Links hervorheben, indem ich hinter ihnen direkt einen kleinen Hinweistext "Link" einfüge (da man die Links ansonsten nur schwer erkennen kann).

    _Das_ ist ein Problem. Vielleicht solltest du dieses an den Wurzeln beheben, anstatt zu versuchen, die Symptome zu lindern?

    Alle Links, die so einen erhalten sollen befinden sich in einem DIV-Element mit der Id "inhalt".

    Dazu ist in funktionstüchtigen Browsern kein JavaScript erforderlich; das geht mit CSS:

    #inhalt a::after {  
      content: " Link";  
    }
    

    Das JavaScript kannst du für veraltete IEs per conditional comments einfügen.

    See ya up the road,
    Gunnar

    --
    “Remember, in the end, nobody wins unless everybody wins.” (Bruce Springsteen)
    1. Hallo Gunnar.

      Dazu ist in funktionstüchtigen Browsern kein JavaScript erforderlich; das geht mit CSS:

      #inhalt a::after {

      content: " Link";
      }

      
      >   
      > Das JavaScript kannst du für veraltete IEs per conditional comments einfügen.  
        
      Abgesehen davon bliebe natürlich auch immer noch die Variante, die selbst in den IEs funktioniert:  
        
      ~~~css
      #inhalt a {  
        background: url(grafik-mit-link-symbol-oder-text.png) no-repeat center right;  
        padding-right: …px; /* Breite der Grafik + ggf. etwas Freiraum */  
      }
      

      Einen schönen Samstag noch.

      Gruß, Ashura

      --
      sh:( fo:} ch:? rl:( br: n4:~ ie:{ mo:| va:) de:> zu:} fl:( ss:) ls:[ js:|
      „It is required that HTML be a common language between all platforms. This implies no device-specific markup, or anything which requires control over fonts or colors, for example. This is in keeping with the SGML ideal.“
      [HTML Design Constraints: Logical Markup]
  3. Hallo,

    Gibt es also eine einfache Möglichkeit abzufragen, ob sich ein Element in einem bestimmten anderen befindet?

    So schwer ist es doch nicht, sich da eine Funktion zu basteln, die sich den DOM-Baum hoch hangelt und nachguckt:

    Element.prototype.isDescendantOf = function (element) {  
        var a = this;  
        var root = this.ownerDocument.documentElement;  
        while (a != root) {  
            a = a.parentNode;  
            if (a == element) {  
                return true  
            }  
        }  
        return false;  
    }
    

    Kleine Warnung für Ausprobierer: Nicht jeder Browser beherrscht die prototypische Erweiterung des Element-Objektes (Safari, fühl' Dich angesprochen!). Infofern sollte man da wohl besser eine eigenständige Funktion wie isDescendantOf(possibleDescendant, possibleAncestor) bauen.

    Tim

    1. Hallo Tim.

      Element.prototype.isDescendantOf = function (element) {}

      Und schon wieder ein mir unbekanntes vorgefertiges Objekt.

      Gibt es eine gute Adresse wo dieses (und die vermutlich hundert anderen mir noch nicht bekannten vorgefertigten Objekte) dokumentiert ist?

      Einen schönen Sonntag noch.

      Gruß, Ashura

      --
      sh:( fo:} ch:? rl:( br: n4:~ ie:{ mo:| va:) de:> zu:} fl:( ss:) ls:[ js:|
      „It is required that HTML be a common language between all platforms. This implies no device-specific markup, or anything which requires control over fonts or colors, for example. This is in keeping with the SGML ideal.“
      [HTML Design Constraints: Logical Markup]
      1. Hallo Ashura,

        Element.prototype.isDescendantOf = function (element) {}
        Und schon wieder ein mir unbekanntes vorgefertiges Objekt.

        Du meinst Element? Das ist im Prinzip das Objekt* Element aus DOM Core. Ich hätte auch spezifischer HTMLElement aus DOM HTML nehmen können oder Node aus DOM Core, ich nutze ja letztendlich nur dessen Methoden. Geschmackssache.

        * Das Objekt, das das Interface Foo implementiert, ich weiss ...

        Gibt es eine gute Adresse wo dieses (und die vermutlich hundert anderen mir noch nicht bekannten vorgefertigten Objekte) dokumentiert ist?

        Ausser den Interfaces der DOM Spezifikationen? Nicht wirklich, wie ich vorhin ja lernen musste, ist ja nicht so schön sauber implementiert, wie es dort steht. Und Browserinterna sind da eher obskur.

        Tim

        1. Hallo Tim.

          Du meinst Element? Das ist im Prinzip das Objekt* Element aus DOM Core. Ich hätte auch spezifischer HTMLElement aus DOM HTML nehmen können oder Node aus DOM Core, ich nutze ja letztendlich nur dessen Methoden. Geschmackssache.

          Hm, mir ist noch gar nicht aufgefallen, dass ich die in DOM HTML aufgeführten Elementobjekte tatsächlich wörtlich nehmen (sprich: per prototype bearbeiten) kann.

          Gibt es eine gute Adresse wo dieses (und die vermutlich hundert anderen mir noch nicht bekannten vorgefertigten Objekte) dokumentiert ist?

          Ausser den Interfaces der DOM Spezifikationen? Nicht wirklich, wie ich vorhin ja lernen musste, ist ja nicht so schön sauber implementiert, wie es dort steht. Und Browserinterna sind da eher obskur.

          Das kommt natürlich erschwerend hinzu ja. Aber trotzdem danke, dass du mir dieses Brett vorm Kopf weggezogen hast.

          Einen schönen Sonntag noch.

          Gruß, Ashura

          --
          sh:( fo:} ch:? rl:( br: n4:~ ie:{ mo:| va:) de:> zu:} fl:( ss:) ls:[ js:|
          „It is required that HTML be a common language between all platforms. This implies no device-specific markup, or anything which requires control over fonts or colors, for example. This is in keeping with the SGML ideal.“
          [HTML Design Constraints: Logical Markup]
    2. Hallo,

      Gibt es also eine einfache Möglichkeit abzufragen, ob sich ein Element in einem bestimmten anderen befindet?

      So schwer ist es doch nicht, sich da eine Funktion zu basteln, die sich den DOM-Baum hoch hangelt und nachguckt:

      Einige Browser kennen die Methode contains() und für Gecko ist ein Workaround möglich. Ich denke mal, das ist performanter als das händische Aufsteigen im Baum.

      Kleine Warnung für Ausprobierer: Nicht jeder Browser beherrscht die prototypische Erweiterung des Element-Objektes (Safari, fühl' Dich angesprochen!).

      Die prototypische Erweiterung wäre im Grunde nur Gecko notwendig, und da gibt es speziellere DOM-Methoden.

      Mathias

      1. Hallo Mathias,

        Einige Browser kennen die Methode contains() und für Gecko ist ein Workaround möglich. Ich denke mal, das ist performanter als das händische Aufsteigen im Baum.

        Nein und Ja. ;)

        Nein für den Fall, dass bei contains() tatsächlich der Baum traversiert wird. Da wäre meine Methode perfomanter, im worst case muss werden dort nur so viele Vergleiche durchgeführt, wie das Element von der Wurzel des Baumes entfernt ist. Bei der Semantik von contains() müssten dann alle Kindelemente verglichen werden, sprich exponential mehr Vergleiche.

        Ja, weeil: Wenn es solche Funktionen gibt, wäre man hinverbrannt neben der reinen Baumstruktur des DOMs für genau diese Fälle zusätzliche Datenstrukturen für andere Zugriffsmöglichkeiten vorzuhalten, wenn auch nicht im JS-DOM exponiert. Und dieser dürften dann sehr viel schneller sein als ein Traversieren des Baum.

        Danke übrigens für den Hinweis auf compareDocumentPosition(). Kannte ich noch nicht.

        Die prototypische Erweiterung wäre im Grunde nur Gecko notwendig, und da gibt es speziellere DOM-Methoden.

        Ich bin mit der Gesamtsitation unzufrieden. Ich bin in der letzen Zeit öfters über Momente gestolpert, in denen ich HTMLElement oder anderes prototypisch hätte erweitern wollen, es ging aber nicht. Ich prangere dies an!

        Tim

        1. Hallo,

          im worst case muss werden dort nur so viele Vergleiche durchgeführt, wie das Element von der Wurzel des Baumes entfernt ist. Bei der Semantik von contains() müssten dann alle Kindelemente verglichen werden, sprich exponential mehr Vergleiche.

          Das verstehe ich nicht, wieso sollte ein Browser mehr Vergleiche anstellen? Schau dir z.B. mal den KHTML-Code an:

          ecma/kjs_dom.cpp

          case DOMNode::Contains:
              {
                DOM::NodeImpl* other = toNode(args[0]);
                if (other && node.isElementNode())
                {
                    bool retval = other->isAncestor(&node);
                    return Boolean(retval);
                }
                return Undefined();
              }

          xml/dom_nodeimpl.cpp

          bool NodeImpl::isAncestor( NodeImpl *other )
          {
              // Return true if other is the same as this node or an ancestor of it, otherwise false
              NodeImpl *n;
              for (n = this; n; n = n->parentNode()) {
                  if (n == other)
                      return true;
              }
              return false;
          }

          Das ist deine Methode in C++.

          Mathias

          1. Hallo Mathias,

            Das verstehe ich nicht, wieso sollte ein Browser mehr Vergleiche anstellen?

            Mein Fehler. Ich war davon ausgegangen, dass bei contains() der Baum nach unten gehangelt werden muss, weil man auf der _Suche_ nach einem Knoten ist:

            root
            * eins
              * zwei
              * drei
                * vier
            * fünf
              * sechs
                * sieben
                  * acht
              * neun

            root.contains(acht) müsste bei einem Traversien auf der Suche nach dem Knoten "acht" acht Vergleiche anstellen.

            (other == eins)   -> false
            (other == zwei)   -> false
            (other == drei)   -> false
            (other == vier)   -> false
            (other == fünf)   -> false
            (other == sechs)  -> false
            (other == sieben) -> false
            (other == acht)   -> true

            Allerdings: Wir kennen den Knoten ja schon ja schon, wir können also auf ihn zugreifen. Ich habe also gedanklich eine Suche assoziert, dabei sagt die Semantik von contains() ja nur: Verwandtschaftsbeziehung zwischen zwei bekannten Knoten. Und dann, ja, dann kann man vom „Zielknoten“ den Baum hochtraversieren, hier sind es nur vier Vergleiche. Anders wäre es wohl, würde man nach einem unbekannten Knoten suchen, der eine bestimmte Eigenschaft hätte, z.B. einen bestimmten String enthalten.

            In drei Worten: Du hast recht. ;)

            Tim