Andreas Dölling: IE: Laufzeitfehler ohne erkennbaren Grund

Hallo,

ich möchte auf einer Suchergebnisseite die Vorkommen der Suchbegriffe markieren. Dazu verpacke ich sie jeweils in ein SPAN-Element mit der Klasse "marker".

Die Suchbegriffe lese ich zunächst aus dem Eingabefeld heraus, wo sie angezeigt werden. Jeder Term ist dabei eingeschlossen in * oder ".

Nachdem ich die Suchbegriffe geordnet habe, hole ich mir nun das innerHTML der Ergebnistabelle, um dies zu manipulieren. (Der Ansatz über die Textknoten war mir hier einfach zu aufwendig.)
Ich iteriere einfach über die Suchbegriffe, trenne den Inhalt an jedem Vorkommen des Begriffs mit split() auf und füge den so erhaltenen Array per join() wieder zusammen, wobei als "Kleber" das Suchwort mit dem bereits erwähnten SPAN benutzt wird.

Soweit zu meinem Ansatz (bessere Vorschläge?).

Im Firefox läuft es problemlos und schnell.
Opera führt die Aktion an sich fehlerfrei aus, zeigt dann allerdings die Tabelle nicht mehr als Tabelle an, sondern als Fließtext.
Und der IE bricht in der Zeile tableObj.innerHTML = tmpContent; mit der schönen Meldung "Unbekannter Laufzeitfehler" ab.

Habt Ihr irgendeine Idee dazu?

Noch zwei Hinweise:

  • Der JS-Code wird nach dem onload-Event ausgeführt, d.h. alle DOM-Elemente sind da.
  • Der IE macht bis auf die letzte Zeile alles richtig, wie Testausgaben zeigten.

Hm, vielleicht ist aber mein Ansatz insgesamt schlecht, und ich sollte doch lieber über die Textknoten gehen? Mir gibt jedenfalls auch das Verhalten von Opera zu denken.

Der Code:

var inputObj = document.getElementById('search');
 var termsRegExp = new RegExp('(?:\*|")([^\*]*)(?:\*|")', 'gi');
 var sortRegExp;
 var matches;
 var searchTerms = new Array();
 var tableObj = document.getElementById('oneColumn').getElementsByTagName('table')[0];
 var contentFragments;
 var i;
 var tmpContent = '';

function termSort(a, b) {
  sortRegExp = new RegExp(b, 'i');
  if(sortRegExp.test(a)) {
   return -1;
  } else {
   return 0;
  }
 }

while(matches = termsRegExp.exec(inputObj.value)) {
  searchTerms[searchTerms.length] = matches[1];
 }

searchTerms.sort();    // first sort lexically
 searchTerms.sort(termSort);  // push words before the terms they contain (e.g. 'Arbeitssicherheit' must precede 'Arbeit')

tmpContent = tableObj.innerHTML;
 for(i=0; i<searchTerms.length; i++) {
  contentFragments = tmpContent.split(searchTerms[i]);
  tmpContent = contentFragments.join('<span class="marker">' + searchTerms[i] + '</span>');
 }
 tableObj.innerHTML = tmpContent;

Thanx und ciao,
Andreas

--
"Das Corporate Design für das Internet sieht eine Reihe von Grafikelementen vor, die die Optik der Webseite visuell und funktionell beeinflussen." - (Zitat aus dem "Styleguide Corporate Design"  eines großen Konzerns...)
  1. Hallo Andreas,

    eine schnelle Idee: lösche einfach die Tabelle vorm beschreiben:
     tableObj.innerHTML = "";
     tableObj.innerHTML = tmpContent;

    Allerdings habe ich schon öfter gehört, dass innerHTML und Tabellen kritisch sein sollen. Vieleicht solltest du nicht alles zwischen <table> und </table> bearbeiten, sondern dich nur auf die Tabellenfelder beschränken. Die Tabelle hast du ja schon, also musst du dich nur noch durch die tableObj.getElementsByTagName('td') durchhangeln. So bearbeitest du die Inhalte der Tabelle, die Struktur bleibt aber erhalten. Bei meinem Tabellensortierer gehe ich so vor und mir sind keine Probleme bekannt. Ich lösche übrigens auch hier die Felder vor dem Beschreiben mit innerHTML.

    Gruß, Jürgen

    1. Hallo,

      Vieleicht solltest du nicht alles zwischen <table> und </table> bearbeiten, sondern dich nur auf die Tabellenfelder beschränken.

      danke für den Tipp.
      Hatte schon die gleiche Idee - und es funktioniert (s.o.).
      ;)

      Ciao,
      Andreas

      --
      "Das Corporate Design für das Internet sieht eine Reihe von Grafikelementen vor, die die Optik der Webseite visuell und funktionell beeinflussen." - (Zitat aus dem "Styleguide Corporate Design"  eines großen Konzerns...)
  2. Hallo,

    da ich den Verdacht habe, daß das Problem darin besteht, wie die Browser einen TABLE-Knoten intern abbilden und ob sie ggf. ein TBODY automatisch ergänzen oder nicht, habe ich meinen Ansatz dahingehend abgewandelt, daß ich nun über die einzelnen TD-Knoten gehe und dort jeweils die Ersetzungen vornehme.

    Das klappt nun auch im IE und in Opera.

    Das einzige noch bestehende Problem, ist, daß sowohl IE als auch Opera den Array mit den Suchbegriffen nicht so sortieren, wie ich das möchte.
    Angenommen, wir haben die Suchbegriffe "Arbeit", "Beispiel" und "Arbeitsschutz". Dann müßte nach dem lexikalischen Sortieren die Reihenfolge sein: "Arbeit", "Arbeitsschutz", "Beispiel" (machen alle Browser richtig).
    Und nach dem zweiten Sortiervorgang mit der Funktion termSort(): "Arbeitsschutz", "Arbeit", "Beispiel" (macht nur Firefox richtig.

    Woran kann das denn liegen? Ideen?

    Hier der - fast - funktionierende abgeänderte Quellcode:

    var inputObj = document.getElementById('search');
     var termsRegExp = new RegExp('(?:\*|")([^\*]*)(?:\*|")', 'gi');
     var sortRegExp;
     var matches;
     var searchTerms = new Array();
     var tableObj = document.getElementById('oneColumn').getElementsByTagName('table')[0];
     var tdColl = tableObj.getElementsByTagName('td');
     var i, k;
     var contentFragments;
     var tmpContent = '';

    function termSort(a, b) {
      sortRegExp = new RegExp(b, 'i');
      if(sortRegExp.test(a)) {
       return -1;
      } else {
       return 0;
      }
     }

    while(matches = termsRegExp.exec(inputObj.value)) {
      searchTerms[searchTerms.length] = matches[1];
     }

    searchTerms.sort();    // first sort lexically
     searchTerms.sort(termSort);  // push words before the terms they contain (e.g. 'Arbeitssicherheit' must precede 'Arbeit')

    for(i=0; i<tdColl.length; i++) {
      tmpContent = tdColl[i].innerHTML;
      for(k=0; k<searchTerms.length; k++) {
       contentFragments = tmpContent.split(searchTerms[k]);
       tmpContent = contentFragments.join('<span class="marker">' + searchTerms[k] + '</span>');
      }
      tdColl[i].innerHTML = tmpContent;
     }

    Thanx und ciao,
    Andreas

    --
    "Das Corporate Design für das Internet sieht eine Reihe von Grafikelementen vor, die die Optik der Webseite visuell und funktionell beeinflussen." - (Zitat aus dem "Styleguide Corporate Design"  eines großen Konzerns...)
    1. Hallo Andreas Dölling,

      ich bin jetzt nicht der RegExp-Experte, daher kann ich zu deine Vergleichsfunktion auch nichts sagen. Ich habe nur eine Idee: wenn du an die Worte vor dem Vergleichen ein "z" hängst, oder besser noch das ASCII-Zeichen nach dem "z", liefert der Vergleich 'Arbeitssicherheitz' vor 'Arbeitz'. Also als Vergleichsfunktion:

      function termSort(a, b) {
        a+="zzz";
        b+="zzz";
        if (a<b) return -1;
        else return 0;
      }

      Gruß, Jürgen

      1. Hallo,

        ich habe es jetzt anders gelöst, indem ich einen "bubble sort" benutze.
        Jetzt läuft alles wie gewünscht!

        Hier der Quellcode:

        var inputObj = document.getElementById('search');
         var termsRegExp = new RegExp('(?:\*|")([^\*]*)(?:\*|")', 'gi');
         var markRegExp;
         var sortRegExp;
         var matches;
         var searchTerms = new Array();
         var tableObj = document.getElementById('oneColumn').getElementsByTagName('table')[0];
         var tdColl = tableObj.getElementsByTagName('td');
         var i, k;
         var contentFragments;
         var tmpContent = '';

        function termSort(a, b) {alert(a + ' : ' + b + "\n(" + searchTerms + ')');
          sortRegExp = new RegExp(b, 'i');
          if(sortRegExp.test(a)) {alert(1);
           return 5;
          } else {
           return 0;
          }
         }

        function sortTerms() {
          // bubble sort
          var x, y, tmp;
          for(x = 0; x < searchTerms.length; x++) {
           for(y = 0; y < (searchTerms.length-1); y++) {
            sortRegExp = new RegExp(searchTerms[y+1], 'i');
            if(!sortRegExp.test(searchTerms[y])) {
             tmp = searchTerms[y+1];
             searchTerms[y+1] = searchTerms[y];
             searchTerms[y] = tmp;
            }
           }
          }
         }

        while(matches = termsRegExp.exec(inputObj.value)) {
          searchTerms[searchTerms.length] = matches[1];
         }

        sortTerms();

        for(i=0; i<tdColl.length; i++) {
          tmpContent = tdColl[i].innerHTML;
          for(k=0; k<searchTerms.length; k++) {
           markRegExp = new RegExp('(' + searchTerms[k] + ')', 'gi');
           tmpContent = tmpContent.replace(markRegExp, '<span class="marker">$1</span>');
          }
          tdColl[i].innerHTML = tmpContent;
         }

        Thanx und ciao,
        Andreas

        --
        "Das Corporate Design für das Internet sieht eine Reihe von Grafikelementen vor, die die Optik der Webseite visuell und funktionell beeinflussen." - (Zitat aus dem "Styleguide Corporate Design"  eines großen Konzerns...)
      2. Hallo,

        Nach dem Lesen von Struppis Beitrag muss ich hier noch eine Korrektur anbringen:

        function termSort(a, b) {
          a+="zzz";
          b+="zzz";
          if (a<b) return -1;

        else if (a>b) return 1;

        else return 0;
        }

        Gruß, Jürgen

    2. Woran kann das denn liegen? Ideen?

      Die Sortierfunktion muss drei Werte zurückgeben, nicht zwei. kleiner, gleich oder größer Null.
      http://de.selfhtml.org/javascript/objekte/array.htm#sort

      Struppi.

      1. Wobei du das, glaube ich, auch mit einem normalen Vergleich machen kannst

        if(a > b) return 1;
        if(a < b) return -1;
        return 0;

        Struppi.