PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : String zu IFrame hinzufügen



Barny
10.08.2017, 12:03
Hi, Leute!

Ich hoffe ihr könnt mir ein bisschen helfen, denn ich weiß solangsam nicht mehr was ich googeln soll... Ich entwickel eigentlich garkein Javascript und habe in der Vergangenheit mich immer schön weit distanzierne können...bis jetzt... also seid nicht zu hart mit mir. :D

Die Ausgangssituation:
Ich habe den Auftrag bekommen eine Firefox-Webextension zu schreiben, welche XML aus einem IFrame liest und nach gewissen Kriterien parst (nach welchen Kriterien ist nicht relevant für mein Problem, da das funktioniert). Das gelingt mir bereits erfolgreich mit Hilfe von:

function getIFrame() { // <-- Gibt den Inhalt des IFrames als String zurück
var list = document.getElementsByTagName("iframe");
for (var i = 0; i < list.length; i++) {
if(findResultUrl(list[i].src) !== false) {
var toReturn = list[i].contentWindow.document.body.innerText;
return unescape(toReturn);
}
}
}
Und anschließend:

function convertToXmlObj(str) {
if(window.DOMParser) {
parser = new DOMParser();
return parser.parseFromString(str, "text/xml");
}else {
return false;
}
}
Dieses Objekt baue ich mir dann so um wie ich es brauche und schmeiß mein Ergebnis wieder in einen String:


// Oberhalb baue ich mir mein Ergebnis
var oSerializer = new XMLSerializer();
return oSerializer.serializeToString(iframe_xml);
Der Ergebnisstring lässt sich auch mit

console.log
anzeigen und ist korrekt. Soweit so gut...

Mein Problem:
Ich möchte unter dem bestehenden IFrame (da wo ich die Daten her habe) ein neues IFrame mit exakt den gleichen Werten (Höhe, Breite, etc.) einsetzen und mein Ergebnis dort anzeigen lassen. Ich erstelle einen Titel für das IFrame und das Iframe selber mit:

// Create Text
var p2 = document.createElement('p');
p2.innerHTML = 'Filterkriterien';
var temp = document.getElementById("api_call_url");
temp.parentNode.insertBefore(p2, temp);

// Create Iframe
var ifrm = document.createElement("iframe");
ifrm.style.width = "100%";
ifrm.style.height = "400px";
ifrm.id = "TOFILL";
temp.parentNode.insertBefore(ifrm, temp);

document.getElementById('TOFILL').src = "data:text/xml;charset=utf-8," + output;
console.log("Fertig");
Es wird mir der Titel (<p>) angezeigt und das erstellte IFrame "TOFILL", jedoch wird es nicht befüllt. Stattdessen erhalte ich in der Konsole nachfolgende Fehlermeldung:

Content Security Policy: Die Einstellungen der Seite haben das Laden einer Ressource auf data:text/xml;charset=utf-8,<?xml%20vers... blockiert ("default-src 'unsafe-inline' [...]


Nach ein bisschen googeln bin ich noch auf diese Möglichkeit gestoßen das IFrame zu befüllen:


//document.getElementById('TOFILL').src = "data:text/xml;charset=utf-8," + output;
var TOFILL = document.getElementById('TOFILL').contentWindow.do cument;
TOFILL.open();
TOFILL.write(escape(output));
TOFILL.close();

Dies brachte keinen Fehler mehr in der Konsole auf, jedoch wurde das Iframe nicht befüllt.

Meine Frage(n):
Wieso zum Fick ( :D ) kann ich alle möglichen Elemente erzeugen und befüllen, nur kein IFrame?! Mache ich da grundlegend etwas falsch? Cross-Origin oder Ähnliches kann hier doch garkein Thema sein, da ich mir die Daten von der Seite hole und auf der Seite anders wieder einfügen möchte. Oder täusche ich mich da? Gibt es hierfür Workarounds? Vielleicht andere Elemente als ein IFrame wo ich meine Daten gut darstellen kann?
Ich hoffe ihr könnt mir helfen... sitz da jetzt schon nen paar Tage dran... Ich freue mich über jedes bisschen Input was ihr mir geben könnt.

Viele Grüße,

Barny

//EDIT:
Okay.. Ich bin nen kleinen Schritt weiter. :D Erstelle ich einen neuen Div-Container und fülle diesen dann mit meinem String, dann wird mir auch ein Ergebnis angezeigt. So befülle ich den Div-Container:

var div = document.createElement("div");
div.style.width = "100%";
div.style.height = "400px";
div.style.border = "solid 1px"
div.style.cssText = "overflow-y: scroll;max-height: 400px;min-height: 400px;border: solid 1px black;border-right: solid 1px lightgray;border-bottom: solid 1px lightgray";
div.id = "TOFILL"
temp.parentNode.insertBefore(div, temp);

var temp2 = document.createTextNode(output);
div.appendChild(temp2);
Wobei auch hier wieder "output" mein Ergebnisstring ist. Das funktioniert gut, allerdings wird mir der String natürlich als 1-Zeiler in den Div-Container geknallt und immer am "Zeilenende" des Containers umgebrochen. Gibt´s ne Möglichkeit diesen ordentlich zu formatieren? Habt ihr da Erfahrungen gemacht? Gefunden habe ich sowas:


var oSerializer = new XMLSerializer();
var sPrettyXML = XML(oSerializer.serializeToString(iframe_xml)).toX MLString();

Hier erhalte ich jedoch garkeine Rückgabe mehr wenn ich "sPrettyXML" zurückgeben lasse. Solangsam kack ich hier richtig ab.^^
Solangsam komme ich auch in die Phase wo ich alles mögliche einfach nur noch durchprobiere...

Benu
11.08.2017, 08:15
Also, iFrames kannst du aufgrund der Content Security Policy eigentlich kaum bist gar nicht bearbeiten. Ein iFrame ist ein eingebetteter Frame, sprich ein Browser-Fenster im Fenster. Das war natürlich nicht immer so, aber es gibt zB. Zahlungssysteme die als iFrame das Kreditkarten-Formular haben und dass man da nicht einfach mitlesen kann, gibt es diese Restriktionen. So zumindest in der Theorie.
Zur Anzeige solltest du aber sowieso kein iFrame verwenden. Entweder wie du es gemacht hast ein Div, oder ein semantischeres HTML5-Element (nicht notwendig).

Tipp am Rande: Verwende doch statt insertBefore, appendChild. Dann hast du es unter dem iFrame, wie du es wolltest.

Zu deinem Problem: Weiß nicht ganz was du formatieren willst. Du könntest Zeilenumbrüche mit BR ersetzen.


str = str.replace(/(?:\r\n|\r|\n)/g, '<br />');

Ansonsten könntest du noch mittels den CSS-Eigenschaften word-break (https://www.w3schools.com/cssref/css3_pr_word-break.asp) und word-wrap (https://www.w3schools.com/cssref/css3_pr_word-wrap.asp) versuchen auf dein gewünschtes Resultat zu kommen.



Wenn du tatsächlich XML formatieren willst, dann nimm ein Plugin wie http://www.eslinstructor.net/vkbeautify/.

Leange
11.08.2017, 09:20
Hi

https://gist.github.com/sente/1083506

Barny
11.08.2017, 12:02
Hiho!

Vielen Dank für die Hilfe!

Ich konnte das Problem jetzt mit beiden von euch gegebenen Quellen lösen. Sieht nun wie folgt aus und tut was es soll:

// Format XML
output = vkbeautify.xml(output); // <-- Thx an Benu
output = output.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/ /g, '&nbsp;').replace(/\n/g,'<br />'); // <-- Thx an Leange
var div = document.createElement("div");
div.innerHTML = output;
div.style.width = "100%";
div.style.height = "400px";
div.style.cssText = "overflow: auto;height: 400px; border: solid 1px black;border-right: solid 1px lightgray;border-bottom: solid 1px lightgray; white-space: nowrap;";
div.style.fontSize = "13px";
div.id = "XMLContainer"

Es wurde durch die vielen missglückten Kombinationen an Code irgendwann einfach zu undurchsichtig. Nochmal richtig strukturiert und vorher drüber nachdenken hat dann zur Lösung geführt. :)

Nochmals Danke für die Hilfe! ;)

Hierzu noch eine Anmerkung:

Also, iFrames kannst du aufgrund der Content Security Policy eigentlich kaum bist gar nicht bearbeiten. Ein iFrame ist ein eingebetteter Frame, sprich ein Browser-Fenster im Fenster. Das war natürlich nicht immer so, aber es gibt zB. Zahlungssysteme die als iFrame das Kreditkarten-Formular haben und dass man da nicht einfach mitlesen kann, gibt es diese Restriktionen. So zumindest in der Theorie.
Die originalen Daten lese ich ja aus einem IFrame. Daher kam mir auch der Gedanke die bearbeiteten Daten wieder ein einem solchem darzustellen. Dies wurde mir aber wie bereits geschrieben unterbunden. Lesen durfte ich jedoch das IFrame.


Tipp am Rande: Verwende doch statt insertBefore, appendChild. Dann hast du es unter dem iFrame, wie du es wolltest.
Danke für den Tipp! Tut aber im mom genau das was es soll, da sich das "insertBefore" an einem Element orientiert, welches am Ende der Page zu finden ist. Von daher passt es so. :)

Viele Grüße,

Barny