Christian: Verwendung Zugriffszähler mit Onlineanzeige

0 38

Verwendung Zugriffszähler mit Onlineanzeige

  1. 1
    1. 0
      1. 0
        1. 0
          1. 0
  2. 0
    1. 0
      1. 0
        1. 0
          1. 2
      2. 0
        1. 0
          1. 0
            1. 0
              1. 5
                1. 0
                  1. 0
                    1. 1
                    2. 0
                      1. 0
                        1. 0
                          1. 0
                            1. 0
                              1. 0
                                1. 0
                                  1. 0
                                    1. 0
                                      1. 0
                                  2. 0
                                    1. 0
                                    2. 5
                    3. 7
                      1. 1
                        1. 0
                          1. 0
                            1. 2
                          2. 0

Hallo,

ich konnte erfolgreich den visitcount.php unter https://wiki.selfhtml.org/wiki/PHP/Tutorials/Zugriffszähler_mit_Onlineanzeige zum Laufen bringen. Ich bin mir aber nicht sicher, ob hier alle Besucher auch als online angezeigt werden, d.h. inklusive aller Unterseiten einer Domain.

Ich habe dies daran feststellen können, dass auf der Hauptseite www.exmaple.de nur ein Besucher als online angezeigt wurde, aber auf der Unterseite www.example.de/forum via dem integrierten phpbb Zähler des Forums 10 Besucher als Online angezeigt wurden.

Muß hier im php-Script bzw. anderen Dateien ggf. noch etwas modifiziert werden, um die komplette Domain mit alle Subpages für den Onlinezähler abzudecken?

Vielen Dank für die Rückinfos.

Christian

  1. Hello,

    jede Seite, deren Requests gezählt werden sollen, benötigen mindestens das Zählpixel und ein <img>-Element, in dem visitcpunt dann z. B. mit der Option ?noshow aufgerufen wird.

    Der Zähler vom CMS ist vermutlich nicht floadingsafe. Probier es mal aus, ob er jeden Request zählt, oder nur einen pro Besucher (IP) innerhalb eines Zeitabschnittes.

    Glück Auf
    Tom vom Berg

    --
    Es gibt nichts Gutes, außer man tut es!
    Das Leben selbst ist der Sinn.
    1. Hello,

      jede Seite, deren Requests gezählt werden sollen, benötigen mindestens das Zählpixel und ein <img>-Element, in dem visitcpunt dann z. B. mit der Option ?noshow aufgerufen wird.

      Der Zähler vom CMS ist vermutlich nicht floadingsafe. Probier es mal aus, ob er jeden Request zählt, oder nur einen pro Besucher (IP) innerhalb eines Zeitabschnittes.

      Glück Auf
      Tom vom Berg

      Hallo Tom,

      vielen Dank für die Rückinfo. Ich verwende kein CMS und habe visitcount.php auf der gleichen Ebene wie die index.html integriert. Deshalb wäre hier meine Frage wie man dies bewerkstelligen müsste, da die Website aus vielen Unterseiten: www.expample.de/subpage1, www.example.de/subpage2, www.example.de/forum, etc. besteht. Wie würde dies dann mit <img> und ?noshow konkret aussehen?

      Schon vorab vielen Dank.

      Grüße

      Christian

      1. Hello,

        Hello,

        jede Seite, deren Requests gezählt werden sollen, benötigen mindestens das Zählpixel und ein <img>-Element, in dem visitcpunt dann z. B. mit der Option ?noshow aufgerufen wird.

        Der Zähler vom CMS ist vermutlich nicht floadingsafe. Probier es mal aus, ob er jeden Request zählt, oder nur einen pro Besucher (IP) innerhalb eines Zeitabschnittes.

        Glück Auf
        Tom vom Berg

        Hallo Tom,

        vielen Dank für die Rückinfo. Ich verwende kein CMS und habe visitcount.php auf der gleichen Ebene wie die index.html integriert. Deshalb wäre hier meine Frage wie man dies bewerkstelligen müsste, da die Website aus vielen Unterseiten: www.expample.de/subpage1, www.example.de/subpage2, www.example.de/forum, etc. besteht. Wie würde dies dann mit <img> und ?noshow konkret aussehen?

        Dazu musst Du dir nur den Quelltext der beiden Beispiele ganz unten im Artikel ansehen.

        Jede Seite, die gezählt werden soll, muss ein <img src="/visitcount/visitcount.php" alt="counter"> enthalten. Damit der Zähler nicht angezeigt wird, schreibst Du stattdessen <img src="/visitcount/visitcount.php?noshow" alt="countpixel">.

        Glück Auf
        Tom vom Berg

        --
        Es gibt nichts Gutes, außer man tut es!
        Das Leben selbst ist der Sinn.
        1. Hallo Tom,

          verstanden. Hierzu dann noch zwei Fragen:

          a) Muss ich ebenfalls auf allen Seiten das Script: <script src="http://www.example.de/visitcount/visitcount_trigger.js"></script> einbauen?

          b) Werden nach Einbau von <img src="/visitcount/visitcount.php?noshow" alt="countpixel"> auf den einzelnen Unterseiten dann auch alle Online-Besucher der Website kummuliert dargestellt, was ja eigentlich der Fall sein sollte, oder?

          Ein erster Test mit nur <img src="/visitcount/visitcount.php?noshow" alt="countpixel"> hat leider nicht funktioniert und es wurde immer noch nur ein Besucher angezeigt, obwohl mehrere Online waren.

          Viele Grüße

          Christian

          1. Hello,

            verstanden. Hierzu dann noch zwei Fragen:

            a) Muss ich ebenfalls auf allen Seiten das Script: <script src="http://www.example.de/visitcount/visitcount_trigger.js"></script> einbauen?

            Auf allen Seiten auf denen dann im <body>-Tag die Funktion für die Aufenthaltsfeststellung eingebaut werden soll.

            b) Werden nach Einbau von <img src="/visitcount/visitcount.php?noshow" alt="countpixel"> auf den einzelnen Unterseiten dann auch alle Online-Besucher der Website kummuliert dargestellt, was ja eigentlich der Fall sein sollte, oder?

            Ja, die Scripte auf den einzelnen Seiten benutzen alle dieselbe Datendatei, wenn Du die Pfade zu den Daten nicht veränderst.

            Ein erster Test mit nur <img src="/visitcount/visitcount.php?noshow" alt="countpixel"> hat leider nicht funktioniert und es wurde immer noch nur ein Besucher angezeigt, obwohl mehrere Online waren.

            Bedenke, dass Besucher mit gleicher IP nur einmal gezählt werden, auch wenn sie sich mehrere Seiten des Auftrittes nacheinander anschauen.

            Du kannst also auf diese Weise nicht feststellen, welche Unterseite wie oft aufgerufen wurde. Dazu müsstest Du den Zähler umbauen.

            Testen:

            Du kannst uns ja nachher mal einen Link zu deiner Testseite schicken, dann klicken wir alle mal unx Du siehst, ob es funktioniert ;-)

            Glück Auf
            Tom vom Berg

            --
            Es gibt nichts Gutes, außer man tut es!
            Das Leben selbst ist der Sinn.
  2. Moin,

    ich konnte erfolgreich den visitcount.php unter https://wiki.selfhtml.org/wiki/PHP/Tutorials/Zugriffszähler_mit_Onlineanzeige zum Laufen bringen.

    das ist schön - aber was versprichst du dir davon? Hältst du das für sinnvoll oder nützlich? - Ich nicht, und im Beitrag steht ja auch schon etwas zur Sinnhaftigkeit solcher Counter.

    Ich bin mir aber nicht sicher, ob hier alle Besucher auch als online angezeigt werden, d.h. inklusive aller Unterseiten einer Domain.

    In der Beschreibung heißt es eindeutig: "Für eine Webseite soll eine Zählung ..."
    (Hervorhebung von mir)
    Also musst du den Zähler auch auf allen Seiten einbauen, auf denen du Besucher zählen willst.

    So long,
     Martin

    --
    Ach, macht ihr da Ohm doch Watt ihr Volt.
    1. Aloha ;)

      In der Beschreibung heißt es eindeutig: "Für eine Webseite soll eine Zählung ..."
      (Hervorhebung von mir)

      Ja... da steht halt freilich noch die Uneindeutigkeit des Wortes "Webseite" im Raum. Das ist hier vermutlich auch Kern des Verständnisproblems.

      Grüße,

      RIDER

      --
      Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
      # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
      1. Hallo Janosch,

        In der Beschreibung heißt es eindeutig: "Für eine Webseite soll eine Zählung ..."
        (Hervorhebung von mir)

        Ja... da steht halt freilich noch die Uneindeutigkeit des Wortes "Webseite" im Raum.

        findest du das wirklich mehrdeutig? Eine Webseite ist eine einzelne Seite eines Webauftritts oder einer Webpräsenz. Analog im Englischen: Web page vs. web site.
        Die phonetische Ähnlichkeit zwischen Seite und Site ist allerdings tückisch, das gebe ich zu. Einer der vielen False Friends zwischen Deutsch und Englisch. So wie ich heute wieder einen Kollegen diskret darauf hingewiesen habe, dass er einen falschen Ausdruck gewählt hatte, dass actual eben nicht aktuell heißt.

        Das ist hier vermutlich auch Kern des Verständnisproblems.

        Möglich. Das ist aber ein Unterschied, den man sehr bald verstehen sollte, weil man sonst immer wieder wegen der Begrifflichkeiten aneckt.

        Schönen Abend noch,
         Martin

        --
        Ach, macht ihr da Ohm doch Watt ihr Volt.
        1. Aloha ;)

          Die phonetische Ähnlichkeit zwischen Seite und Site ist allerdings tückisch, das gebe ich zu. Einer der vielen False Friends zwischen Deutsch und Englisch.

          Genau da liegt der Hase im Pfeffer. Eigentlich wäre das deutsche Webseite (web page) schon eindeutig, aber die phonetische Ähnlichkeit mit web site und die allgegenwärtige Verenglischung tragen dazu bei, dass Webseite und Website immer mehr vermischt werden - und auch teils mit genau der gegenteiligen Intention verwendet werden.

          Daher würd ich sogar weitergehen. Website ist nicht nur ein False Friend, sondern sogar bereits in den deutschen Sprachgebrauch als Fremdwort übergegangen und daher doppelt gefährlich, da vielerorts nicht mehr zwischen Webseite und Website unterschieden wird - wer keine Ahnung von der Materie hat, dem ist der Unterschied bei zwei so ähnlich klingenden, bedeutungsähnlichen Worten auch schwer zu vermitteln.

          Noch schlimmer: "Meine Seite" wird inzwischen auch mal gerne für ein persönliches Webprojekt verwendet. Die Vermischung im normalen Sprachgebrauch (= abseits der Fachsprache) ist also bereits weit fortgeschritten.

          Das ist hier vermutlich auch Kern des Verständnisproblems.

          Möglich. Das ist aber ein Unterschied, den man sehr bald verstehen sollte, weil man sonst immer wieder wegen der Begrifflichkeiten aneckt.

          Richtig. Wie auch der Umstand, dass ein Zählpixel natürlich nur dann angefasst werden kann, wenn es auf der konkret aufgerufenen Seite eingebunden ist. Das war allerdings hier auch nicht gegeben.

          Vielleicht wäre es daher sinnvoll, das Wort Webseite zu vermeiden, weil es nur mit Fachsprach-Kenntnissen eindeutig zu deuten ist. Vielleicht wäre ein "Webdokument" oder ein "HTML-Dokument im Web" eindeutiger und daher für Anfänger freundlicher?

          Grüße,

          RIDER

          --
          Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
          # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
          1. Hej Camping_RIDER,

            Die phonetische Ähnlichkeit zwischen Seite und Site ist allerdings tückisch, das gebe ich zu. Einer der vielen False Friends zwischen Deutsch und Englisch.

            Genau da liegt der Hase im Pfeffer. Eigentlich wäre das deutsche Webseite (web page) schon eindeutig, aber die phonetische Ähnlichkeit mit web site und die allgegenwärtige Verenglischung tragen dazu bei, dass Webseite und Website immer mehr vermischt werden […]

            Gab es mal eine Zeit, wo einer gesagt hat "ich habe eine Webseite" und meinte damit, dass er ein einzelnes HTML-Dokument besitzt?

            Meinem Gefühl nach war Webseite schon immer umgangssprachlich für Webauftritt inklusive aller Unterseiten.

            Ist eine einzelne Seite gemeint, wird in der Regel deren Name genannt. Die Startseite oder das Kontaktformular (womit nicht das form-Element gemeint ist, sondern die Seite, die das enthält).

            So reden auch die Entwickler miteinander, die ich kenne.

            Als Dozent achte ich natürlich darauf und erkläre das auch zu Anfang explizit.

            Aber ein Dozent ist halt auch ein komischer Kauz. 🦉

            Homepage bedeutet für die meisten Deutschen dasselbe wie Webseite oder Website und ist etwas anderes als das englische „home page“, was nämlich Startseite bedeutet.

            Ich spreche auch am liebsten von HTML-Dokumenten in den Kursen, wo es um statisches HTML geht.

            Ansonsten übernehme ich die offiziellen Begrifflichkeiten, die das System, wie z.B. Wordpress vorgibt (Seiten, Beiträge und ggfs. weitere durch PlugIns erzeugte Möglichkeiten).

            Marc

            --
            Ceterum censeo Google esse delendam
      2. Hello,

        Aloha ;)

        In der Beschreibung heißt es eindeutig: "Für eine Webseite soll eine Zählung ..."
        (Hervorhebung von mir)

        Ja... da steht halt freilich noch die Uneindeutigkeit des Wortes "Webseite" im Raum. Das ist hier vermutlich auch Kern des Verständnisproblems.

        Es wird doch deutlich gezeigt, wie die drei Elemente JS-Script, JS-Funktionsaufruf und <img>-Element (PHP-Programm) im HTML eines Dokumentes eingebunden werden müssen. Dass das dann in jedem Dokument, dessen Aufrufe gezählt werden sollen. notwendig ist, sollte man schon von alleine folgern können.

        Und schließlich steht das Forum noch zur Fragebeantwortung zur Verfügung ;-)

        Glück Auf
        Tom vom Berg

        --
        Es gibt nichts Gutes, außer man tut es!
        Das Leben selbst ist der Sinn.
        1. Aloha ;)

          Es wird doch deutlich gezeigt, wie die drei Elemente JS-Script, JS-Funktionsaufruf und <img>-Element (PHP-Programm) im HTML eines Dokumentes eingebunden werden müssen. Dass das dann in jedem Dokument, dessen Aufrufe gezählt werden sollen. notwendig ist, sollte man schon von alleine folgern können.

          Du setzt da aber voraus, dass da bereits ein Verständnis dafür da ist, wie die Mechanismen intern ticken. Wer keine Ahnung von der Materie hat könnte auf die Idee kommen, es genüge, das Ding im Webroot zu hinterlegen und irgendwo einzubinden, weil wenn man eine Unterseite aufruft ist das ja immernoch im selben Webauftritt.

          Mir und dir ist völlig klar, dass das so nicht funktioniert. Ein Anfänger hat ggf. keine Vorstellung davon, was der Webserver bei einem Seitenaufruf alles so anfasst, und was eben nicht.

          Und da kommt das Eindeutigkeitsproblem ins Spiel: Mit "Webseite" meint man gelegentlich ein einzelnes aufzurufendes Webdokument, manchmal meint man damit aber auch das gesamte Projekt, also den gesamten Webauftritt. Wer da jetzt für "Webseite" nicht "Webdokument" sondern "Webauftritt" versteht, tappt in die Falle und wird ggf. noch in seinen Fehlvorstellungen bestätigt.

          Grüße,

          RIDER

          --
          Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
          # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
          1. Hallo,

            jetzt hätte ich aber noch einmal eine Frage zur Einbindung wenn ich die Diskussion richtig verfolgt habe.

            Man muss auf allen einzelnen Seiten:

            a) den Script <script src="/visitcount/visitcount_trigger.js"></script>

            b) <body onLoad="counter_refresh('/visitcount/visitcount.php');"> --> oder ist dies nicht notwendig?

            c) <div id="counter"><img id="img_counter" src="/visitcount/visitcount.php" alt="counter"></div>

            einbinden, richtig?

            Was ist hier dann der JS-Funktionsaufruf?

            Desweiteren wäre meine Frage was man machen muss wenn alle Webseiten/Webdokumente den gleichen Footer über ein php include haben.

            Schon vorab vielen Dank für die Rückinfo.

            Christian

            1. Aloha ;)

              jetzt hätte ich aber noch einmal eine Frage zur Einbindung wenn ich die Diskussion richtig verfolgt habe.

              Man muss auf allen einzelnen Seiten:

              a) den Script <script src="/visitcount/visitcount_trigger.js"></script>

              b) <body onLoad="counter_refresh('/visitcount/visitcount.php');"> --> oder ist dies nicht notwendig?

              c) <div id="counter"><img id="img_counter" src="/visitcount/visitcount.php" alt="counter"></div>

              einbinden, richtig?

              Ja, richtig.

              Was ist hier dann der JS-Funktionsaufruf?

              In dem Fall: b) - denn hier wird die JS-Funktion aufgerufen, mit dem PHP-Skript als Parameter.

              @TS: Warum eigentlich body onload noch ins HTML und nicht direkt ein body.addEventListener(load, ...)?

              Desweiteren wäre meine Frage was man machen muss wenn alle Webseiten/Webdokumente den gleichen Footer über ein php include haben.

              Nichts anderes. Wenn du den Counter im Footer anzeigen willst, dann packst du das img mit dem Counter einfach da rein.

              Schon vorab vielen Dank für die Rückinfo.

              Kein Ding.

              Grüße,

              RIDER

              --
              Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
              # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
              1. Hallo Camping_RIDER

                Warum eigentlich body onload noch ins HTML und nicht direkt ein body.addEventListener('load', ...)?

                Diese Variante würde nicht funktionieren, denn das body-Element hat kein load-Event.

                Aus historischen Gründen führt eine Handler-Registrierung über das Attribut onload auf dem body-Element tatsächlich dazu, dass der Handler auf window registriert wird, wo es ein entsprechendes Event gibt. Bei Verwendung der moderneren Methode addEventListener passiert das hingegen nicht.

                const handler = _ => {}
                
                document.body.onload = handler
                
                console.log(document.body.onload === window.onload) // true
                

                Die Eigenschaft body.onload reflektiert window.onload und umgekehrt. Das heißt, eine Zuweisung an eine der Eigenschaften überschreibt immer auch den Wert der jeweils anderen Eigenschaft. Und eine spätere Zuweisung an eine der beiden Eigenschaften überschreibt eine vorangegangene Registrierung über das onload-Attribut im Markup.

                    <body onload="console.log(1)">
                        <script>
                
                            window.onload = _ => console.log(2)
                
                        </script>
                    </body>
                </html>
                

                Hier wird nur 2 in die Konsole geschrieben, da in beiden Fällen ein Handler für die Eigenschaft window.onload registriert wird, und das Skript die Registrierung des anonymen Handlers im Markup überschreibt.

                Soll aus einem Skript heraus das globale load-Event überwacht werden (und nicht das meist besser geeignete Event DOMContentLoaded), dann muss die Registrierung auf dem window-Objekt erfolgen, wenn dafür die zu Recht empfohlene Methode addEventListener verwendet werden soll.

                window.addEventListener('load', event => /* ... */)
                
                // oder
                
                addEventListener('load', event => /* ... */)
                

                Die explizite Referenz auf window kann weggelassen werden, da addEventListener als Eigenschaft des globalen Objekts auch direkt angesprochen werden kann. Die Bindung an window als Kontextobjekt erfolgt hier automatisch.

                Viele Grüße,

                Orlok

                1. Aloha ;)

                  Warum eigentlich body onload noch ins HTML und nicht direkt ein body.addEventListener('load', ...)?

                  Diese Variante würde nicht funktionieren, denn das body-Element hat kein load-Event.

                  Danke für die Aufklärung! Und…

                  Aus historischen Gründen führt eine Handler-Registrierung über das Attribut onload auf dem body-Element tatsächlich dazu, dass der Handler auf window registriert wird, wo es ein entsprechendes Event gibt. Bei Verwendung der moderneren Methode addEventListener passiert das hingegen nicht.

                  …das war mir tatsächlich neu, erklärt aber Effekte, die ich mir bisher nicht erklären konnte.

                  Allerdings bleibt die Frage: warum den JS-Aufruf ins HTML einbinden und nicht direkt in der eh bereits vorhandenen JS-Datei feuern?

                  Grüße,

                  RIDER

                  --
                  Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                  # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
                  1. Hello,

                    es wäre doch mMn eine gute Tat, wenn Du dem Artikel einen eigenen Abschnitt mit den gewonnenen Erkenntnissen und der alternativen Methode hinzufügen würdest.

                    Die Intention bei der Nutzung von <body onLoad="..."> war, hier in kleinsten und leicht nachvollziehbaren Schritten das mögliche Zusammenspiel von HTML und JavaScript zu demonstrieren. Deine Vorgehensweise benötigt hingegen schon wieder eine oder sogaf mehrere Wissensebenen zusätzlich.

                    Glück Auf
                    Tom vom Berg

                    --
                    Es gibt nichts Gutes, außer man tut es!
                    Das Leben selbst ist der Sinn.
                    1. Aloha ;)

                      es wäre doch mMn eine gute Tat, wenn Du dem Artikel einen eigenen Abschnitt mit den gewonnenen Erkenntnissen und der alternativen Methode hinzufügen würdest.

                      Klar, gerne, sobald wir ausreichend darüber gesprochen haben.

                      Die Intention bei der Nutzung von <body onLoad="..."> war, hier in kleinsten und leicht nachvollziehbaren Schritten das mögliche Zusammenspiel von HTML und JavaScript zu demonstrieren. Deine Vorgehensweise benötigt hingegen schon wieder eine oder sogaf mehrere Wissensebenen zusätzlich.

                      Warum eine oder mehrere Wissensebenen zusätzlich? JavaScript und das DOM sollten ja ggf. schon verstanden sein, und wir empfehlen bereits an anderer Stelle die Verwendung von addEventListener statt der HTML-Attribute, da wir ja unobtrusives JavaScript für empfehlenswert halten und dementsprechend auch propagieren wollen.

                      Deshalb stellt sich für mich die Frage, ob die Darstellung als alternativer Weg sinnvoll ist, oder ob nicht besser gleich diese Vorgehensweise vorgeschlagen werden sollte.

                      Die Einbindung wäre dadurch einfacher (in nur zwei statt drei Schritten) und wir würden unseren eigenen Empfehlungen konsistenter folgen.

                      Grüße,

                      RIDER

                      --
                      Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                      # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
                    2. Hallo,

                      Die Intention bei der Nutzung von <body onLoad="..."> war, hier in kleinsten und leicht nachvollziehbaren Schritten das mögliche Zusammenspiel von HTML und JavaScript zu demonstrieren. Deine Vorgehensweise benötigt hingegen schon wieder eine oder sogaf mehrere Wissensebenen zusätzlich.

                      wenn man für den Zähler einen Block aus HTML-Element, Scripteinbindung und evtl. Scriptbereich zur Parametrisierung und zum Starten erstellt, kann man diesen überall, auch z.B. im zentralen Footer einbinden und benötigt keine Events mehr.

                      Gruß
                      Jürgen

                      1. Hello,

                        Hallo,

                        Die Intention bei der Nutzung von <body onLoad="..."> war, hier in kleinsten und leicht nachvollziehbaren Schritten das mögliche Zusammenspiel von HTML und JavaScript zu demonstrieren. Deine Vorgehensweise benötigt hingegen schon wieder eine oder sogaf mehrere Wissensebenen zusätzlich.

                        wenn man für den Zähler einen Block aus HTML-Element, Scripteinbindung und evtl. Scriptbereich zur Parametrisierung und zum Starten erstellt, kann man diesen überall, auch z.B. im zentralen Footer einbinden und benötigt keine Events mehr.

                        Für den Zähler benötigt man nur den Scriptaufruf, hier per <img>-Element.
                        Für die "Online"-Anzeige benötigt man die Events.

                        Ich schlage deshalb ja vor, dass Ihr die Alternativen erst mal fertig schreibt, zusammen mit den notwendigen Vergleichen und Erläuterungen, und wir das dann in den Artikel als Abschnitt aufnehmen.

                        Glück Auf
                        Tom vom Berg

                        --
                        Es gibt nichts Gutes, außer man tut es!
                        Das Leben selbst ist der Sinn.
                        1. Hallo Tom,

                          Für die "Online"-Anzeige benötigt man die Events.

                          warum?

                          Gruß
                          Jürgen

                          1. Hello,

                            Hallo Tom,

                            Für die "Online"-Anzeige benötigt man die Events.

                            warum?

                            Du möchtest auf das DOM-Event verzichten, indem Du den JS-Funktionsaufruf nach allem HTML ins Dokument schreibst?

                            Dass das meistens funktioniert, ist kein garantiertes Browserverhalten.

                            Glück Auf
                            Tom vom Berg

                            --
                            Es gibt nichts Gutes, außer man tut es!
                            Das Leben selbst ist der Sinn.
                            1. Hallo Tom,

                              Du möchtest auf das DOM-Event verzichten, indem Du den JS-Funktionsaufruf nach allem HTML ins Dokument schreibst?

                              ich stelle mir das so vor:

                              <body>
                              
                              ...
                                  <div id="counter">
                                      <img id="img_counter" src="/visitcount/visitcount.php" alt="counter">
                                  </div>
                                  <script src="/visitcount/visitcount_trigger.js"></script>  
                                  <script>
                                      counter_refresh('/visitcount/visitcount.php');
                                  </script>
                              ...
                              
                              </body>
                              

                              Wobei der Aufruf von counter_refresh auch in visitcount_trigger.js erfolgen kann, und dort kann das Script auch noch den Pfad selbst ermitteln.

                              Gruß
                              Jürgen

                              1. Aloha ;)

                                ich stelle mir das so vor:

                                Wobei der Vorschlag ja jetzt noch weniger unobtrusive ist, oder nicht?

                                Grüße,

                                RIDER

                                --
                                Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                                # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
                                1. Hallo

                                  Wobei der Vorschlag ja jetzt noch weniger unobtrusive ist, oder nicht?

                                  warum? Nur weil html und Javscript jetzt zusammenstehen und so als Block eingebaut werden können?

                                  Ich lasse gerne zusammen, was zusammen gehört. Und wenn das Script hinter dem html eingebunden wird, kann auf den Loadevent-Handler verzichtet werden.

                                  Gruß
                                  Jürgen

                                  1. Hallo Jürgen,

                                    Hallo

                                    Wobei der Vorschlag ja jetzt noch weniger unobtrusive ist, oder nicht?

                                    warum? Nur weil html und Javscript jetzt zusammenstehen und so als Block eingebaut werden können?

                                    Ich lasse gerne zusammen, was zusammen gehört. Und wenn das Script hinter dem html eingebunden wird, kann auf den Loadevent-Handler verzichtet werden.

                                    Gruß
                                    Jürgen

                                    heißt das dann wenn man:

                                    <div id="counter"> <img id="img_counter" src="/visitcount/visitcount.php?nowshow" alt="counter"> </div> <script src="/visitcount/visitcount_trigger.js"></script>
                                    <script>counter_refresh('/visitcount/visitcount.php'); </script>

                                    in den Footer einbindet, dass dann alle Besucher auf den einzelnen HTML Seiten der Website kummuliert gezählt werden (da ja der Footer bei allen Seiten durch das php include der Gleiche ist)?

                                    Das wäre toll und simpel.

                                    Viele Grüße

                                    Christian

                                    1. Hallo,

                                      ich würde sagen, das geht so, probier es einfach mal aus. Aber genaueres weiß der Autor @TS

                                      Gruß
                                      Jürgen

                                      1. Hallo Jürgen,

                                        Hallo,

                                        ich würde sagen, das geht so, probier es einfach mal aus. Aber genaueres weiß der Autor @TS

                                        Gruß
                                        Jürgen

                                        Die Einbindung von:

                                        <div id="counter">
                                        <img id="img_counter" src="http://www.example.de/visitcount/visitcount.php?noshow" alt="countpixel">
                                        </div>
                                        <script src="http://www.example.de/visitcount/
                                        visitcount_trigger.js"></script>
                                        <script>
                                                counter_refresh(http://www.example.de/
                                        visitcount/visitcount.php');
                                            </script>
                                        

                                        im Footer zu Lösung der Thematik funktioniert leider nicht 😟

                                        Es wird auf der index.html immer nur ein Besucher als online angezeigt, obwohl mehrere Besucher auf der Website sind.

                                        Viele Grüße

                                        Christian

                                  2. Aloha ;)

                                    Wobei der Vorschlag ja jetzt noch weniger unobtrusive ist, oder nicht?

                                    warum? Nur weil html und Javscript jetzt zusammenstehen und so als Block eingebaut werden können?

                                    Kommt auf den Maßstab an, aber ja, wenn unobtrusive der Maßstab ist, dann ist das nicht optimal gelöst. Ob du jetzt dem onload-Attribut einen Funktionsaufruf verpasst oder hinten an den body ein <script> dranhängst bleibt sich im Endeffekt gleich - beides ist kein gutes Beispiel für unobtrusive JavaScript.

                                    Ja, ich stimme dir zu - wenn schon obtrusive, dann besser en block als in Einzelteilen.

                                    Vermutlich wäre richtig gewesen, nicht zu sagen, dass der Vorschlag noch weniger unobtrusive ist, sondern, dass der Vorschlag auch nicht näher an unobtrusive JavaScript rankommt.

                                    Grüße,

                                    RIDER

                                    --
                                    Camping_RIDER a.k.a. Riders Flame a.k.a. Janosch Zoller
                                    # Twitter # Steam # YouTube # Self-Wiki # Selfcode: sh:) fo:) ch:| rl:) br:^ n4:? ie:% mo:| va:) js:) de:> zu:} fl:( ss:) ls:[
                                    1. Hallo Janosch,

                                      ich mache „unobtrusive“ nicht daran fest, ob das Script im Head oder im Body steht. Für mich ist bei abgeschlossen Aufgaben wichtiger, das zusammenbleibt, was zusammen gehört.

                                      Wenn alle Scripte im Head eingebunden werden, hat man natürlich sofort einen Überblick über die Scripte, wenn man allerdings wissen will, was alles zum Seitenzähler gehört, ist die Blocklösung mMn besser, auch weil man sie als Block einfügen kann.

                                      Gruß
                                      Jürgen

                                    2. Hallo Camping_RIDER

                                      Ob du jetzt dem onload-Attribut einen Funktionsaufruf verpasst oder hinten an den body ein <script> dranhängst bleibt sich im Endeffekt gleich - beides ist kein gutes Beispiel für unobtrusive JavaScript.

                                      Im Ergebnis richtig, aber die Verwendung von onload ist im Vergleich viel problematischer.

                                      Der wesentliche Grund, der gegen die Registrierung von Eventhandlern durch Zuweisung spricht, ist die hohe Fehleranfälligkeit. Programme, die diese Technik nutzen, sind nicht robust, da immer das Risiko besteht, dass die Eigenschaft an einer anderen Stelle überschrieben wird. Das gilt natürlich besonders für das Ereignis load, das von vielen Skripten als Einstiegspunkt in das Programm verwendet wird.

                                          <body onload="doSomething()"><script src="path/to/doSomethingElse.js"></script>
                                          </body>
                                      </html>
                                      

                                      Wird zu einem späteren Zeitpunkt ein weiteres Skript hinzugefügt, das ebenfalls einen Handler durch Zuweisung an die Eigenschaft window.onload registriert, dann wird eins der beiden Programme nicht ausgeführt. Welches das ist, hängt davon ab, in welcher Reihenfolge die Handler registriert werden. Für jemanden, der sich dieser Problematik nicht bewusst ist, ist die Fehlerursache nicht unmittelbar ersichtlich, insbesondere, wenn der Fehler erst zu einem späteren Zeitpunkt bemerkt wird.

                                      Wenn man Eventhandler durch Eigenschaftszuweisung registriert, muss man immer genau im Blick haben, welches Skript für welches Objekt welches Event überwacht, und die konkurrierenden Zugriffe koordinieren. Das erfordert zusätzliche Logik und kann dazu führen, dass Skripte, die inhaltlich nichts miteinander zu tun haben, in Abhängigkeiten geraten. Was für manchen vielleicht zunächst wie die einfachere Lösung aussieht, ist außer in den allereinfachsten Fällen mit deutlich mehr Komplexität verbunden.

                                              <script>
                                      
                                                  ⋮
                                      
                                                  window.addEventListener('load', doSomething);
                                      
                                              </script>
                                              <script>
                                      
                                                  ⋮
                                      
                                                  window.addEventListener('load', doSomethingElse);
                                      
                                              </script>
                                          </body>
                                      </html>
                                      

                                      Die Methoden addEventListener und removeEventListener wurden eingeführt, damit sich nicht jeder seine eigene Lösung für diese Probleme stricken muss. Damit können beliebig viele Handler für dasselbe Objekt und dasselbe Ereignis registriert und wieder gelöscht werden, ohne dass es dabei zu Kollisionen kommt.

                                      Meiner Meinung nach sollte in Lehrbeispielen zur Behandlung von Ereignissen ausschließlich diese Methoden verwendet werden – und auch im vorliegenden Fall sehe ich keinen Grund, der dagegen sprechen würde. Es mag zwar Fälle geben, in denen eine Registrierung über Attribute oder Eigenschaften unproblematisch und vielleicht sogar sinnvoll ist, aber solche Situationen zu erkennen erfordert dann doch etwas mehr Einsicht, als von der Zielgruppe eines Tutorials erwartet werden kann.

                                      Viele Grüße,

                                      Orlok

                    3. Hallo TS

                      Es wäre doch mMn eine gute Tat, wenn Du dem Artikel einen eigenen Abschnitt mit den gewonnenen Erkenntnissen und der alternativen Methode hinzufügen würdest.

                      Das wäre sicher eine gute Tat. Eine noch bessere wäre es allerdings, wenn das in dem Artikel vorgestellte Programm eine Ausgabe produzieren würde, die für alle Seitenbesucher zugänglich ist und nicht nur für diejenigen, die sehen können.

                      Die ermittelte Anzahl der Seitenbesucher wird serverseitig als Bild gerendert und so zum Client geschickt. Das ist gleich in doppelter Hinsicht problematisch:

                      1. Es gibt keine textuelle Alternative. Benutzern mit fehlender oder stark eingeschränkter Sehfähigkeit, die sich die Seite vorlesen lassen, bleibt die Information verborgen.

                      2. Der Text wird als Rastergrafik ausgeliefert. Benutzer mit eingeschränkter Sehfähigkeit, die eine größere Schrift benötigen, können den Text unter Umständen nicht entziffern.

                      Ein besseres Beispiel wäre es, wenn sich der Server nur um die Bereitstellung der Daten kümmern würde und der Client die Präsentation übernimmt, in einer Weise, dass die Informationen für alle Besucher der Seite zugänglich sind. Die übermittelten Werte sollten ordentlich ausgezeichnet werden, etwa so wie im folgenden Beispiel.

                      <aside id="counter">
                      
                          <!-- Überschrift oder aria-label mit Accessible Name -->
                      
                          <label for="online">Online:</label>
                          <output id="online"></output>
                      
                          <label for="visits">Visits:</label>
                          <output id="visits"></output>
                      
                      </aside>
                      

                      Bis zur erfolgreichen Ausführung des Skripts sollten die Elemente verborgen werden. Dazu wird das Attribut hidden auf dem Containerelement gesetzt. Erst wenn das Skript ausgeführt und der erste Satz Daten eingetroffen ist, wird das Attribut entfernt. Wenn neue Daten eintreffen, wird nur der textuelle Inhalt der für die Ausgabe vorgesehenen Elemente aktualisiert.

                      Alternativ könnte das Markup auch mit dem Skript ausgeliefert und nachträglich in das Dokument eingefügt werden. Das wäre in diesem Fall vermutlich sogar die bessere Variante, da die Komponente nur gerendert werden soll, wenn das Skript tatsächlich ausgeführt wird.

                      const createCounter = (online, visits) => {
                          document.body.insertAdjacentHTML(
                              'beforeend',
                              `
                                  <aside id="counter">
                                      <h2>User Counter</h2>
                                      <label for="online">Online:</label>
                                      <output id="online">${
                                          online
                                      }</output>
                                      <label for="visits">Visits:</label>
                                      <output id="visits">${
                                          visits
                                      }</output>
                                  </aside>
                              `
                          );
                      };
                      

                      Das Einfügen ins Dokument könnte wie in dem Beispiel oben erfolgen. Ich verwende hier einen Templatestring, um die initialen Werte einzufügen und um mir das Escapen der Zeilenumbrüche zu ersparen. Die Elemente werden am Ende von body eingefügt. Um den Zähler an einer beliebigen Stelle ins Dokument einfügen zu können, könnte man das Elternelement natürlich auch als Argument übergeben.

                      Darüber hinaus sollte die Kommunikation mit dem Server über das Fetch API laufen, statt dafür ein img zu missbrauchen, wobei es sich aus pädagogischer Sicht anbieten würde, die Daten für die Besucherzahlen im JSON-Format zu übertragen. Das Response-Objekt besitzt eine entsprechende Methode, mit der die Daten einfach konvertiert werden können.

                      const getData = async url => {
                          const response = await fetch(url);
                          const {online, visits} = await response.json();
                      
                          outputForOnline.value = online;
                          outputForVisits.value = visits;
                      };
                      

                      Angenommen, die Variablen outputForOnline und outputForVisits enthalten Referenzen auf die output-Elemente und die Daten werden als Objekt mit entsprechenden Schlüsseln übertragen, dann könnte die Funktion zur Beschaffung der Daten so ähnlich wie in dem Beispiel oben aussehen.

                      Ich verwende dabei aus Gründen der besseren Lesbarkeit die async/await-Syntax, bei der es sich im Prinzip nur um syntaktischen Zucker handelt. Ich denke, der Code ist auch dann nachvollziehbar, wenn man nicht das letzte Detail verstanden hat.

                      Das sind alles nur Vorschläge und nicht zwingend der Weisheit letzter Schluss. Ich halte es aber für wichtig, dass die Beispiele im Wiki inklusiv sind und nicht mehr oder weniger willkürlich Benutzergruppen von der Bedienung ausgeschlossen werden. Das gilt ganz besonders für solche Artikel wie diesen, die sich eher an angehende Backend-Entwickler richten, die oft überhaupt nicht auf dem Schirm haben, dass ihr Vorgehen in dieser Hinsicht problematisch sein könnte, und die später häufig Frontend-Aufgaben übernehmen.

                      Viele Grüße,

                      Orlok

                      1. Kleiner Zusatz: Wenn man das DOM über HTML-Strings zusammenbaut, sollte man im Allgemeinen die variablen Inhalte maskieren. Das ist hier nicht zwingend notwendig, da nur Zahlen eingesetzt werden, aber besser man verlässt sich nicht darauf.

                        // Quelle: https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript
                        function escapeHtml(unsafe) {
                            return unsafe
                                .replace(/&/g, "&amp;")
                                .replace(/</g, "&lt;")
                                .replace(/>/g, "&gt;")
                                .replace(/"/g, "&quot;")
                                .replace(/'/g, "&#039;");
                        }
                        
                        const createCounter = (online, visits) => {
                            document.body.insertAdjacentHTML(
                                'beforeend',
                                `
                                    <aside id="counter">
                                        <h2>User Counter</h2>
                                        <label for="online">Online:</label>
                                        <output id="online">${
                                            escapeHtml(online)
                                        }</output>
                                        <label for="visits">Visits:</label>
                                        <output id="visits">${
                                            escapeHtml(visits)
                                        }</output>
                                    </aside>
                                `
                            );
                        };
                        

                        BTW: Gibt es keine native Funktion in JS, die HTML maskiert?

                        1. @@1unitedpower

                          function escapeHtml(unsafe) {
                          

                          Hm, eine globale Funktion?

                          Wäre das nicht sauberer?

                          String.prototype.escapeHtml = function () {
                          	return this
                          		.replace(/&/g, "&amp;")
                          		.replace(/</g, "&lt;")
                          		.replace(/>/g, "&gt;")
                          		.replace(/"/g, "&quot;")
                          		.replace(/'/g, "&#039;");
                          };
                          

                          Und statt escapeHtml(visits) dann visits.escapeHtml().

                          Man könnte die Methode auch htmlSpecialChars() nennen. 😉

                          Warum wird eigentlich das > escapet? Ja, PHPs htmlspecialchars() tut das auch, aber > ist doch kein böses Zeichen?

                          LLAP 🖖

                          --
                          „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
                          „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

                          —Marc-Uwe Kling
                          1. Hallo Gunnar

                            function escapeHtml(unsafe) {
                            

                            Hm, eine globale Funktion?

                            Ob die Funktion global, ist hängt davon ab, wo sie definiert wird. Das lässt sich ja aus dem Schnippsel nicht ableiten. Grundsätzlich ist es aber natürlich nicht falsch, auch hier über die Kapselung des Codes nachzudenken. Die einfachste Methode das Ziel zu erreichen ist wohl, nur lexikalische Deklarationen (const oder let) zu verwenden und das ganze Programm in einem Anweisungsblock auszuführen, also etwa so:

                            // counter.js
                            
                            {
                                const escapeHTML = unsafe => {};const createCounter = (online, visits) => {};
                            }
                            

                            Da es sich bei dem Besucherzähler nur um ein Komfortfeature handelt, könnte man auch darüber nachdenken, das Programm als Modul einzubinden.

                            <script type="module" src="counter.js"></script>
                            

                            Wird ein Skript auf diese Weise eingebunden, dann sind prinzipiell alle im globalen Gültigkeitsbereich vorgenommenen Deklarationen auf eben dieses Skript beschränkt. Sie leaken nicht in den Scope von anderen Modulen oder Skripten. Der Browsersupport für Module liegt heute soweit ich weiß bei über achtzig Prozent. Ich finde das ist ein Fall, wo man über die Verwendung ohne Netz und doppelten Boden nachdenken kann.

                            Wäre das nicht sauberer?

                            String.prototype.escapeHtml = function () {
                            	return this
                            		.replace(/&/g, "&amp;")
                            		.replace(/</g, "&lt;")
                            		.replace(/>/g, "&gt;")
                            		.replace(/"/g, "&quot;")
                            		.replace(/'/g, "&#039;");
                            };
                            

                            Und statt escapeHtml(visits) dann visits.escapeHtml().

                            Ich halte das Verändern von eingebauten Objekten für schlechte Praxis. Bei diesen Objekten handelt es sich um geteilte Ressourcen und wie immer in solchen Fällen muss sichergestellt werden, dass sich die Nutzer dieser Ressourcen nicht in die Quere kommen. Als Entwickler erwarte ich die eingebauten Objekte so vorzufinden, wie sie standardisiert und dokumentiert sind. Wenn jedes eingebundene Skript die eingebauten Objekte nach belieben an die eigenen Bedürfnisse anpasst, dann ist das nicht mehr gewährleistet und es ist nur eine Frage der Zeit, bis es zu unvorhersehbaren Fehlern kommt.

                            Natürlich ist es unwahrscheinlich, dass ein anderes Programm ebenfalls eine Methode mit dem Namen escapeHtml auf String.prototype definieren will und diese Methode mit deiner Definition nicht kompatibel ist. Indem du dieses eingebaute Objekt manipulierst, handelst du aber nicht nach einer Maxime von der man wollen kann, dass sie allgemeines Gesetz werde. Es ist meiner Meinung nach eine gute Konvention, die gemeinsam genutzten Objekte nicht zu verändern.

                            Wenn man Standardobjekte unbedingt anpassen möchte, dann ist die bessere Vorgehensweise, eine von dem jeweiligen Typ abgeleitete Klasse zu erstellen. Im vorliegenden Fall ist das zwar nicht wirklich praktikabel, da es sich bei Strings nicht um Objekte sondern um einen primitiven Datentyp handelt, und wir die Werte darüber hinaus auch nicht selbst produzieren, aber in vielen Fällen erreicht man damit sein Ziel, ohne dabei die Ausführung von anderen Programmen zu gefährden.

                            Viele Grüße,

                            Orlok

                            1. Hallo Ingrid

                              Wäre das nicht sauberer?

                              String.prototype.escapeHtml = function () {
                              	return this
                              		.replace(/&/g, "&amp;")
                              		.replace(/</g, "&lt;")
                              		.replace(/>/g, "&gt;")
                              		.replace(/"/g, "&quot;")
                              		.replace(/'/g, "&#039;");
                              };
                              

                              Und statt escapeHtml(visits) dann visits.escapeHtml().

                              Ich halte das Verändern von eingebauten Objekten für schlechte Praxis.

                              Davon abgesehen, gibt es hier eine viel schönere Lösung.

                              Wenn wir Werte in ein Templateliteral einfügen, die escaped werden müssen, dann wollen wir die entsprechende Funktion doch eigentlich nicht für jeden dieser Werte einzeln aufrufen, egal ob als Funktions- oder als Methodenaufruf. Denn zum einen sind wir faul und zum anderen besteht dabei das Risiko, dass wir vergessen, einen der Werte zu escapen.

                              Wir könnten natürlich vor dem Zusammenbau über die Werte iterieren, aber das wäre unnötig umständlich. Außerdem ist der richtige Zeitpunkt für die kontextgerechte Behandlung, wenn die Werte in den neuen Kontext eingebracht werden.

                              Die schönere Lösung besteht darin, ein Tagged Template zu verwenden:

                              const createCounter = (online, visits) => {
                                  document.body.insertAdjacentHTML(
                                      'beforeend',
                                      escapeHTML`
                                          <aside id="counter">
                                              <h2>User Counter</h2>
                                              <label for="online">Online:</label>
                                              <output id="online">${
                                                  online
                                              }</output>
                                              <label for="visits">Visits:</label>
                                              <output id="visits">${
                                                  visits
                                              }</output>
                                          </aside>
                                      `
                                  );
                              };
                              

                              Wird wie oben direkt vor dem Templateliteral ein Tag in Form einer Funktionsreferenz notiert, dann werden die innerhalb des Templates notierten Ausdrücke zwar ausgewertet, aber der String wird nicht konkateniert. Stattdessen wird die angegebene Funktion mit den Teilzeichenketten des Templatestrings und den ermittelten Werten als Argument aufgerufen. Was von der Funktion zurückgegeben wird ist dann das Ergebnis des Ausdrucks.

                              Betrachten wir zunächst ein einfacheres Beispiel:

                              const square = ([_before, operator, _after], a, b) => {
                                  return `${a**2}${operator}${b**2}`;
                              };
                              
                              const expression = square`${2} + ${3}`;
                              
                              console.log(expression); // "4 + 9"
                              

                              Die Funktion square wird hier mit drei Argumenten aufgerufen. Das erste Argument ist ein Array, das die Teilstrings enthält. Die beiden anderen Argumente sind die Werte der Ausdrücke, die in dem Templateliteral notiert wurden. Ich destrukturiere hier das Array mit den Teilstrings, um an die Zeichenkette mit dem Operator zu kommen. Am Ende wird der Ausdruck mit den veränderten Werten neu zusammengesetzt.

                              Hier sollte zwei Aspekten besondere Aufmerksamkeit geschenkt werden:

                              1. In dem Ausdruck square`${2} + ${3}` scheint der Templatestring mit einem Platzhalter zu beginnen und mit einem Platzhalter zu enden. Das ist aber nicht richtig. Ein Template beginnt und endet immer mit einem String – in diesem Fall dem leeren String.

                              2. Die Gesamtzahl der Argumente mit denen die Funktion aufgerufen wird hängt davon ab, wieviele Ausdrücke in dem Template notiert wurden. In diesem Beispiel ist die Anzahl der Ausdrücke bekannt, weshalb wir einzeln benannte Parameter verwenden können.

                              Wenn es wie in unserem Anwendungsfall darum geht, prinzipiell beliebig lange Zeichenketten mit beliebig vielen Platzhaltern zu verarbeiten, dann können wir uns die Erkenntnis zu nutze machen, dass die Anzahl der Teilstrings genau um eins größer ist als die Anzahl der variablen Werte, die in das Template eingefügt wurden.

                              Die Funktionssignatur könnte demnach wiefolgt aussehen:

                              const escapeHTML = ([x, ...xs], ...unsafe) => {};
                              

                              Wir destrukturieren wieder das Array mit den Teilstrings. Dabei teilen wir unter Verwendung der Restsyntax die Liste der Strings in head und tail. Die zu escapenden Werte, deren Anzahl wir nicht kennen, werden ebenfalls mittels Restsyntax einem Array hinzugefügt.

                              Wir könnten nun den ersten Teilstring x als Rückgabewert nehmen und mit einer Schleife über die beiden Arrays iterieren, wobei wir die unsicheren Werte escapen und sie zusammen mit dem jeweils nachfolgenden Teilstring ans Ende von x anfügen. Ich finde es allerdings schöner, hierfür die Methode reduce zu verwenden.

                              const escapeHTML = ([x, ...xs], ...unsafe) =>
                                  xs.reduce((accumulator, safe, i) =>
                                      `${accumulator}${
                              
                                          String(unsafe[i])
                                              .replace(/&/g, '&amp;')
                                              .replace(/</g, '&lt;')
                                              .replace(/>/g, '&gt;')
                                              .replace(/"/g, '&quot;')
                                              .replace(/'/g, '&apos;')
                              
                                      }${safe}`, x);
                              

                              Wir rufen reduce auf dem Array mit den restlichen Teilstrings auf, wobei wir den ersten Teilstring als Initialwert übergeben. Unser Reducer ist eine Funktion die drei Argumente entgegennimmt. Das erste Argument ist der Akkumulator – beim ersten Aufruf der Initialwert, bei allen weiteren Aufrufen der Rückgabewert der Funktion. Das zweite Argument ist der Teilstring, der dem zu escapenden Wert nachfolgt. Das dritte und letzte Argument ist der Index.

                              Wir greifen in jedem Aufruf mit dem Index auf das Array mit den zu escapenden Werten zu. Da wir nicht wissen, ob es sich bei dem Wert wirklich um einen String handelt und wir Typfehler vermeiden wollen, casten wir den Wert, bevor wir die Methode replace aufrufen. Schließlich verwenden wir wieder ein Templateliteral, um den bereits verarbeiteten String, den escapeten Wert und den nächsten Teilstring zusammenzufügen.

                              Das Ergebnis ist dann das ursprüngliche Template mit allen Werten kontextgerecht escaped.

                              Viele Grüße,

                              Orlok

                          2. Wäre das nicht sauberer?

                            So ist die Funktion ebenfalls global, weil String schon global ist. Ich schließe mich Orlok an, ich erweitere fremde Objekte nur ungern und würde das eher mit einem Modul lösen.

                            Man könnte die Methode auch htmlSpecialChars() nennen. 😉

                            Das dürfte dann vielen Lesern aus PHP schon bekannt sein. Für sich genommen finde ich den Namen aber eher unglücklich.

                            Warum wird eigentlich das > escapet? Ja, PHPs htmlspecialchars() tut das auch, aber > ist doch kein böses Zeichen?

                            In unquoted Attributes schon. Dürfte aber ein sehr seltener Fall sein.