Eine Suchfunktion läuft nicht mehr

Status
Dieses Thema wurde gelöst! Zur Lösung gehen…

Webhufi

Erfahrenes Mitglied
Hallo,

ich hatte auf einer alten Seite - die leider verschwunden ist - eine Suche drin, die ich jetzt auf eine andere Page übernommen habe; nur diesen HTML-Teil hatte ich gerettet.
Leider funktioniert diese Suche nicht, wahrscheinlich fehlt etwas (ein Script?)

Ich erinnere mich, dass es recht einfach und ebenso kurz war, es funktionierte nur auf der Seite, in die es eingebaut war; mehr ist nicht notwendig.

Natürlich gibt es im Web solche Suchfunktionen, aber die sind mir alle zu aufgebauscht, und verstehen kann ich sie sowieso nicht.

Hat jemand eine Idee - und auch Lust dazu - diese Suche (etwas weiter unten) wieder zum Laufen zu bringen? Das würde mich sehr freuen!

Viele Grüße
Norbert
 

Sempervivum

Erfahrenes Mitglied
Hallo Norbert und willkommen zurück!
Um mich nicht durch die Ergebnisse von Google durchkämpfen zu müssen, habe ich schnell einen Algorithmus geschrieben, der die Textknoten des Dokumentes durchsucht und die Fundstellen in ein span-Element einbettet, so dass man sie mit CSS hervor heben kann.
Code:
        function search(node, needle) {
            node.childNodes.forEach(node => {
                switch (node.nodeType) {
                    // Handelt es sich um einen Elementknoten?
                    case 1:
                        // Suche fortsetzen
                        search(node, needle);
                        break;
                    // Handelt es sich um einen Textknoten?
                    case 3:
                        // Den Text heraus ziehen
                        const txt = node.textContent;
                        // Um den gefundenen Text hervor zu heben, betten wir ihn ein ein
                        // span-Element ein, das wir dann geeignet mit CSS gestalten koennen.
                        // In einem Textknoten wird jedoch kein HTML interpretiert.
                        // Daher erzeugen wir ein neues span-Element und tragen dort den
                        // geaenderten Text ein.
                        let newEle = document.createElement('span');
                        newEle.innerHTML = txt.replace(needle, '<span class="found">' + needle + '</span>')
                        node.replaceWith(newEle);
                        break;
                }
            });
        }

        // Die folgende Funktion wird durch das Suchformular aufgerufen
        // und startet die Suche
        function suchen(needle) {
            search(document.querySelector('body'), needle);
            return false;
        }
Was noch zu tun ist:
Das Durchgehen der Suchergebnisse mit Enter programmieren. Könnte ich mir so vorstellen, dass man den spans mit den Fundstellen eine nummerierte ID zuweist und diese dann als Anker verwendet, um dort hin zu springen.
 
Zuletzt bearbeitet:

Sempervivum

Erfahrenes Mitglied
Auch der nächste Schritt ist getan: Durchgehen der Fundstellen mit Enter:
Code:
    <script>
        function search(node, needle) {
            node.childNodes.forEach(node => {
                switch (node.nodeType) {
                    // Handelt es sich um einen Elementknoten?
                    case 1:
                        // Suche fortsetzen
                        search(node, needle);
                        break;
                    // Handelt es sich um einen Textknoten?
                    case 3:
                        // Den Text heraus ziehen
                        const txt = node.textContent.trim();
                        // console.log(txt)
                        if (txt != '') {
                            // Um den gefundenen Text hervor zu heben, betten wir ihn ein
                            // span-Element ein, das wir dann geeignet mit CSS gestalten koennen.
                            // In einem Textknoten wird jedoch kein HTML interpretiert.
                            // Daher erzeugen wir ein neues span-Element und tragen dort den
                            // geaenderten Text ein.
                            let newEle = document.createElement('span');
                            newEle.innerHTML = txt.replace(needle, '<span class="found">' + needle + '</span>')
                            node.replaceWith(newEle);
                            break;
                        }
                }
            });
        }
        let searchDone = false,
            foundElems,
            idxSearch = 0;
        // Die folgende Funktion wird durch das Suchformular aufgerufen
        // und startet die Suche
        function suchen(needle) {
            // event.preventDefault();
            // Wurde die Suche noch nicht gestartet?
            if (!searchDone) {
                // Suche starten
                search(document.querySelector('body'), needle);
                // Gefundene Element bereit stellen
                foundElems = document.querySelectorAll('.found');
                // Erstes gefundenes Element hervor heben
                foundElems[idxSearch].classList.add('highlight');
                foundElems[idxSearch].scrollIntoView();
                searchDone = true;
            } else {
                // Hevorhebung des alten gefundenen Elementes löschen
                foundElems[idxSearch].classList.remove('highlight');
                // Naechstes gefundenes Element hervor heben
                idxSearch++;
                foundElems[idxSearch].classList.add('highlight');
                foundElems[idxSearch].scrollIntoView();
            }
            return false;
        }
    </script>
Beste Grüße - Ulrich
 

Sempervivum

Erfahrenes Mitglied
PS: Wie ich jetzt erst sehe, funktioniert die alte Suche bei mir einwandfrei (Opera). Allerdings ist das Skript von Anno Tobak, da wird noch NS4 abgefragt :LOL:
 

Webhufi

Erfahrenes Mitglied
Hallo Ulrich,

danke für dein Zurück-Willkommen! :)
Wie du weißt, gibt es immer etwas Ungewöhnliches, wenn ich auftauche... ;-)

Dein Script scheint mir, soweit ich es verstehe (und das wird immer besser, vor allem durch deine Auskommentierungen), recht toll zu sein.
Jedoch funktioniert es nicht so, wie ich es verstehe: Hervorhebung gibt es keine, weitersuchen mit Enter geht nicht, bei einem nicht gefunden Wort gibt es keine Meldung wie im alten Script (z.B. Norbert), die Suche an sich ist case sensitiv: Einstein geht, aber nicht einstein. Schau bitte hier!

Was mir in deinem Script auffällt: Es gibt case 1 und case 3, aber kein case 2.

Dann bitte noch eine Erklärung: was ist ein Element- bzw. Textknoten? Nie gehört...

Herzliche Grüße
Norbert
 

Sempervivum

Erfahrenes Mitglied
Da habe ich etwas wichtiges vergessen: Das Skript setzt nur zwei Klassen, damit die Fundstellen sichtbar werden, muss man noch ein CSS definieren, z. B.:
Code:
.highlight {
    background-color: lightblue !important;
}

Was mir in deinem Script auffällt: Es gibt case 1 und case 3, aber kein case 2.
Das hängt mit den Typen von Knoten zusammen, siehe hier:
https://wiki.selfhtml.org/wiki/JavaScript/DOM/Node/nodeType2, 4, 5, 6 sind deprecated, d. h. veraltet. Wir brauchen nur Elementknoten und Textknoten, also 1 und 3. Ein Knoten ist ein Element im Baum des DOM wo alle Elemente des HTML-Dokumentes entsprechend den Eltern-/Kind-Beziehungen definiert sind. Was im HTML z. B. ein div mit Text darin ist, ist im DOM etwas komplizierter, nämlich das div als Elementknoten und darin ein Textknoten mit dem Text darin. Bei unserer Suche ist das hilfreich, denn wir wollen ja nur Fundstellen im sichtbaren Text und nicht in Kommentaren, Attributen oder einem Skript.
 

Sempervivum

Erfahrenes Mitglied
bei einem nicht gefunden Wort gibt es keine Meldung wie im alten Script (z.B. Norbert), die Suche an sich ist case sensitiv: Einstein geht, aber nicht einstein.
Da ist anscheinend noch ein wenig Arbeit zu tun. Erst mal sehen, dass das Hervorheben und das Springen von einer Fundstelle zur nächsten funktioniert.
 

Sempervivum

Erfahrenes Mitglied
Jetzt nicht mehr case-sensitiv:
Code:
    <script>
        function search(node, needle) {
            const regex = new RegExp('(' + needle + ')', 'i');
            node.childNodes.forEach(node => {
                switch (node.nodeType) {
                    // Handelt es sich um einen Elementknoten?
                    case 1:
                        // Suche fortsetzen
                        search(node, needle);
                        break;
                    // Handelt es sich um einen Textknoten?
                    case 3:
                        // Den Text heraus ziehen
                        const txt = node.textContent.trim();
                        // console.log(txt)
                        if (txt != '') {
                            // Um den gefundenen Text hervor zu heben, betten wir ihn ein
                            // span-Element ein, das wir dann geeignet mit CSS gestalten koennen.
                            // In einem Textknoten wird jedoch kein HTML interpretiert.
                            // Daher erzeugen wir ein neues span-Element und tragen dort den
                            // geaenderten Text ein.
                            let newEle = document.createElement('span');
                            newEle.innerHTML = txt.replace(regex, '<span class="found">$1</span>')
                            node.replaceWith(newEle);
                            break;
                        }
                }
            });
        }
        let searchDone = false,
            foundElems,
            idxSearch = 0;
        // Die folgende Funktion wird durch das Suchformular aufgerufen
        // und startet die Suche
        function suchen(needle) {
            // event.preventDefault();
            // Wurde die Suche noch nicht gestartet?
            if (!searchDone) {
                // Suche starten
                search(document.querySelector('body'), needle);
                // Gefundene Element bereit stellen
                foundElems = document.querySelectorAll('.found');
                // Erstes gefundenes Element hervor heben
                foundElems[idxSearch].classList.add('highlight');
                foundElems[idxSearch].scrollIntoView();
                searchDone = true;
            } else {
                // Hevorhebung des alten gefundenen Elementes löschen
                foundElems[idxSearch].classList.remove('highlight');
                // Naechstes gefundenes Element hervor heben
                idxSearch++;
                foundElems[idxSearch].classList.add('highlight');
                foundElems[idxSearch].scrollIntoView();
            }
            return false;
        }
    </script>
 

Webhufi

Erfahrenes Mitglied
Aha, 'node' ist mir schon mal über den Weg gelaufen. Danke für die Erklärung!

Seltsam: Ich habe deinen neuen Code und auch den Style eingefügt, und es klappte prima in der Vorschau, auch mit Enter zum Weitersuchen. Dann habe ich im Suchfeld die Farbe geändert und alles hochgeladen; jetzt funktioniert die Suche nicht mehr... Was habe ich verbeutelt??? :-( An der Farbänderung liegt es sicher nicht.

P.S.: kein alert, sondern gar nichts! Das war vorher, als das Script noch funktionierte...

Jetzt mach bitte mal Pause, ich schaue morgen Abend wieder vorbei.
 
Status
Dieses Thema wurde gelöst! Zur Lösung gehen…

Neue Beiträge