in Textarea strings sammeln, dannach in die Zwischenablage kopieren
Joachim
- html
Hallo und frohes Neues allerseits.
Ich habe folgendes Problem: auf der Arbeit muss ich zwecks Dokumentation die Namen & LOT-Nummern der verwendeten Matrialien notieren, wobei ich bei unterschiedlichen Aufgaben unterschiedlich viele Materialien benutze (ca. 45 verschiedene Materialien).
Zur Arbeitserleichterung will ich mir eine einfache Webseite machen, die ich mit diversen Buttons, die jeweils für ein Material stehen, versehe. Beim clicken auf ein oder mehrere Buttons soll in einer Textarea alles angezeigt werden - pro Zeile ein Material samt LOT-Nr. Darunter ein Button zum kopieren des gesamten Textes in die Zwischenablage und danach löschen des Inhaltes der Textarea.
Mein Ansatz: jeden Button mit einer id belegen, dann mit einem onclick eine Funktion aufrufen. Die id wird in eine var (string) umgewandelt. Anschließend wird diese var zu einer anderen var (ebenfalls ein string, aber global) hinzugefügt, die nun in die textarea hineinkopiert wird.
Bsp:
dannach 2. click auf Button afa3 -> function -> id =var1 (afa3); varZeig = var1 (afa3) + varVorhanden(afa2); VarZeig wird in textarea angezeigt : (afa2 afaf3)
Danach click auf den Kopierbutton, wobei der Text in die Zwischenablage kopiert und das textarea geleert wird.
Wie ihr euch nun denken könnt, habe ich mich erst jetzt in HTML und JS eingelesen und kann fast nichts...
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</br>
<button onclick="document.getElementById('MatLot').value = afa2"> flow 2 </button>
<button onclick="document.getElementById('MatLot').value = afa3"> flow 3 </button>
<button onclick="document.getElementById('MatLot').value = afa35"> flow 3,5 </button>
</br>
<textarea id="MatLot" cols="75" rows="10" placeholder="Verwendete Materialien"></textarea></br>
<input placeholder="Paste here, to try!"></br></br></br>
<p> Testtext Überschrift</p>
<button onclick="myFunction()">Copy text</button>
<script>
var afa2 = "flow a2 lot: 12345 \n";
var afa3 = "flow a3 lot: 23456 \n";
var afa35 = "flow a3,5 lot: 34567 \n";
function myFunction() {
var copyText = document.getElementById("MatLot");
copyText.select();
copyText.setSelectionRange(0, 99999)
document.execCommand("copy");
//alert("Copied the text: " + copyText.value);
}
</script>
</br>
</body>
</html>
Quelltext hier
Könnte mir jemand bitte helfen?
Hallo Joachim,
sowas kann man machen - aber ist es die beste Idee?
Ich frage mich: Klickst Du die Buttons in unterschiedlichen Reihenfolgen, um auch eine bestimmte Reihenfolge in der Doku zu erhalten? Oder ist die Reihenfolge egal - vielleicht sogar vorgegeben, in der die Materialien im Dokument erscheinen sollten?
In dem Fall wäre es besser, Checkboxen statt Buttons zu verwenden, von denen Du die benötigten anhakst. Und ja, natürlich braucht jeder der Buttons dafür eine ID.
Schließen sich bestimmte Materialien gegenseitig aus? In dem Fall könntest Du sie zu einer Radiobutton-Gruppe zusammenfassen (das macht man, indem man mehreren Radiobuttons das gleiche name Attribut gibt)
Gibt es Mengenangaben? Die könnte man noch hinzufügen.
Am Ende hast Du dann nur noch einen Button: COPY. Hinter dem liegt dann JavaScript, dass die Checkboxen-/Radiobuttons abklappert und dementsprechend den Text zusammenbaut. Den schreibst Du in die <textarea> und kopierst es ins Clipboard. Die textarea selbst kannst Du verstecken, die braucht keiner zu sehen (mit position:absolute; left: -10000px; ins Nirvana verschieben).
Ich würde vorschlagen: Wie man das genau tut, besprechen wir, wenn wir deine fachlichen Wünsche unabhängig von deinen technischen Ideen diskutiert haben.
Rolf
@@Rolf B
Die textarea selbst kannst Du verstecken, die braucht keiner zu sehen (mit position:absolute; left: -10000px; ins Nirvana verschieben).
Nei-en! Verstecken, ja, aber doch nicht so! Aus Gründen.
Übrigens braucht man die die Textarea nicht zu verstecken, sondern gar nicht.[1]
Man kopiert den generierten String direkt in die Zwischenablage. ☞ Beispiel
In Browsern, die das nicht unterstützen, gibt man den String aus – und zwar nicht in einem Eingabeelement (was textarea
ja ist), sondern in einem Ausgabeelement: output
.
😷 LLAP
Hallo Gunnar,
Zeugma-Alarm
und wieder was gelernt, vielen Dank.
Die rhetorische Figur kannte ich natürlich, wusste aber bis eben nicht, wie sie heißt. TIL TYL?
Live long and pros healthy,
Martin
@@Der Martin
TYL?
😷 LLAP
Hallo,
TYL?
okay, okay - ich glaub's ja schon.
Live long and pros healthy,
Martin
Hallo Der,
Zeugma-Alarm
und wieder was gelernt, vielen Dank.
dto. Diese Art von Wortspielerei fällt mir oft bei Jürgen von der Lippe auf, hätte aber nie gedacht, dass es dafür eine Bezeichung gibt.
Gruss
Henry
Hallo,
Diese Art von Wortspielerei fällt mir oft bei Jürgen von der Lippe auf,
Heinz Erhardt wäre jetzt mein Paradebeispiel gewesen.
Gruß
Kalk
Hallo Tabellenkalk,
ja, er hatte die Stirn, sie zu runzeln... 😉
Rolf
Hi,
Diese Art von Wortspielerei fällt mir oft bei Jürgen von der Lippe auf
als studierter Germanist sollte er sich mit sowas auskennen. Ja, die deutsche Sprache beherrscht er wirklich ganz hervorragend, das ist mir auch schon aufgefallen.
Heinz Erhardt wäre jetzt mein Paradebeispiel gewesen.
Meins auch, der hatte offenbar großen Spaß an Zeugmata und hat sie gern und oft verwendet.
Live long and pros healthy,
Martin
Hallo,
Es soll vorkommen, dass die Nachkommen mit dem Einkommen ihrer Vorfahren nicht auskommen.
... und daher vollkommen umkommen!
Gruß
Kalk
Hallo Gunnar,
unterm Strich: Ja, Clipboard API ist besser. Ich war gestern abend nur zu doof dafür.
Ansonsten: Du ärgerst mich.
Nei-en! Verstecken, ja, aber doch nicht so! Aus Gründen.
Probierst Du den Mist, den Du da vorschlägst, eigentlich selber aus? Oder geht's Dir nur darum, mir aus Prinzip erstmal zu widersprechen? In letzter Zeit habe ich diesen Eindruck. Der Vorschlag mag für ein <p> sinnvoll sein, aber nicht für eine Textarea.
Das ist also eine für diesen Zweck sehr unpassende Idee, und entscheidende Fehler bleiben. Genau die, gegen die Du immer antrittst: Accessibility und Tastaturbedienung.
Man kann die genannten Probleme allesamt mit HTML-Attributen oder CSS-Eigenschaften lösen, aber eins bleibt: um nicht hineinklicken zu können, muss die textarea off-screen platziert werden, oder hinter ein anderes Element, und damit ist das ganze visuelle Gedönsrath egal.
Ich würde daher diese Methode vertreten: tabindex="-1", aria-hidden="true" und per CSS noch width:1px; left:-10px; position:absolute. Damit sollte das Hauptargument deiner verlinkten Seite beseitigt sein: Performance (die sich nur auf lahmarschigen Geräten bei Animationen zeigen dürfte).
(Edit: -1px in 1px geändert)
Man kopiert den generierten String direkt in die Zwischenablage
Ja, das ist natürlich besser, und das hatte ich auch ausprobiert. Mit Chrome. Und da funktionierte es nicht:
pen.js:21 Async: Could not copy to clipboard: DOMException: The Clipboard API has been blocked because of a Feature Policy applied to the current document. See https://goo.gl/EuHzyv for more details.
Das passiert in jsFiddle und Codepen gleichermaßen. Firefox kennt diese Feature Policy (noch) nicht, darum hast Du das nicht bemerkt, würde ich annehmen.
Das war gestern abend; da war ich wohl zu verschnarcht, einfach mal eine lokale HTML Seite daraus zu machen statt es in einem Fiddle zu probieren. Ohne iframe geht es auch in Chrome - offenbar ist das clipboard-write Feature auf einer ungeframten Seite per Default eingeschaltet (ich hab mal probehalber einen Feature Policy Header gesetzt, und konnte es damit verhindern)
Deshalb bin ich gestern erstmal bei der textarea geblieben (und kein output, weil es die select/setSelectedRange Methoden nur in Eingabeelementen gibt).
Rolf
Hallo Rolf,
lass mich nur auf zwei kleine technische Details eingehen.
[...] und per CSS noch width:-1px; left:-10px; position:absolute.
das ist teilweise ungültig: Die Werte für width oder height dürfen nicht negativ sein.
pen.js:21 Async: Could not copy to clipboard: DOMException: The Clipboard API has been blocked because of a Feature Policy applied to the current document. See https://goo.gl/EuHzyv for more details.
Das passiert in jsFiddle und Codepen gleichermaßen. Firefox kennt diese Feature Policy (noch) nicht, darum hast Du das nicht bemerkt, würde ich annehmen.
Firefox und Chrome verhalten sich offenbar unterschiedlich, wenn das Feature "Clipboard Access" deaktiviert ist. Firefox leugnet dann komplett, dieses Feature überhaupt zu kennen; eine Feature-Abfrage liefert daher ein sinnvolles Ergebnis. Chrome dagegen scheint bei der Feature-Abfrage zu sagen: "Yo, kenn ich", fällt dann aber auf die Schnauze, wenn man es wirklich benutzt.
Live long and pros healthy,
Martin
Hallo Der,
das ist teilweise ungültig: Die Werte für width oder height dürfen nicht negativ sein.
Wohl wahr. Das war ein Typo.
Rolf
@@Rolf B
unterm Strich: Ja, Clipboard API ist besser. Ich war gestern abend nur zu doof dafür.
Ansonsten: Du ärgerst mich.
Mir kommt’s eher so vor, als ärgertest du dich über dich selbst und lässt deinen Ärger an mir aus.
Nei-en! Verstecken, ja, aber doch nicht so! Aus Gründen.
Probierst Du den Mist, den Du da vorschlägst, eigentlich selber aus?
Bezüglich des Versteckens habe ich überhaupt nichts vorgeschlagen. Wenn, dann wäre es selbstverständlich das hidden
-Attribut gewesen: Das Element wird nicht angezeigt, ist nicht im accessibility tree, aber per Script erreichbar.
Mein Vorschlag war ganz einfach: das textarea
-Element gar nicht erst einsetzen, weil nicht notwendig.
Übrigens, was Mist ist: HTML-Elemente zu missbrauchen – z.B. Eingabeelemente zur Ausgabe.
Man kopiert den generierten String direkt in die Zwischenablage
Ja, das ist natürlich besser, und das hatte ich auch ausprobiert. Mit Chrome. Und da funktionierte es nicht:
pen.js:21 Async: Could not copy to clipboard: DOMException: The Clipboard API has been blocked because of a Feature Policy applied to the current document. See https://goo.gl/EuHzyv for more details.
Das passiert in jsFiddle und Codepen gleichermaßen. Firefox kennt diese Feature Policy (noch) nicht, darum hast Du das nicht bemerkt, würde ich annehmen.
Das war gestern abend; da war ich wohl zu verschnarcht, einfach mal eine lokale HTML Seite daraus zu machen statt es in einem Fiddle zu probieren. Ohne iframe geht es auch in Chrome
Ich hab das Beispiel aus den Zwängen von CodePens Iframes befreit – läuft auch in Chromia.
😷 LLAP
Hallo Gunnar,
als ärgertest du dich über dich selbst
Wieso sollte ich? Weil Du an jedem Beitrag von mir was zum kritteln findest? Auf eine Art, die durchaus nervig ist:
Nei-en! Verstecken, ja, aber doch nicht so! Aus Gründen.
Bezüglich des Versteckens habe ich überhaupt nichts vorgeschlagen
Ach so. Und ich dachte, du hättest den Link mit Absicht gesetzt. Dass es nur um die Gründe gegen off-screen Platzierung ging, und nicht um eine bessere Verstecktechnik, war mir nicht so ganz klar.
Abgesehen davon hat sich die Diskussion zweigeteilt: (1) wie versteckt man eine textarea so, dass Joachims Ansatz noch funktioniert und (2) was ist die bessere Idee für Joachim.
Zu (1) funktioniert weder hidden noch display:none, weil dann ein .select() gefolgt vom copy-Command nichts mehr tut. Will man also mit der textarea als Fallback arbeiten, weil das clipboard-Feature aus irgendeinem Grund nicht nutzbar ist, oder weil man keine APIs nutzen will die als "experimentell" gekennzeichnet sind, bleibt nur off-screen Platzierung. Oder hättest Du einen besseren Fallback im Angebot? Außer: Schreiben in ein <output> und den User veranlassen, selbst zu kopieren - das wäre wohl nicht im Sinne der Klickminimierung. Wir reden hier ja von einer sehr speziellen Anwendung.
Solange das Feature vorhanden ist, ist writeText natürlich besser. Das Vorhandensein hat Joachim selbst in der Hand: er muss einen aktuellen Browser verwenden und er darf den Feature Policy Header nicht senden, der das Clipboard deaktiviert.
So, und nun sollten wir mal abwarten, was meine Rückfrage an ihn ergibt, bevor wir den Thread mit Diskussion füllen und der TO kopfschüttelnd wegläuft.
Rolf
@@Rolf B
Wieso sollte ich? Weil Du an jedem Beitrag von mir was zum kritteln findest?
Liegt das nun an mir oder an deinen Beiträgen? 🤔
Auf eine Art, die durchaus nervig ist:
Nei-en! Verstecken, ja, aber doch nicht so! Aus Gründen.
Der Artikel von Zeldman ist fast 9 Jahre alt und wurde hier unzählige Male verlinkt. Der kann kaum an dir vorbeigegangen sein.
Mag mag mir nachsehen, etwas genervt zu sein, wenn man hier immer wieder dasselbe erzählen muss. Immer wieder dasselbe. Immer wieder …
Dass es nur um die Gründe gegen off-screen Platzierung ging, und nicht um eine bessere Verstecktechnik, war mir nicht so ganz klar.
Ich schrieb „doch nicht so“. (Hätte es vielleicht fett hervorheben sollen?) Ich schrieb nichts von „sondern anders“.
Abgesehen davon hat sich die Diskussion zweigeteilt: (1) wie versteckt man eine textarea so, dass Joachims Ansatz noch funktioniert
Ich hatte nie die Absicht, darüber zu diskutieren, weil das mit
(2) was ist die bessere Idee für Joachim.
hinfällig ist.
Deswegen hatte ich auch das hidden
-Attribut als bessere Verstecktechnik hier nicht getestet. Wozu auch?
😷 LLAP
Hallo Gunnar,
Übrigens braucht man die die Textarea nicht zu verstecken, sondern gar nicht.
in Anlehnung daran:
Was hat der Soldat unterm Bett?
Zu putzen!
Kein Zeugma nach der eigentlichen Definition, aber eine ähnliche Konstruktion.
Hat diese sprachliche Wendung auch eine besondere Bezeichnung? Kennt sich jemand aus?
Live long and pros healthy,
Martin
Hi Rolf,
ich beantworte mal kurz deine Fragen:
Bsp: ich gebrauche Mat1, Mat2; Mat5; Mat7, aber wenn ich erst die 1, dann die 7, 5 und 2 anklicke spielt keine Rolle
Die Textarea würde ich gern behalten, falls ich evtl noch was ergänzen muss, bevor ich den Copy-Button drücke
Was für eine Info brächtest du noch?
Gruß Joachim
Hallo Joachim,
wenn es wirklich nötig ist, den generierten Text nachzubearbeiten, dann mach die Textarea.
Aber wenn Du nur eine Notiz am Ende brauchst, sollte die Textarea nur dafür sein.
Einen "Verklicker" rauslöschen brauchst Du ja nicht, dafür machst Du einfach die Checkbox wieder aus.
Verwendest Du einen modernen Browser? Dann solltest Du Dir Gunnars Vorschlag mit dem Clipboard-API wirklich zu Herzen nehmen.
Rolf
Hallo Rolf,
ja ich werde mich mal die Tage mit der Checkbox auseinandersetzen und auch mal gucken was es mit der Clipboard-API zu tun hat.
Wir wohl doch anders als gedacht und ist definitiv schwieriger als vermutet.
Vielen Dank für die Vorschläge.
Ich halte euch auf dem Laufenden.
Gruß
Joachim
@@Joachim
ja ich werde mich mal die Tage mit der Checkbox auseinandersetzen und auch mal gucken was es mit der Clipboard-API zu tun hat.
Wir wohl doch anders als gedacht und ist definitiv schwieriger als vermutet.
Das mit dem Clipboard-API kannst du ja genauso aus meinem Beispiel übernehmen.
Nur die Zeilen 6–14 (das Zusammenbauen des Strings) werden bei dir anders sein: Da musst du halt deine Checkboxen, Radiobuttons(?) und Texteingabefeld auswerten.
Nur dass bei dir weder der String noch das output
-Element workdays
heißen sollte.
😷 LLAP
@@Gunnar Bittersmann
Das mit dem Clipboard-API kannst du ja genauso aus meinem Beispiel übernehmen.
Nur die Zeilen 6–14 (das Zusammenbauen des Strings) werden bei dir anders sein: Da musst du halt deine Checkboxen, Radiobuttons(?) und Texteingabefeld auswerten.
Kann dann so aussehen:
for (let checkbox of form.core) {
if (checkbox.checked) {
awayTeam += `${checkbox.value}\n`;
}
}
Schleife über alle Checkboxen, die in meinem Beispiel alle name="core"
tragen, also in form.core
gesammelt sind. Für gesetzte Checkboxen wird deren Wert an den String angehängt.
Noch den Wert des Freifeldes (sofern da was eingegeben wurde) dazu – fertig.
Nur dass bei dir weder der String noch das
output
-Elementworkdays
heißen sollte.
… und auch nicht awayTeam
.
😷 LLAP
Hallo Gunnar,
Disclaimer: This doesn’t work in Chromia (Chome, Edge, …)
Der Browser, dessen Name nicht genannt werden darf 😉? Oder macht deine Tastatur auch Mätzchen bei gewissen Tasten? Bei mir war der Punkt defekt, bis ich die Kappe abgemacht und Produktionsmüll entsorgt habe.
Abhilfe gegen einen Error schafft:
if (navigator.clipboard &&
document.featurePolicy.allowsFeature("clipboard-write")) {
...
}
Dann greift zumindest der Fallback mit dem output-Element. Wobei ich gelesen habe, dass das auch nicht in jeder Chrome-Version funktioniert hat, aber im aktuellen Chrome 87 geht es.
Rolf
@@Rolf B
wenn es wirklich nötig ist, den generierten Text nachzubearbeiten, dann mach die Textarea.
Aber wenn Du nur eine Notiz am Ende brauchst, sollte die Textarea nur dafür sein.
Gute Idee.
Und je nach benötigter Länge für die Notiz tut’s dann vielleicht auch ein einzeiliges input
anstatt der mehrzeiligen textarea
.
😷 LLAP
Hallo nochmal an alle,
danke dafür, dass ihr euch damit auseinandersetzt. Habe auch so einiges dazugelernt 😀
Ich habe gesehen, da stand noch der Browser im Raum - es ist Edge und Firefox installiert. Zugang zum Internet gibt es keinen - nur Intranet.
Wie gesagt es muss nichts hochkomplexes sein, auch keine besondere Formatierung. Reiner Text reicht. Nur je nachdem was es für ein Ablauf ist, werden verschiedene und unterschiedlich viele Materialien gebraucht. Dabei spielt die Menge und die Häufigkeit keine Rolle.
Ach und es wäre gut, wenn ich die LOT-Nr. neu eintrage/warte, dass es nicht zu arg verstreut im Quelltext verstreut liegt 😁 Deswegen habe ich ja auch alle als Variablen deklariert. So sind sie alle am gleichen Ort.
Gruß Joachim
Hallo Joachim,
wenn Du auf zentrale Wartung Wert legst, dann solltest Du vielleicht noch etwas länger nachdenken, bevor Du loslegst. Du hast - wie es scheint - für jedes Material den Text, der zum Button / zur Checkbox gehört, und du hast den Text, der in der Doku erscheinen soll. Diese Texte sind nicht die Gleichen, wenn ich mir dein Beispiel zu Anfang anschaue.
Im schlimmsten Fall hast Du pro Checkbox 3 Werte: Eine ID, eine Checkbox-Beschriftung und einen Dokumentationseintrag. Wenn ich dein Eingangsbeispiel anschaue, wäre eine solche Dreiergruppe zum Beispiel "afa2", "flow 2" und "flow a2 lot: 12345". Oder "afa35", "flow a3,5 lot: 34567".
So etwas kann man in einem Objekt speichern:
const materialListe = {
"afa2": { label: "flow 2", text: "flow a2, lot: 12345" },
"afa3": { label: "flow 3", text: "flow a3, lot: 23456" },
"afa35": { label: "flow 3,5", text: "flow a3,5, lot: 34567" },
// und so weiter
};
Wenn Du deine Checkboxen (oder Radiobuttons) nach einem einheitlichen Schema im HTML aufbaust, zum Beispiel so:
<label><input type="checkbox" name="afa2"></label>
<label><input type="radio" name="afa47"></label>
dann kann man dafür sorgen, dass die Anzeigetexte aus dem Materialienobjekt automagisch eingesteuert werden. Dazu entfernt man die Texte aus dem HTML und setzt einen leeren span an ihre Stelle:
<label><input type="checkbox" name="afa2"><span></span></label>
<label><input type="radio" name="afa47"><span></span></label>
Man könnte den Span auch weglassen und im JavaScript Text anhängen. Ein Span schafft aber einen klarer definierten Platzhalter für den Text.
Mit einer Prise JavaScript setzt man die Texte ein:
for (let materialElement of materialWähler()) {
materialElement.element
.closest("label")
.querySelector("span").textContent = materialElement.material.label;
}
function* materialWähler(checkedOnly = false) {
let selektor = "label > input[name]";
if (checkedOnly)
selektor += ":checked";
for (let element of document.querySelectorAll(selektor)) {
let material;
if (element.type == "checkbox")
material = materialListe[element.name];
else if (element.type == "radio")
material = materialListe[element.value];
if (material)
yield { element, material };
}
}
materialWähler ist als function*
definiert, das ist eine Generator-Funktion. Ein Generator kann in einer Schleife eine Liste von Werten zurückgeben, die zum Beispiel in einer (for...of) Schleife verarbeitet werden können. Generatoren sind ungemein praktisch, um Erzeugung und Verarbeitung einer Liste von Werten sauber zu trennen, ohne die Liste dafür zwischenspeichern zu müssen. Mehr dazu im verlinkten Wiki-Artikel.
materialWähler
baut zunächst einen CSS Selektor für die gesuchten Input-Elemente auf. Das ist zunächst "label > input[name]", also alle input-Elemente mit einem name-Attribut, die ein label als Elternelement haben. Wird der Funktion true
übergeben, wird noch ein :checked hinzugefügt, d.h. nur die Checkboxen oder Radiobuttons ausgewählt, die angehakt sind. Dadurch kannst Du die Funktion wahlweise für alle Inputs oder nur für die gerade ausgewählten Inputs verwenden.
Anhand des erzeugten CSS Selectors sucht materialWähler
mittels querySelectorAll
die Input-Elemente heraus. Die Zuordnung zum Material unterscheidet sich bei Checkbox und Radiobuttons, weil in einer Gruppe Radiobuttons alle inputs den gleichen Namen haben. Darum wird für Checkboxen über name gesucht und für Radiobuttons über value. Ist es keins von beiden, bleibt material leer. Wurde ein Material zum input Element gefunden, wird ein kleines Objekt aufgebaut, das Element und Material enthält, und per yield bereitgestellt.
Die for...of Schleife im Hauptprogramm durchläuft die vom Generator bereitgestellten Ergebnisse. Jeder Treffer ist ein Pärchen aus Element und Materialdefinition, und nun muss nur noch das span-Element gesucht werden und der Label-Text eingetragen werden. Dafür wird zunächst mit closest zum Label navigiert und von dort mit querySelector zum span.
Später, wenn der "Dokumentation generieren" Button geklickt wird, rufst Du materialWähler(true)
auf, gehst die Ergebnisse ebenfalls mit for...of durch und baust die Inhalte der text-Eingeschaft aus der Materialliste zusammen.
Hier das Ganze in einem Fiddle: https://jsfiddle.net/Rolf_b/qb5dtysc/
Rolf