mumpel: Tampermonkey: Neues Tag einfügen

Hallo!

Gegeben ist ein DIV mit IMG.

<div id="test">
 <img src="seite.de/bild.png" title="test">
</div>

Nun möchte ich per Tampermonkey ein neues Tag einfügen (menu). Mit document.querySelectorAll('div img') komme ich ja an die Elemente/Elementauflistung. Ich habe zwar schon ein paar Codes gefunden, aber da bekomme ich in Tampermonkey die Meldung "variablenname" used out of scope. Weiss jemand wie man es richtig macht? Oder kennt ihr eine Seite auf der ich das lernen/nachlesen kann? Danke!

(Als Hinweis: Es soll ein neuer Menüpunkt in das Kontextmenü der Bilder eingebaut werden, über dass der src des Bildes in die Zwischenablage kopiert werden soll).

Gruß, René

  1. Hallo mumpel,

    nach einem img zu suchen, um darin ein Menü einzufügen, nützt nicht viel. Ein img ist eine ganz arme Socke, es darf keine Kinder haben. Du kannst ihm aber Geschwister geben, also ins div ein Menü einfügen. document.getElementById("test") - damit kannst Du weitermachen.

    Ansonsten: Was hast Du dem Fummeläffchen denn gegeben, woraus die Meldung mit dem Variablennamen resultiert?

    Rolf

    --
    sumpsi - posui - clusi
    1. Natürlich soll das in den DIV. Sollte aber kein Problem sein.

      Ansonsten: Was hast Du dem Fummeläffchen denn gegeben

      So wie ich es auf dem Internet habe.

      var createTag = document.CreateElement('menu');
          createTag.setAttribute('contextmenu', 'setTest()');
      
      1. @@mumpel

        So wie ich es auf dem Internet habe.

        var createTag = document.CreateElement('menu');
        

        So hast du es aus dem Internet?

        So wird das nichts. Das sollte dir die Fehlerkonsole deines Browsers auch verraten, dass es keine Methode document.CreateElement() gibt.

        Ein Kamel hat große Höcker, aber keinen großen Kopf. 🐪

        LLAP 🖖

        --
        „Wer durch Wissen und Erfahrung der Klügere ist, der sollte nicht nachgeben. Und nicht aufgeben.“ —Kurt Weidemann
      2. Hallo mumpel,

        was auch immer deine Quelle da geliefert hat - es ist eine Schwefelquelle. Sie stinkt. Kannst Du uns den Link sagen?

        Und wenn Du nicht mehr als das gezeigte eingegeben hast - da fehlt eigentlich alles relevante.

        • Es reicht nicht, ein Element zu erzeugen. Man muss es auch ins DOM hängen. Zum Beispiel als Kind des div mit id='test'.
        • Ein menu-Element braucht eine id - natürlich eine andere als test
        • Diese id muss dem Element, das das Kontextmenü anzeigen will, per contextmenu-Attribut bekannt gemacht werden
        • Dem contextmenu-Attribut wird eine id zugewiesen, kein Javascript-Fragment
        • Ein menu-Element braucht menuitems
        • Diese items brauchen click-Eventhandler, die reagieren wenn der Menüpunkt ausgewählt wird.

        Rolf

        --
        sumpsi - posui - clusi
        1. Das was ich hier gezeigt habe ist was den Fehler anzeigt. Wenn es da schon einen Fehler gibt brauch ich nicht weitermachen. 😉

          Hier mal alles was ich bisher habe. Bei "id" muss ich natürlich noch ändern (alle Elemente mit id = null ist nicht gut).

          // ==UserScript==
          // @name         CreateIMG-Link
          // @namespace    http://tampermonkey.net/
          // @version      0.1
          // @description  Bildlink extrahieren
          // @author       Ich
          // @match        https://seite.com/*
          // @grant        none
          // ==/UserScript==
          
             (function() {
              'use strict';
              var newElem = document.createElement( 'script'); //create a script tag
                  newElem.type = 'text/javascript'; // add type attribute
                  newElem.innerHTML = 'function setTest () {var el = "test";window.alert(test);}'; // add content i.e. function definition and a call
                  document.head.appendChild(newElem); // Insert it as the last child of body
             })();
          
          var timeoutClick;
          function setClickAttribute() {
              'use strict';
              var observer = new MutationObserver(function(mutations) {
                  if (mutations[0].addedNodes.length > 0) {
                      var hasAddedH4 = true; // hier noch Code einfügen, um zu schauen ob wirklich ein h4 eingefügt wurde
                      if (hasAddedH4) {
                          var newTag = document.querySelectorAll('img ');
                          if (newTag && newTag.length) {
                              for (var i = 0; i < newTag.length; i++) {
                                  var node = newTag[i].firstChild;
                                  if (node && node.nodeType == 3)
                                      var newSubTag = document.createElement('menu');
                                      newTag[i].appendChild(newSubTag);
                                      newSubTag.setAttribute('type', 'context');
                                      newSubTag.setAttribute('id', 'null');
                              }
                          }
                      }
                  }
              });
              observer.observe(document, { childList: true, subtree : true });
          }
          timeoutClick = window.setTimeout(setClickAttribute, 3000);
          

          Aber wonach muss ich suchen. Wie lauten da die korrekten Suchbegriffe?

          1. Hallo mumpel,

            die grundsätzliche Strategie hatte ich ja aufgeschrieben; wie du sie in den Tampermonkey einbringst ist natürlich ein weiteres Thema. Da ich das Äffchen bisher nicht verwendet habe, habe ich da keine Erfahrung.

            Verwendest Du eigentlich Firefox? Weil - wenn nicht, funktioniert contextmenu nicht. Dieses Attribut war mal auf dem Weg in den Standard, aber weil es nur von Firefox implementiert wurde, gilt als mittlerweile als missbilligt.

            In deinem Code sehe ich folgende Probleme:

            • Deine Experimentierfunktion setTest erzeugt eine Variable el, verwendet sie im darauf folgenden alert() aber nicht. Statt dessen steht da test, ohne Anführungszeichen, und die Deklaration einer Variablen dieses Namens fehlt. Das mag den out-of-scope Fehler erklären. Welche Variable genau wird da eigentlich als fehlend angemeckert?

            • Ob „Script im String“ der beste Weg ist, um deinen Menü-Eventhandler unterzubringen, weiß ich nicht. Ist das durch Tampermonkey zwingend bedingt?

            • Das Menü musst Du nur einmal erzeugen, nicht einmal pro img. Das ist auch ganz praktisch so, weil Du Dir sonst für jedes Bild eine eigene ID für das zugehörige Menü ausdenken müsstest. Das Erzeugen des Menü kannst Du im gleichen Script-Teil machen, in dem Du das Script ins DOM hängst.

            • Du versuchst immer noch, einem img ein Kind anzuhängen. LASS DAS. Bilder sind unfruchtbar. Sie bekommen keine Kinder. Du musst lediglich für den img-Node die contextMenu Eigenschaft setzen.

            • Es geht die Mär, dass eine Funktion einen Eingang und einen Ausgang haben muss, alles andere sei schlechter Stil. Aber sag mir: was ist besser: Ein Einrückungsgebirge, wie bei Dir, oder das hier. Da Du Tampermonkey verwendest, wird der Code für FF oder Chrome sein, also kann man neueres Ecmascript verwenden...

            function(mutations) {
               if (!mutations[0].addedNodes.length) return;
            
               let hasAddedH4 = true; // bzw. Ergebnis einer h4 Ermittlung
               if (!hasAddedH4) return;
            
               // querySelectorAll liefert IMMER eine NodeList
               document.querySelectorAll("img").forEach(bild => bild.contextMenu = "myCtxMenu");
            }
            

            Rolf

            --
            sumpsi - posui - clusi
            1. weil Du Dir sonst für jedes Bild eine eigene ID für das zugehörige Menü ausdenken müsstest.

              Das könnte man theoretisch wie in VBA machen? el.setAttribute('id', 'menu'+i);

              Dein Codebeispiel teste ich wenn ich wieder zuhause bin. Da habe ich Zugriff auf die entsprechende Internetseite.

              1. Hallo mumpel,

                Das könnte man theoretisch wie in VBA machen? el.setAttribute('id', 'menu'+i);

                Kann man. Muss man aber nicht :) Deine Kontextmenüs werden ja alle gleich sein. Also reicht eins.

                Rolf

                --
                sumpsi - posui - clusi
                1. Nun soll das Kontextmenü aber nur bei Bildern sein die in einem div eingeschlossen sind. Dann doch so document.querySelectorAll("div img") ?

                  1. Hallo mumpel,

                    Nun soll das Kontextmenü aber nur bei Bildern sein die in einem div eingeschlossen sind. Dann doch so document.querySelectorAll("div img") ?

                    Ggf. auch document.querySelectorAll("div > img").

                    Bis demnächst
                    Matthias

                    --
                    Rosen sind rot.
                  2. Hallo mumpel,

                    Ja. Die Formulierung des korrekten Selektors ist Deine Sache :)

                    Das Menü selbst kann irgendwo stehen. Ok, nicht IRGENDWO, es muss im body sein und nicht Kind von irgendwas, was keine Kinder haben kann (img oder input)...

                    Rolf

                    --
                    sumpsi - posui - clusi
            2. Hab es gerade mal probiert. Ercheint leider kein Eintrag im Kontextmenü.

              1. Hallo mumpel,

                vielleicht ist was falsch in dem was ich geschrieben hatte.

                Und angesichts der Tatsache, dass das, was ich da geschrieben habe, unvollständig war (z.B. habe ich die Definition des Kontextmenüs selbst nicht ausformuliert), mag das Problem auch in deinen Ergänzungen liegen.

                Den Tampermonkey habe ich nicht installiert und will ihn auch nicht haben, vielleicht muss man da noch Besonderheiten beachten. Ich kann Dir also die Lösung nicht komplett präsentieren; du musst auch noch was selbst dazu beitragen. Grundsätzlich ist ein Kontextmenü im Firefox möglich, also ohne die dynamischen Dinge die man mit Tampermonkey tun muss, das habe ich in einem jsFiddle probiert. Hier: https://jsfiddle.net/Rolf_b/n0crkhvh/

                Happy Debugging also - mach die Entwicklertools vom Firefox auf und guck, was da so an Meldungen in der Konsole erscheint.

                Rolf

                --
                sumpsi - posui - clusi
              2. Hallo mumpel,

                habe gerade nun doch mal den Affen in den Fuchs gesteckt und was probiert.

                Fehlermeldung: Execution of script 'Menu' failed! setting getter-only property "contextMenu"

                Würde sagen: So geht's nicht. Die Eigenschaft ist schreibgeschützt. Ich wüsste jetzt nicht, wie man sie von JavaScript aus ändern sollte, es sei denn durch schweres Geschütz: Container des img suchen (das div), innerHTML dieses Containers auslesen, alle img-Elemente manipulieren dass sie das contextMenu-Attribut bekommen, innerHTML überschreiben. Das löst dann ein Layout-Update aus und dürfte ordentlich flackern.

                Angesichts der Tatsache, dass contextMenu ohnehin auf der Abschussliste steht, wäre die Idee damit tot.

                Es gibt noch das contextmenu-Event, auf das man sich registrieren kann (das ist die klassische Methode um den Klick auf die "rechte" Maustaste zu unterbinden), damit kannst Du aber keine Menüpunkte ins Browser-Kontextmenü hineinmogeln. Statt dessen kannst Du ein EIGENES Menü hochbringen, d.h. ein DIV in den Body kleben und darin ein paar Buttons unterbringen. Von <menu> würde ich hier abraten, weil caniuse.com sagt, dass <menu> nur von Firefox und nur für type="context" unterstützt würde.

                Du willst ja sicherlich nicht vorhandene Fuchsfeatures überschreiben, sondern ergänzen. D.h. Du könntest es BEISPIELSWEISE so machen, dass Du auf das contextmenu-Event reagierst und darin prüfst, ob die Maus zusammen mit der Alt-Taste geklickt wurde. Wenn ja, bringst Du deine eigene Funktionalität, wenn nein, tust Du nichts - woraufhin das Browser-Kontextmenü erscheint.

                Dein Tampermonkey-Script muss also über die Nodelist laufen, die aus querySelectorAll zurückkommt und für jeden Eintrag einen contextmenu Eventlistener hinzufügen (mit addEventListener). In der Handler-Funktion greift man auf das target-Attribut des Event-Objekts zu, das ist das img, und findet dort den src. Den kann man dann weiterverarbeiten. Wie man den Wert ins Clipboard bekommt, weißt Du hoffentlich - ich nicht (müsste es erstmal nachgucken).

                Ich habe das gerade mal im Tampermonkey probiert - mit einem alert für den src statt einem Copy ins Clipboard - klappt ganz gut. Aber ich bin ja kein Vorkauer und will Dir dein Erfolgserlebnis beim Selbermachen nicht nehmen. Viel Spaß 😀

                Rolf

                --
                sumpsi - posui - clusi
                1. Das Kontextmenü bekomme ich nur mit "bild.setAttribute" eingebaut.

                  Schade dass das nicht geht. Wäre eine feine Zwischenlösung bis der Hersteller von Coyo mal reagiert und etwas vernünftiges ausliefert. Falls er diesbezüglich überhaupt etwas machen kann (er kann ja auch keinen funktionierenden Kontextmenüeintrag reinzaubern)

                  Danke euch allen!

  2. Hi,

    (Als Hinweis: Es soll ein neuer Menüpunkt in das Kontextmenü der Bilder eingebaut werden, über dass der src des Bildes in die Zwischenablage kopiert werden soll).

    In meinen Browsern (Firefox, Chrome, und sogar im IE) gibt es diesen Menüpunkt bereits im Kontextmenü eines Bildes.

    Warum willst Du das nochmal reinbauen?

    cu,
    Andreas a/k/a MudGuard

    1. Bei Bildern gibt es das tatsächlich. Aber leider nur bei echten Bildern. Bei unechten Bildlinks (DIVs denen ein background-image per "style" oder "mg-style" zugewiesen wird) leider nicht. Da bekommt man nur die Serveradresse ("www.seite.de"), aber nicht den kompletten Bildlink.

    2. Es gibt auch Anhänge die als Bildvorschau eingebunden sind, davon wird der Link zum Anhang benötigt. Alles nicht so einfach bei Coyo.