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

[ERLEDIGT] Button value als Variable möglich?

colaholiker

Mitglied
Sorry Sckero2004,
Ich habs bisher wohl vermasselt mit der Console: "Log" war deaktiviert.
Also nochmal: der neue Button:
-Response Type: "basic"...
-myblobtype: object
- Blob { size: 9, type: "text/blob" }
aufgeklappt:
size: 9
type: "text/blob"
<prototype>: BlobPrototype { slice: slice(), stream: stream(), text: text(), … }

Das gilt für:
Code:
server.send(200, "text/blob", "Test-blob");

Ich baue dann mal wieder den C++- Download- Code ein und melde mich mit dem Ergebnis...
 

colaholiker

Mitglied
So, hier die Consolen-Darstellung mit dem C++ Downloadcode und neuem Button:
Code:
001-Anfang.htm dir:184:9
============ myresponse: dir:247:9
Response { type: "basic", url: "http://192.168.178.49/dir?", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers(4), body: ReadableStream, bodyUsed: false }
dir:248:9
============ myblobtype: dir:252:9
object dir:253:9
Blob { size: 3312, type: "application/octet-stream" }
Die Zeilenangaben "dir:" gehören ganz nach rechts.
"Response..." und "Blob..." lassen sich aufklappen, mehrmals.
Schreib am besten was Du davon wissen möchtest.

Dasselbe mit dem alten Button ergibt wieder eine Zeile "POST..." und darunter nur das Prompt (die Fetch- Routine wird ja nicht genutzt).
 

Sclero2004

Mitglied
Tut mir Leid für die späte Antwort, waren dauernd andere Dinge ...
Code:
001-Anfang.htm dir:184:9
============ myresponse: dir:247:9
Response { type: "basic", url: "http://192.168.178.49/dir?", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers(4), body: ReadableStream, bodyUsed: false }
dir:248:9
============ myblobtype: dir:252:9
object dir:253:9
Blob { size: 3312, type: "application/octet-stream" }
Das sieht schon mal sehr gut aus, wir bekommen ein Blob vom Server zurück.
Jetzt muss ich nur noch heraus suchen, wie wir das Teil im Dateisystem speichern. Kann einen Moment dauern.
 

Sclero2004

Mitglied
Anscheinend geht das nur über den Umweg über einen Download-Link, den man durch das Skript klickt, siehe hier:
Code:
function saveBlob(blob, fileName) {
    var a = document.createElement("a");
    document.body.appendChild(a);
    a.style = "display: none";

    var url = window.URL.createObjectURL(blob);
    a.href = url;
    a.download = fileName;
    a.click();
    window.URL.revokeObjectURL(url);
};

saveBlob(file, 'test.zip');

Edit: Geht doch ohne den Trick mit dem Link, siehe hier:
Das Beispiel mit der Funktion saveFile, funktioniert bei mir einwandfrei.
 
Zuletzt bearbeitet:

colaholiker

Mitglied
Vielen Dank nochmal für Deine ganze Mühe, das kostet ja etliche Zeit.

Ehe ich saveFile probiere würde ich gerne noch wissen:

- ob die Funktion von der Blob-Fetch- Routine her aufgerufen werden muß (damit im Blob Daten enthalten sind)
- oder direkt aus der Funktion "handleFileName", etwa so:
Code:
...
case 'download':
saveFile(fileName);
 break;
...
Wie baue ich den Filenamen dann in die Funktion "saveFile" ein (const writableStream =...)
Da gehört doch sicher URL(SD)+Pfad+filename zusammen?
 

Sclero2004

Mitglied
Du musst die Funktion im then-Zweig des fetch aufrufen:
Code:
            fetch('deine-url', {
                method: 'post',
                body: deinBody
            }).then(response => {
                return response.blob();
            }).then(blob => {
                saveFile(blob, fileName);
            });
Und den Dateinamen kannst Du so einstellen:
Code:
        async function saveFile(blob, fileName) {
            // create a new handle
            const newHandle = await window.showSaveFilePicker({
                suggestedName: fileName
            });

            // create a FileSystemWritableFileStream to write to
            const writableStream = await newHandle.createWritable();

            // write our file
            await writableStream.write(blob);

            // close the file and write the contents to disk.
            await writableStream.close();
        }
 

colaholiker

Mitglied
Leider kein Download.

Console:
001-Anfang.htm dir:195:9
============ myresponse: dir:258:9

Response { type: "basic", url: "http://192.168.178.49/dir?", redirected: false, status: 200, ok: true, statusText: "OK", headers: Headers(4), body: ReadableStream, bodyUsed: false }
dir:259:9
============ myblobtype: dir:263:9
object dir:264:9

Blob { size: 3312, type: "application/octet-stream" }
dir:265:9

dann rot hinterlegt:

Uncaught (in promise) TypeError: window.showSaveFilePicker is not a function
saveFile http://192.168.178.49/dir:334
sendtoMCdir http://192.168.178.49/dir:266
promise callback*sendtoMCdir http://192.168.178.49/dir:262
handleFileName http://192.168.178.49/dir:234
<anonymous> http://192.168.178.49/dir:159

In einem weiteren Versuch hatte ich ein Semikolon gesetzt:
Code:
  const newHandle = await window.showSaveFilePicker({
    suggestedName: fileName;
    });
Das ergab zwar einen Syntaxerror, aber in der ersten Zeile tauchte "Post..." auf statt "001-Anfang.htm", genauso wie beim Originalbutton.
 

colaholiker

Mitglied
Das funktioniert mit dem Link!

Zwei Fragen habe ich dazu:

- Die letzte Zeile
Code:
saveBlob(file, 'test.zip');
steht außerhalb der Funktion. Ist das ein Dummy?
- Im Seitenquelltext sollte ich das <a>- Element doch finden?
(über </script></body> befindet sich ja (zufällig) die genannte Zeile).

Nachmittags werde ich noch viel damit testen, z.B. welchen Einfluß die Daten aus C++ auf die Sache haben, ob ich den "Dummy" weglassen kann usw.
Die Methode könnte sich auch gut für Buttons in der <ul>- Leiste eignen. Evtl. ist sogar ein "ständiges" <a> Element besser, dessen Inhalt nur jeweils angepaßt wird.
 

Sclero2004

Mitglied
- Die letzte Zeile
Code:
saveBlob(file, 'test.zip');
steht außerhalb der Funktion. Ist das ein Dummy?
Nein, das ist kein Dummy. Durch das function saveBlob(blob, fileName) { wird die Funktion zunächst mal nur definiert, ohne dass der Code darin ausgeführt wird. Damit er ausgeführt wird, muss sie aufgerufen werden und das macht diese Zeile.

- Im Seitenquelltext sollte ich das <a>- Element doch finden?
Im Quelltext nicht, weil sie dynamisch eingefügt wird aber im Seiteninspektor solltest Du sie auf jeden Fall finden.
 

colaholiker

Mitglied
weiter geht's.
wird die Funktion zunächst mal nur definiert, ohne dass der Code darin ausgeführt wird. Damit er ausgeführt wird, muss sie aufgerufen werden und das macht diese Zeile.
Naaa, ohne diese geht es auch da ich die Funktion bereits aus der Blob-Fetch-Routine anspreche.
Ohne den Aufruf dort und dagegen "diese Zeile" aktiv geht es nicht.
Also: auskommentiert.

Das Semikolon am Funktionsende konnte ich auch weglassen.

In C++ genügt es, den ganzen Code (vgl.#85) wegzulassen und einfach
Code:
server.send(200, "text/text", "xxx");
abzuschicken. Das soll einer verstehen.

Zu <a>:
Im Quelltext nicht, weil sie dynamisch eingefügt wird aber im Seiteninspektor solltest Du sie auf jeden Fall finden.

liegt wohl an
Code:
window.URL.revokeObjectURL(url);
Ich wollte ja mit einem statischen <a> Element testen ob ich damit weitere Buttons verwenden kann.

Vorher muß ich erstmal wieder die anderen Fetch- Funktionen aktivieren (Delete...).

Dazu werde ich versuchen, den Blob- Code mit diesen Sachen in eine Funktion zu bekommen.
 

colaholiker

Mitglied
guten Morgen,
gestern fiel mir noch auf, daß die Daten von C++ keinesfalls egal sind betreffs des Downloads.
Sende ich "irgendwas" wird lediglich eine Datei mit dem Filenamen ohne Inhalt erzeugt und geladen.

Mein Stand ist jetzt, zwei getrennte Fetch- Routinen für Text und Blob zu benutzen; ich habe beide gestern nicht zusammenbekommen. So sieht das jetzt aus:
Code:
        function sendtoMCdir(action, fileName) {
            const params = new FormData();
            params.append('0', action + '_' + fileName);
            fetch('dir?', {
                method: 'post',
                body: params
            })
            .then(response => response.text())
            .then(txt => {
                console.log('============ myText: ');
                console.log(txt);
                const
                parser = new DOMParser(),
                docLoaded = parser.parseFromString(txt, 'text/html');
                console.log('============ mydocLoaded:');
                console.log(docLoaded);
                const
                tblCurrent = document.querySelector('table'),
                tblLoaded = docLoaded.querySelector('table');
                console.log('============ mytblCurrent:');
                console.log(tblCurrent);
                console.log('============ mytblLoaded:');
                console.log(tblLoaded);
                tblCurrent.replaceWith(tblLoaded);
                const
                h1Current = document.querySelector('h1'),
                h1Loaded = docLoaded.querySelector('h1');
                h1Current.textContent = h1Loaded.textContent;
            });
            document.getElementById('delete-dialog').close();
            document.getElementById('rename-dialog').close();
        }
    
        function sendtoMCdir_dwnl(action, fileName) {
            const params = new FormData();
            params.append('0', action + '_' + fileName);
            fetch('dir?', {
                method: 'post',
                body: params
            })
            .then(response => response.text())
            .then(txt => {
                console.log('============ mytext:');
                console.log(typeof blob);
                    saveBlob(blob, fileName);
            });
        }

Dafür funktionieren aber alle bisher angepaßten Buttons erstmals zusammen. Der Button "Stream" ist von <ul> in die Tabelle gewandert und soll dort später zugehörige Dateien im Browser öffnen (also auch Texte und Bilder). Ob das geht muß ich erst noch sehen.

Weiter werde ich mich damit befassen, das Element <a> für den Link fest einzubauen und dann zu testen wie ich ihn auch für andere Linkbuttons benutzen kann, ungefähr so:
Code:
<a class= 'a_link' style= display: none></a>
<script>       
     function sendLink(link, fileName) {
            var url = window.URL.createObjectURL(link);
            a.href = url;
            // if () {a.download = fileName;}
            a.click();
        }
</script>
 

colaholiker

Mitglied
...gemäß #111 habe ich das <a> Element fest in die Webseite eingebaut:
Code:
<a id= 'a_link' style= display: none></a>
und die Funktion angepaßt.
Hier der Code der Funktion und was der Inspektor daraus macht:
Code:
    function sendLink(blob, fileName) {
        var a = document.getElementById('a_link');
        var url = window.URL.createObjectURL(blob);
        a.href = url;
        a.download = fileName;
        a.click();
    }

<a id="a_link" style="display:" none="" href="blob:http://192.168.178.49/a2e1e4ef-bead-4a0e-ae87-494ab85526de" download="001-Anfang.htm"></a>
Das kann doch nur eine Anpassung durch Firefox sein? Immerhin funktioniert ja alles.

Nur um den Code für andere Buttons (ohne blob oder fileName) zu erweitern wüßte ich gerne, was wirklich in <a> steht...
 

Sclero2004

Mitglied
Ja, das wurde durch FF angepasst. Dieses:
Code:
style= display: none
ist fehlerhaft und müsste so aussehen:
Code:
style="display: none;"
FF hat wohl versucht, aus dem fehlerhaften etwas sinnvolles zu machen, aber ohne Erfolg.
Und beim href-Attribut ist der Wert die ObjectURL, die Du ihm zugewiesen hast und die aus dem Blob entstanden ist.
 

colaholiker

Mitglied
Hallo,
jetzt habe ich das Problem, <a></a> leer zu bekommen:
Code:
        function sendLink(fn, blob, fileName) {
        var a = document.getElementById('a_link');
        if ( fn == 'dnl' )
            {
                var url = window.URL.createObjectURL(blob);
                a.href = url;
                a.download = fileName;
            }
        if ( fn == 'homepage' )
            {
                var url = '/';
                a.href = url;
            }
        a.click();
        window.URL.revokeObjectURL(url);
        a.href = '';
        }
Der Ausdruck window.URL.revokeObjectURL gibt die URL im Speicher frei (im Inspektor wird sie auch aus <a> entfernt) und dann sieht es im Falle von "fn == 'dnl'" so aus:
Code:
<a id="a_link" style="display: none;" download="001-Anfang.htm"></a>
Daher mein -unwirksames- "a.href = '';" am Ende.
Es entsteht bei "fn == 'homepage'"
Code:
<a id="a_link" style="display: none;" href="/" download="001-Anfang.htm"></a>
und trotz der angeblich im Speicher freigegebenen Blob-URL wird der Download wieder durchgeführt.

Geht es, "a.href" und "a.download" zu einer URL zusammenzufassen um unten komplett den <a>-Inhalt zu entfernen?
----------------------------
Ähm, ich sehe gerade <a id= [...] href="/" download="001-Anfang.htm"></a>
richtig wäre doch
<a id= [...] >href="/" download="001-Anfang.htm"</a>
oder?
 
Zuletzt bearbeitet:

Sclero2004

Mitglied
trotz der angeblich im Speicher freigegebenen Blob-URL wird der Download wieder durchgeführt.
Das liegt daran, dass Du immer noch das Attribut download drin hast. Das veranlasst den Browser, den Inhalt von href herunter zu laden anstatt ihn anzuzeigen. Lösche das Attribut mit removeAttribute, dann sollte das nicht mehr passieren.

ich sehe gerade <a id= [...] href="/" download="001-Anfang.htm"></a>
richtig wäre doch
<a id= [...] >href="/" download="001-Anfang.htm"</a>
oder?
Nein, das erste ist richtig, das a-Tag besteht aus einem öffnenden und einem schließenden Tag.
 
Zuletzt bearbeitet:

colaholiker

Mitglied
Lösche das Attribut mit removeAttribute, dann sollte das nicht mehr passieren.
Jetzt funktioniert es...
Hat was gedauert: wichtig ist die Reihenfolge...
Code:
        a.click();
        a.removeAttribute('download');
        a.URL.revokeObjectURL(url);
Jetzt kann ich probieren was sich mit den restlichen Buttons so anstellen läßt (Ordner erstellen, umbenennen, löschen usw.).
Das findet warscheinlich meist in C++ statt.

Vielen Dank Sclero2004 für die Hilfe bisher!
Garantiert melde ich mich wieder mal, dann zu einem neuen Thema.
 
Oben