• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

Frage Text aus Tabelle in Zwischenablage

Sclero2004

Mitglied
Das ist jetzt doppelt: Wenn Du den Aufruf inline im HTML notierst, ist das addEventListener überflüssig, lösche es heraus.
 

colaholiker

Mitglied
Ich denke schon, denn ein paar \n einzufügen ist ja kein Problem, einmal Compilieren und Linken auch nicht. So hat man zumindest halbwegs lesbaren HTML-Code.
Aufwändiger wird es nur, wenn man auch noch Tidy-HTML einsetzen will, dann muss man eine zusätzliche Library erzeugen, aber auch das sollte für einen erfahrenen Programmierer kein unlösbares Problem darstellen.
Naja, nicht eingerückt ist ein immer noch besser als alles am Stück.
 

Sclero2004

Mitglied
Außerdem musst Du den Zellen mit dem Namen jeweils die Klasse "td-filename" verpassen, damit dieses:
Code:
nameCell = row.querySelector('.td-filename');
die Zelle findet.
 

Sclero2004

Mitglied
... und den Parameter definieren:
Code:
function Copy(event) {
Viel einfacher wäre es, auf das onclick im HTML zu verzichten und direkt meinen Code aus #7 zu verwenden. Dann musst Du nur den Zellen mit dem Namen die Klasse verpassen.
 

colaholiker

Mitglied
...Viel einfacher wäre es, auf das onclick im HTML zu verzichten und direkt meinen Code aus #7 zu verwenden. Dann musst Du nur den Zellen mit dem Namen die Klasse verpassen.
Das teste ich gerade.
Von der Sache mit der Zwischenablage habe ich erstmal Abstand genommen, das funktioniert nur wenn ich die Webseite vom PC her aufrufe. Erzeuge ich sie von außen (Microcontroller) geht das nicht mehr (ist wohl nicht Browser-orientiert).

Also habe ich Deinen Code aus #7 in

<script>
.td-filename {
[Code aus #7]
};
</script>

gesetzt und dann die entspr. Tabellen-Zellen als

<td class = "td-filename">Dir</td>

gekennzeichnet.
Wie gehe ich jetzt mit den Buttons um ohne onclick?
Auf dieses würde ich nämlich auch gerne verzichten, weil mein Code 'onclick statt "onclick erzeugt, was in HTML nicht läuft.

Zur Weiterverarbeitung müßte der Filename (statt in die Zwischenablage zu kommen) dann als Variabe in einer Funktion verwendet werden. Kann ich die Funktion ohne "onclick" erreichen?
 

Sclero2004

Mitglied
Dieses:
Code:
<script>
td-filename {
[Code aus #7]
};
</script>
macht so keinen Sinn. Ich vermute, Du wolltest damit die Verbindung zu dem Button herstellen. Das tut mein Code aus #7 jedoch schon. Damit das klarer wird, habe ich ihn jetzt etwas ausführlicher kommentiert:
Code:
<script>
// Wir registrieren zunächst einen Eventlistener für "window".
// Dieser feuert wenn irgend wo auf der Seite geklickt wurde.
window.addEventListener('click', event=> {
    // event.target ist das Element das geklickt wurde.
    // Wir prüfen jetzt ob der Button für das Kopieren
    // in die Zwischenablage gedrückt wurde. Das ist der Fall,
    // wenn es sich um einen Button in einer Tabelle handelt.
    if (event.target.matches('table button')) {
                const
                    // Vom Button ausgehend die Tabellenzeile ermitteln.
                    // Die Funktion closest sucht aufwärts das erste Element,
                    // das, in diesem Fall, ein Reihe in der Tabelle ist.
                    row = event.target.closest('tr'),
                    // und die Zelle mit dem Dateinamen
                    // dazu müssen wir dieser jeweils im HTML
                    // die Klasse "td-filename" geben
                    nameCell = row.querySelector('.td-filename'),
                    // Jetzt haben wir die Zelle und können daraus den Text auslesen:
                    fileName = nameCell.innerHTML;
                // Jetzt können wir eine Funktion aufrufen und dieser
                // den Namen übergeben.
                handleFileName(fileName);
    }
});
// Die Funktion, die aufgerufen wird, müssen wir natürlich auch definieren:
function handleFileName(fileName) {
    // Jetzt steht der Dateiname als Parameter "fileName" zur Verfügung
    // und Du kannst damit arbeiten.
}
</script>
 
Zuletzt bearbeitet:

colaholiker

Mitglied
Das kostet bestimmt Nerven bei mir Anfänger! Aber der Code funktioniert jetzt prima, vor allem auch per Microcontroller erzeugt.

Da ich von der Zwischenablage abgekommen bin, soll der Filename entweder auf einer weiteren Webpage in ein Eingabefeld gesetzt werden oder gleich im C++-Code verarbeitet werden.
Für diesen Fall sind mehrere Buttons in einer Tabellenzelle nötig (Download, Delete, Rename...), das würde sogar diese "weiteren Webpages" sparen.

Den Buttons vergebe ich immer noch eine eindeutige ID. An welcher Stelle frage ich diese ab, bzw. welcher Button gedrückt wurde (button.Name...)?
 

Sclero2004

Mitglied
Das kostet bestimmt Nerven bei mir Anfänger!
Keine Sorge, bei einem anderen Projekt von mir, Entwicklung einer Android-App, bin ich selber der Anfänger.

Da ich von der Zwischenablage abgekommen bin, soll er Filename entweder auf eine weitere Webpage in ein Eingabefeld gesetzt werden oder gleich im C++-Code verarbeitet werden.
Ich nehme mal an, der C++-Code läuft irgend wie auf dem Server, nicht wahr?
Mit dem Javascript befindest Du dich jedoch auf dem Client bzw. im Browser und hast nicht ohne weiteres Zugriff auf das was auf dem Server läuft. Das einfachste wäre, eine weitere Seite aufzurufen mit dem Dateinamen als GET-Parameter:
Code:
function handleFileName(fileName) {
    // Jetzt steht der Dateiname als Parameter "fileName" zur Verfügung
    // und Du kannst damit arbeiten.
    location.href = 'die-andere-Seite.html?name=' + fileName);
}
Dann steht dir dort der Dateiname als GET-Parameter zur Verfügung.
 

Sclero2004

Mitglied
Den Buttons vergebe ich immer noch eine eindeutige ID. An welcher Stelle frage ich diese ab, bzw. welcher Button gedrückt wurde (button.Name...)?
Eine ID braucht mein Code nicht. Der Button wird über event.target identifiziert. Javascript "weiß" ja, welcher Button gedrückt wurde und übergibt ihn automatisch an den Eventhandler.
 

colaholiker

Mitglied
Ich nehme mal an, der C++-Code läuft irgend wie auf dem Server, nicht wahr?
Mit dem Javascript befindest Du dich jedoch auf dem Client bzw. im Browser und hast nicht ohne weiteres Zugriff auf das was auf dem Server läuft. Das einfachste wäre, eine weitere Seite aufzurufen mit dem Dateinamen als GET-Parameter...

Server, Client? Also der Microcontroller irgendwo in LAN hat eine SD-Karte. Er wird von darauf befindlichen Webseiten von meinem PC-Browser her (zB.) gesteuert und eingestellt. Um diese Funktionen geht es hier im Thread aber nicht.
Ich bezeichne den Microcontroller als Client (es gibt etliche).
Der Server wäre dann mein PC? Also andersherum wie Du meintest...

Die SD- Karte bearbeite ich separat per C++ Code vom Microcontroller her (so hätte ich kein Problem, die SD-Karte sogar zu formatieren, stelle ich mir vor ...später).
Daher werden die Directory- Seite, eine zum Download. eine Upload-Seite usw. nicht von der SD-Karte geladen, sondern codemäßig jedesmal erstellt (bisher: wenn vorher ein Button außerhalb/unterhalb der Tabelle betätigt wurde).
Ob sich Variablen von einer Webpage auf eine andere übertragen lassen, wenn diese gerade neu erstellt wird halte ich für fraglich.
Deshalb wäre die Übergabe an meinen C++-Code wohl besser, auch wie ich schon schrieb, um die weiteren Webseiten einzusparen.
Eine ID braucht mein Code nicht. Der Button wird über event.target identifiziert. Javascript "weiß" ja, welcher Button gedrückt wurde und übergibt ihn automatisch an den Eventhandler.
Ja, aber in welcher Form? Es sind ja 4 (max) Buttons in einer Tabellenzeile.
Wie wird der erkannte Button (z.B. 'Rename' bezeichnet? Den brauche ich ja dann auch zur Übergabe an meinen Code.
Das würde ich natürlich auch testen, muß jetzt aber eine Weile weg...
 

Sclero2004

Mitglied
Es sind ja 4 (max) Buttons in einer Tabellenzeile.
OK, da hatte ich jetzt nicht genau aufgepasst, es ist also nicht nur 1 Button sondern mehrere. In dem Fall brauchst Du natürlich einen Identifier in Form einer Klasse. Die wäre in allen Tabellenzeilen gleich und Du kannst sie im Javascript so abfragen:
Code:
    <script>
        // Wir registrieren zunächst einen Eventlistener für "window".
        // Dieser feuert wenn irgend wo auf der Seite geklickt wurde.
        window.addEventListener('click', event => {
            // event.target ist das Element das geklickt wurde.
            // Wir prüfen jetzt ob der Button für das Kopieren
            // in die Zwischenablage gedrückt wurde. Das ist der Fall,
            // wenn es sich um einen Button in einer Tabelle handelt.
            if (event.target.matches('table button')) {
                const
                    // Vom Button ausgehend die Tabellenzeile ermitteln.
                    // Die Funktion closest sucht aufwärts das erste Element,
                    // das, in diesem Fall, ein Reihe in der Tabelle ist.
                    row = event.target.closest('tr'),
                    // und die Zelle mit dem Dateinamen
                    // dazu müssen wir dieser jeweils im HTML
                    // die Klasse "td-filename" geben
                    nameCell = row.querySelector('.td-filename'),
                    // Jetzt haben wir die Zelle und können daraus den Text auslesen:
                    fileName = nameCell.innerHTML;
                // Jetzt können wir eine Funktion aufrufen und dieser
                // den Namen übergeben.
                handleFileName(event.target, fileName);
            }
        });
        // Die Funktion, die aufgerufen wird, müssen wir natürlich auch definieren:
        function handleFileName(btn, fileName) {
            // Jetzt steht der Dateiname als Parameter "fileName" zur Verfügung
            // und Du kannst damit arbeiten.
            console.log(fileName);
            // Hat der Button die Klasse "add"?
            if (btn.classList.contains('add')) {
                console.log('Add-Button wurde gedrückt');
            }
            // Hat der Button die Klasse "delete"?
            if (btn.classList.contains('delete')) {
                console.log('Delete-Button wurde gedrückt');
            }
        }
    </script>
 

Sclero2004

Mitglied
Also der Microcontroller irgendwo in LAN hat eine SD-Karte. Er wird von darauf befindlichen Webseiten von meinem PC-Browser her (zB.) gesteuert und eingestellt.
...
Daher werden die Directory- Seite, eine zum Download. eine Upload-Seite usw. nicht von der SD-Karte geladen, sondern codemäßig jedesmal erstellt
Da treffen jetzt zwei verschiedene Welten aufeinander: Die des Microcontrollers und die der Webentwicklung. Aus Sicht der Webentwicklung ist das, wo die HTML-Seiten liegen, egal ob statisch oder dynamisch durch C++ erzeugt, der Server. Und der Browser auf dem PC (oder auch Tablet oder Handy), wo auch das Javascript läuft, der Client.
 

colaholiker

Mitglied
... und ich vermute jetzt, mit der Funktion hier:

meinst Du eine C++-Funktion, nicht wahr?
nein, Javascript, als Beispiel:

Code:
<script>
  function sendRes(res) {
    var xRes = new XMLHttpRequest();
    xRes.onreadystatechange = function() {
      if (this.readyState == 4 && this.status == 200) {
        document.getElementById("sendMCreset").innerHTML =
        this.responseText;
      }
    };
    xRes.open("GET", "setReset?sendMCreset="+res, true);
    xRes.send();
  }
</script>
Ein Reset-Button auf einer Webseite löst die Funktion aus, "MCreset1" wird zum Controller gesendet(Get,send), dort mit C++ weiterverarbeitet.

Ähem, die Buttons in der Tabelle funktionieren jetzt. Weiter gehts dann mit einer ähnlichen Funktion wie die oben und dem C++-Teil.
Aber vorher muß ich mich noch im <style> - Block tummeln. Die 4 Buttons (2x2) ragen über den Tabellenrand :-(
Dann überlege ich, den Upload-Button in den Tabellen-Footer zu tun, der gehört ja in keine Spalte.
 

Sclero2004

Mitglied
meinst Du eine C++-Funktion, nicht wahr?
nein, Javascript, als Beispiel:
Verstehe, dann müsste die Funktion in etwa so aussehen, mit fetch ist es wesentlich einfacher:

Code:
        function handleFileName(btn, fileName) {
            // Jetzt steht der Dateiname als Parameter "fileName" zur Verfügung
            // und Du kannst damit arbeiten.
            console.log(fileName);
            // Hat der Button die Klasse "add"?
            if (btn.classList.contains('add')) {
                console.log('Add-Button wurde gedrückt');
                fetch('handleFileAction?name="+ fileName + '&action=add';)
                    .then(response => { response.text() })
                    .then(text => {
                        document.getElementById("feedback-from-fetch").innerHTML = text;
                    });
            }
            // Hat der Button die Klasse "delete"?
            if (btn.classList.contains('delete')) {
                console.log('Delete-Button wurde gedrückt');
            }
        }
(ungetestet)
 

colaholiker

Mitglied
Ich habs so gemacht:
Code:
        function handleFileName(btn, fileName) {
            var xText;
            if (btn.classList.contains('dir')) {xText = 'Directory';
            }
            if (btn.classList.contains('do')) {xText = 'Download';
            }
            if (btn.classList.contains('de')) {xText = 'Delete';
            }
            if (btn.classList.contains('re')) {xText = 'Rename';
            }
            if (btn.classList.contains('so')) {xText = 'Sonstiges';
            }
            var xText = xText + ',' + fileName;
            xText.onreadystatechange = function(){
                if (this.readyState == 4 && this.status == 200) {
                    <!--1 document.getElementById("RelaisState").innerHTML =-->
                    <!--1 this.responseText;-->
                    <!--2 document.getElement(xText) = this.responseText;<!--
                    <!--3 element.innerHTML =  xText;-->
                }
            };
            xText.open('GET','setCommand?xText',true);
            xText.send();
        }
und kommt nicht durch zum Controller.

Den Zweck der auskommentierten Zeilen 1..3 verstehe ich nicht:
Das auskommentierte <!--1 ist zum Vergleich aus einem funktionierenden Code.
Da ich aber nicht mit IDs arbeite habe ich die Versionen <!--2 und <!--3 versucht.
Da ist Dein Vorschlag mit Fetch evtl. der richtige Weg.

Weitere Fehler können in der GET-Zeile auftreten, z.B. könnten wieder nicht die -'- akzeptiert werden statt der -"-.
Der Button "Directory" kommt immer allein vor, wenn ein Unterordner angezeigt wird. Der soll später den Pfad ändern.
Ich hatte die Idee, Button und fileName als einen String mit Trennkomma zu senden.
Komisch daß
if (btn.classList.contains('so')) {xText = 'Sonstiges,' + Filename;
}
nicht funktioniert hatte.
Morgen suche ich mal in älteren Projekten (die laufen) ob man Hochkommas in der GET- Anweisung verwenden darf.
 

Sclero2004

Mitglied
Vergleiche das mal genau mit deinem Code in #34:
Code:
    var xRes = new XMLHttpRequest();
Du musst zunächst ein XMLHttpRequest-Objekt erzeugen und darauf dann die Operationen durchführen.

Leider weiß ich nicht wie die Serverseite bzw. der Microcontroller die URL auswertet, die Du in open übergibst. Programmierst Du das selber? Normaler Weise macht man das so wie in meinem Code mit fetch.
 
Zuletzt bearbeitet:

colaholiker

Mitglied
Ich muß aber in Deinem Code #34 die Abfrage [if (btn.classList.contains('...] genauso für jede Buttonklasse wiederholen?

In der Fetch-Zeile zeigt mir der Debugger einen Syntax-Error an. Was ich mir jetzt zu fetch durchgelesen (und verstanden) habe bringt mich nicht weiter, ich habe einige Sachen versucht (-'- gegen -"- getauscht) Du hast auch mal -"- und -'- verwendet, aber das hat die Console mit dem Syntax-Error demnach nicht gemeint.
Obwohl im Quelltext dann nur die Zeile mit "fetch" blau hinterlegt ist kann sich wohl der Fehler im gesamten Ausdruck (.then...) befinden?
Die Befehle console.log() haben nichts ausgegeben.

Leider weiß ich nicht wie die Serverseite die URL auswertet, die Du in open übergibst. Programmierst Du das selber? Normaler Weise macht man das so wie in meinem Code mit fetch.


mit
Code:
            xText.onreadystatechange = function(){
                if (this.readyState == 4 && this.status == 200) {
                    element.innerHTML = xText;
                }
            };
            xText.open('GET','setCommand?xTest',true);
            xText.send();
(wobei element.innerHTML = xText; sicher falsch ist)

soll im C++-Code dann mit
Code:
 server.on("/setCommand",  handle_SD);
eine Routine "handle_SD()" durchlaufen werden wo ich dann auf die Eingaben reagieren kann. Dort sollen Aktion und Filename ankommen.
 

Sclero2004

Mitglied
Ich muß aber in Deinem Code #34 die Abfrage [if (btn.classList.contains('...] genauso für jede Buttonklasse wiederholen?
Ja, ich hatte eine Klasse verwendet weil ich dachte, das sei am Anfang am einfachsten. Du kannst auch ein data-Attribute nehmen:
dann kannst Du dessen Wert direkt verwenden, also im HTML so:
Code:
<td><button data-action="dir">ölagh</button></td>
und im JS kannst Du dann den Wert direkt verwenden, ohne Switch:
Code:
const
    action = event.target.dataset.action;
    queryString = `${action},${fileName}`;
Beachte die Backticks. Mit dieser Syntax kann man Variablen in einen String einfügen.
Poste am besten mal deinen Code mit dem fetch, dann kann man sicher schnell erkennen, warum das nicht läuft.
Noch eine Frage zum Hintergrund: Ich hatte vor etwas längerer Zeit Berührung mit einem Microcontroller-Projekt, da handelte es sich um einen Arduino und der C++-Code steckte in ino-Dateien statt cpp. Ist das bei dir etwas ähnliches?
 

colaholiker

Mitglied
Ja, ich hatte eine Klasse verwendet weil ich dachte, das sei am Anfang am einfachsten. Du kannst auch ein data-Attribute nehmen:
Ist ok: nur eine Klasse reicht ja um die Beiträge hier möglichst klein zu halten.

...auch ein data-Attribute nehmen...

Ich würde es gerne erstmal so zum laufen bringen (wo ich noch "etwas" verstehe:-(
Wir Anfänger brauchen noch unser gosub ;-)

Die Fehlermeldung im Debugger kommt sowie ich meine Testseite mit Deinem Code aus #35 hochlade. Was ich nur angepaßt habe ist die Klasse "dir" statt "add" und "del" statt "delete":
Code:
        function handleFileName(btn, fileName) {
            // Jetzt steht der Dateiname als Parameter "fileName" zur Verfügung
            // und Du kannst damit arbeiten.
            console.log(fileName);
            // Hat der Button die Klasse "dir"?
            if (btn.classList.contains('dir')) {
                console.log('Dir-Button wurde gedrückt');
                fetch('handleFileAction?name="+ fileName + '&action=dir';)
                    .then(response => { response.text() })
                    .then(text => {
                        document.getElementById("feedback-from-fetch").innerHTML = text;
                    });
            }
            // Hat der Button die Klasse "del"?
            if (btn.classList.contains('del')) {
                console.log('Delete-Button wurde gedrückt');
            }
        }
Die Errormeldung in der fetch-Zeile hatte ich wie o.erwähnt, nicht wegbekommen.

Beachte die Backticks. Mit dieser Syntax kann man Variablen in einen String einfügen.
Habe ich noch nicht gekannt. Im oberen Code sind aber keine Backticks.

Noch eine Frage zum Hintergrund: Ich hatte vor etwas längerer Zeit Berührung mit einem Microcontroller-Projekt, da handelte es sich um einen Arduino und der C++-Code steckte in ino-Dateien statt cpp. Ist das bei dir etwas ähnliches?
Ja genau, das ist eine .ino-Datei, mit einer zugehörigen Datei css.h. In letzterer stehen als Variablen der HTML-Codes gemeinsam für alle benötigten Webseiten (Kopf- und Fußteil), und im .ino werden die Zeilen fürs Directory oder was gerade erforderlich ist dazwischengetan und alles zusammengesetzt.
Der Prozessor ist ein ESP32, kein Arduino, aber die Arduino-IDE benutze ich auch für meine ESPs.
 
Zuletzt bearbeitet:
Oben