Eine Suchfunktion läuft nicht mehr

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

Sempervivum

Erfahrenes Mitglied
Hallo Norbert, hier eine neue Version mit folgender Verbesserung: Nach einer Suche kann jetzt eine neue gestartet werden, indem man den Suchbegriff im Eingabefeld ändert und Enter drückt.
Code:
    <script>
        function undoSearch() {
            // Ueber alle Fundstellen:
            document.querySelectorAll('span.found').forEach(item => {
                // Elternelement ermitteln
                const parent = item.parentNode;
                // Textknoten mit Text des Elternelementes erzeugen
                const newTxtNode = document.createTextNode(parent.textContent);
                // ... und Elternelement damit ersetzen
                parent.replaceWith(newTxtNode);
                // Jetzt hat der Knoten wieder der ursprünglichen Zustand
            });
        }
        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 lastSearchStr = '',
            foundElems,
            idxSearch = 0;
        // Die folgende Funktion wird durch das Suchformular aufgerufen
        // und startet die Suche
        function suchen(needle) {
            // event.preventDefault();
            // Unterscheidet sich der Suchstring vom gespeicherten?
            // D. h. handelt es sich um eine neue Suche?
            if (needle != lastSearchStr) {
                lastSearchStr = needle;
                // Aenderungen am DOM von der vorigen Suche rueckgaengig machen
                undoSearch();
                // 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');
                // ... und in den sichtbaren Bereich scrollen
                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');
                // ... und in den sichtbaren Bereich scrollen
                foundElems[idxSearch].scrollIntoView();
            }
            return false;
        }
    </script>

Übrigens: Das Skript setzt zwei Klassen: .found bei allen Fundstellen und .highlight bei der, die man gerade mit Enter angesteuert hat. Kannst Du z. B. mit diesem CSS testen:
Code:
    <style>
        .found {
            background-color: lightsalmon !important;
        }

        .found.highlight {
            background-color: lightblue !important;
        }
    </style>
 

Sempervivum

Erfahrenes Mitglied
... wie ich sehe, funktioniert nur das untere Suchfeld. Bei dem oberen fehlt der Aufruf der Suchen-Funktion beim Submit, diesen müsstest Du ergänzen:
Oberes Suchformular:
<form name="search">
Unteres Suchformular:
<form onsubmit="return suchen(this.suchtexting.value);" name="search">

Dann gibt es allerdings noch ein kleines Problem: Da sind oben zwei Menüs und wenn die zugeklappt sind und darin der Suchbegriff gefunden wird, sieht man die Fundstellen nicht. Wie hat das eigentlich bei der alten Suche funktioniert :grübel: ?
 

Webhufi

Erfahrenes Mitglied
Donnerwetter, da hast du aber was entdeckt! Ich wusste gar nicht mehr, dass unten auch noch ein Suchfeld ist... Das ist völlig unnötig, da man ja mit den Buttons nach oben gelangen kann.
Das obere habe ich rausgeworfen und das untere dorthin eingefügt, mit deiner Ergänzung <form onsubmit="return suchen(this.suchtexting.value);" name="search">.
Trotzdem funktioniert es nicht! Wobei übrigens im oberen Formular durchaus das <form name="search"> drinne war.

Zu deinem *grübel*:

Anno tobak hatte ich diese Funktion auf einer einfacheren Seite mit nur vier Hauptmenüpunkten.

Wenn man aber jetzt nur die relevante Page aufsucht, ist das Hauptmenü ja zugeklappt, sollte also kein Hindernis sein für die Suche; das zweite Menü verschwindet ebenfalls in einem sehr kleinen Fenster, wobei nur noch "Menü" übrig bleibt. Auch das sollte kein Hindernis sein für die Ergebnisse der Suchfunktion.

Was mich aber völlig stutzig macht ist ja, dass es einmal zu meiner riesigen Freude geklappt hatte! Ich hatte am oberen Bildschirmrand die erste hellblaue Fundstelle gesehen, und mit Enter gelangte ich zu nächsten. Nach dem nächsten Update ging überhaupt nichts mehr, auch jetzt nicht.
Ich habe inzwischen alle deine Codes noch einmal nacheinander probiert; erfolglos... Ich finde den gepfefferten Hasen nicht...

Änderung ist online.

Ungeschickterweise läuft der Besucherzähler weiter, aber kein traut sich zu sagen, dass da was nicht stimmt! Vielleicht stolpern auch einige darüber, wenn sie nach der gleichnamigen Zeitung suchen und klicken dann erschrocken wieder zurück... :cool:
 

Sempervivum

Erfahrenes Mitglied
Da fehlte jetzt im form-Tag das onsubmit mit dem Aufruf der Funktion suchen. Wir lassen das jedoch, ich habe statt dessen einen Eventlistener registriert, damit kann das form-Tag bleiben wie ist.

Code:
    <script>
        function undoSearch() {
            // Ueber alle Fundstellen:
            document.querySelectorAll('span.found').forEach(item => {
                // Elternelement ermitteln
                const parent = item.parentNode;
                // Textknoten mit Text des Elternelementes erzeugen
                const newTxtNode = document.createTextNode(parent.textContent);
                // ... und Elternelement damit ersetzen
                parent.replaceWith(newTxtNode);
                // Jetzt hat der Knoten wieder der ursprünglichen Zustand
            });
        }
        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 lastSearchStr = '',
            foundElems,
            idxSearch = 0;
        // Die folgende Funktion wird durch das Suchformular aufgerufen
        // und startet die Suche
        function suchen(needle) {
            // event.preventDefault();
            // Unterscheidet sich der Suchstring vom gespeicherten?
            // D. h. handelt es sich um eine neue Suche?
            if (needle != lastSearchStr) {
                lastSearchStr = needle;
                // Aenderungen am DOM von der vorigen Suche rueckgaengig machen
                undoSearch();
                // 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');
                // ... und in den sichtbaren Bereich scrollen
                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');
                // ... und in den sichtbaren Bereich scrollen
                foundElems[idxSearch].scrollIntoView();
            }
            return false;
        }
        document.querySelector('form[name="search"]').addEventListener('submit', function (event) {
            event.preventDefault();
            suchen(document.querySelector('input[name="suchtexting"]').value);
        });
    </script>
 

Sempervivum

Erfahrenes Mitglied
Das liegt daran, dass das Javascript im Head liegt. Auch kein Problem, wenn wir einen Eventlistener für DOM-ready nehmen:
Code:
    <script>
        function undoSearch() {
            // Ueber alle Fundstellen:
            document.querySelectorAll('span.found').forEach(item => {
                // Elternelement ermitteln
                const parent = item.parentNode;
                // Textknoten mit Text des Elternelementes erzeugen
                const newTxtNode = document.createTextNode(parent.textContent);
                // ... und Elternelement damit ersetzen
                parent.replaceWith(newTxtNode);
                // Jetzt hat der Knoten wieder der ursprünglichen Zustand
            });
        }
        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 lastSearchStr = '',
            foundElems,
            idxSearch = 0;
        // Die folgende Funktion wird durch das Suchformular aufgerufen
        // und startet die Suche
        function suchen(needle) {
            // event.preventDefault();
            // Unterscheidet sich der Suchstring vom gespeicherten?
            // D. h. handelt es sich um eine neue Suche?
            if (needle != lastSearchStr) {
                lastSearchStr = needle;
                // Aenderungen am DOM von der vorigen Suche rueckgaengig machen
                undoSearch();
                // 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');
                // ... und in den sichtbaren Bereich scrollen
                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');
                // ... und in den sichtbaren Bereich scrollen
                foundElems[idxSearch].scrollIntoView();
            }
            return false;
        }
        document.addEventListener('DOMContentLoaded', function () {
            document.querySelector('form[name="search"]').addEventListener('submit', function (event) {
                event.preventDefault();
                suchen(document.querySelector('input[name="suchtexting"]').value);
            });
        });
    </script>
 

Webhufi

Erfahrenes Mitglied
Wie gelassen du das alles nimmst, Ulrich... Jedenfall liest es sich so! :)

Und: Du bist 'ne Wucht! Es funktioniert tadellos! *hüpf

Na ja, fast: Ein nicht gefundenes Suchwort wird nicht als solches kommentiert.

Mir fällt auch auf, dass - wenn ich nach "urknall" suche - der erste Artikel gar nicht durchsucht wird. Liegt das vielleicht daran, dass ich schon einmal danach gesucht hatte, und diese Suche weiter unten auf der Seite fortgeführt wird oder auch gar nicht mehr? Ich finde das etwas verwirrend für den (Be)Sucher. Möglicherweise wäre es sinnvoller, die Historie zu löschen. Oder aber, was sicher aufwändig ist, den Sucher zu fragen: Suche fortsetzen? Suche von neuem Beginnen? Vielleicht in Verbindung mit dem folgenden Absatz:

Ach ja, jetzt werde ich fast unverschämt vor lauter Freude: Wenn die gesamte Seite mit Enter durchsucht wurde, tut sich beim weiteren Enter nichts mehr. Könnte man dann einen Hinweise geben, dass die Suche beendet ist und wieder an den Anfang springen? Vielleicht sogar an den Anfang des zweiten Menüs? Das wäre super.

Eigentlich genügt das blaue Highlight, ich habe das CSS korrigiert.

Noch ein "ach ja": Es ist doch üblich, dass der Autor einer solchen Zauberei genannt wird. Wo darf ich dich unterbringen, mit vielleicht einem Link?

Zum Schluss werde ich noch ein png mit einer Lupe hinter das Suchfeld einfügen. Ich denke, das kommt gut. Ich hoffe, dass ich das schaffe...
 
Status
Dieses Thema wurde gelöst! Zur Lösung gehen…