Injecting html dom inside iframe's document and/or shadow-root - javascript

I am injecting iframe onto the webpage using javascript (using chrome extension). Using javascript, I am creating iframe and I can access my html's url, so I though I can fetch the DOM using $.get
var elt = document.createElement('iframe');
elt.id = 'my_iframe';
$.get(chrome.extension.getURL('views/test.html'), function(doc) {
var container = document.querySelector('#my_iframe');
console.log(container.documentContent); // can access
console.log(container.shadowRoot); // can't access
// ideally:
container.shadowRoot($(doc));
container.contentDocument($(doc));
});
document.getElementsByTagName('body')[0].appendChild(elt);
How can I inject my 'text.html' inside the #shadow-root?
The reason is that, when I use elt.src = url, it doesn't wrap the html content inside #document or #shadow-root, and this results in a bug - (blurry content in iframe when not wrapped in #document or #shadow-root - bug report)

If you are just changing the contents of an iframe, you can do it by:
const iframe = document.querySelector('#myIframe')
iframe.outerHTML = '<iframe></iframe>' // clears the iframe
iframe.contentDocument.open()
iframe.contentDocument.write(yourHTMLText)
iframe.contentDocument.close()

Related

Why cant I access iframe's document with src or srcdoc attributes set?

<html>
<body>
<!-- <iframe id="iff" srcdoc="<div>ok</div>"></iframe> -->
<iframe id="iff" src="data:text/html;charset=utf-8,%3Cdiv%3Eok%3C%2Fdiv%3E"></iframe>
<script>
console.log(document.getElementById('iff').contentWindow.document)
</script>
</body>
</html>
I set srcdoc (tried src also) of <iframe>, but cannot access the real document of the iframe (tried iframeElement.contentDocument also). Chrome outputs (also tried Firefox):
I see in Get IFrame's document, from JavaScript in main document that I cannot get the document of a cross-domain iframe, and also learned from Which is the difference between srcdoc="..." and src="data:text/html,..." in an <iframe>? that src and srcdoc behaves different about cross-domain behavior. But I tried both, none works.
2. When I append a child to the document body of an iframe (with src attribute set), the DOM updates but it doesnt show on screen.
Try something like:
window.frames['iff'].document.myvar;
This can be useful if you look for the iframe with the url:
var x=getIframeID("cool.php");
x.contentWindow.callafunction();
function getIframeID(iframeurl) {
var iFs = top.document.getElementsByTagName('iframe');
var x, i = iFs.length;
while ( i-- ){
x = iFs[i];
if(iframeurl.indexOf(x.src)>=0) return (x.id);
if (x.src == iframeurl) return (x.id);
}
return("");
}

Determine when iFrame content is rendered after IFrame has already loaded

Using javascript I'm creating an iframe, adding it to the parent DOM and then writing HTML to it via iFrameEl.contentWindow.document.write()
I need to determine when all content in the iFrame has been rendered after iFrameEl.contentWindow.document.closed() has been called.
The iFrame's onload event appears to be called when the iframe is added to the DOM originally, before I can write to it and I need to add it to the DOM in order to get access to the iFrame's contentWindow.document, so catch 22.
In Chrome, as an alternative I have used the srcdoc attribute to add all the content I need to the iframe and the add the iframe to the dom and wait for the onload event however srcdoc is not supported in IE
var iFrameHTML = '<!DOCTYPE html><html><head>';
iFrameHTML = iFrameHTML + '</head><body>' + htmlIncludingImagesEtc + '</body></html>';
iFrameEl.srcdoc = iFrameHTML;
myDiv.append(iFrame);
iFrameEl.onload = function(){
//proceed
}
I know the iFrame's src attribute can also be used, but the limitation on Data URI characters prevents me from using that approach
I know there are many similar questions on here, but I could not find any that matches my requirements.
I need to dynamically create an iFrame, add content to it and determine when all the content has been rendered, is there some obvious way to achieve this, or will it require MutationObservers etc.?
Check out DOMFrameContentLoaded. It is an event that will be fired when the content in the frame is loaded and parsed.
Late answer, but it may help someone...I found that even after the iframe was added to the DOM, if I added the links to style sheets from the head of the parent DOM to the iframe as a String as follows, it meant that the load event occurred
iFrame$.on('load',function(){
//iFrame loaded
});
var headHTML = '<head>';
$('head link').each(function(index, link) {
headHTML = headHTML + link.outerHTML;
});
headHTML = headHTML + '</head>';
iFrameDoc.open();
iFrameDoc.write("<!DOCTYPE html>");
iFrameDoc.write("<html>");
iFrameDoc.write(headHTML);
iFrameDoc.write("</body>");
iFrameDoc.write("</html>");
iFrameDoc.close();

How can I scroll content of <webview> tag from JavaScript?

atom-shell: https://github.com/atom/atom-shell
version: v0.20.2
I am using <webview> tag to embed a page. <webview> tag has shadow-root which has one tag, <object id="browser-plugin-1 ...>. So I tried to set scrollTop value for this tag like this.
var webView = document.getElementById('webview tag id');
var elm = webView.shadowRoot.firstChild; // elm is object tag
console.log(elm.scrollTop); // 0
elm.scrollTop = 100;
console.log(elm.scrollTop); // 0
But nothing happend...
Is it possible to control <webview> tag scroll position from outside?
Yes, do this instead:
var webView = document.getElementById('webview tag id');
webView.executeJavaScript("document.querySelector('body:first-child').scrollTop=100");
It's possible to execute any kind of javascript via the WebView.executeJavaScript(code) function which will evaluate the code inside the WebView.
To access your element you would first have to wait for the WebView to load, and then execute the javascript.
var webView = document.getElementById('webView');
webView.addEventListener('did-finish-load', scrollElement );
function scrollElement(){
var code = "var elm = document.querySelector('body:first-child'); elm.scrollTop = 100;";
webView.executeJavaScript(code);
}
Note: Haven't tested this code, it may have syntax errors.
Source (AtomShell's WebView tag documentation)

Removing iframe from page

I am creating an iframe dynamically for submmiting a form,after submitting i need to remove the iframe form the page.I removed itas follows but it is not removed,
function remove(){
var frame = document.getElementById("upload_iframe"),
var frameDoc = frame.contentDocument || frame.contentWindow.document;
frameDoc.removeChild(frameDoc.documentElement);
}
How to remove the ifarme form the form completely.
Thanks
Frame has 2 behaviors: frame as document element (like div or another DOM element) and frame as window element (like global window object). So if you want to remove iframe from DOM tree you have to work with iframe like with DOM element
function remove(){
var frame = document.getElementById("upload_iframe");
frame.parentNode.removeChild(frame);
}
A way I've been doing it (since I have a large amount of iframes) is using jQuery,
$('iframe').remove()
or in the case of only one iframe you can remove it using its ID, still with jQuery
$('#iframeID').remove()

Get element from within an iFrame

How do you get a <div> from within an <iframe>?
var iframe = document.getElementById('iframeId');
var innerDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
You could more simply write:
var iframe = document.getElementById('iframeId');
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
and the first valid inner doc will be returned.
Once you get the inner doc, you can just access its internals the same way as you would access any element on your current page. (innerDoc.getElementById...etc.)
IMPORTANT: Make sure that the iframe is on the same domain, otherwise you can't get access to its internals. That would be cross-site scripting. Reference:
MDN: <iframe> Scripting
MDN: Same-Origin Policy: Cross-Origin Script API Access
Do not forget to access iframe after it is loaded. Old but reliable way without jQuery:
<iframe src="samedomain.com/page.htm" id="iframe" onload="access()"></iframe>
<script>
function access() {
var iframe = document.getElementById("iframe");
var innerDoc = iframe.contentDocument || iframe.contentWindow.document;
console.log(innerDoc.body);
}
</script>
Above answers gave good solutions using Javscript.
Here is a simple jQuery solution:
$('#iframeId').contents().find('div')
The trick here is jQuery's .contents() method, unlike .children() which can only get HTML elements, .contents() can get both text nodes and HTML elements. That's why one can get document contents of an iframe by using it.
Further reading about jQuery .contents(): .contents()
Note that the iframe and page have to be on the same domain.
window.parent.document.getElementById("framekit").contentWindow.CallYourFunction('pass your value')
CallYourFunction() is function inside page and that function action on it
None of the other answers were working for me. I ended up creating a function within my iframe that returns the object I was looking for:
function getElementWithinIframe() {
return document.getElementById('copy-sheet-form');
}
Then you call that function like so to retrieve the element:
var el = document.getElementById("iframeId").contentWindow.functionNameToCall();
If iframe is not in the same domain such that you cannot get access to its internals from the parent but you can modify the source code of the iframe then you can modify the page displayed by the iframe to send messages to the parent window, which allows you to share information between the pages. Some sources:
https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
Html5 - Cross Browser Iframe postmessage - child to parent?
cross site iframe postMessage from child to parent
You can use this function to query for any element on the page, regardless of if it is nested inside of an iframe (or many iframes):
function querySelectorAllInIframes(selector) {
let elements = [];
const recurse = (contentWindow = window) => {
const iframes = contentWindow.document.body.querySelectorAll('iframe');
iframes.forEach(iframe => recurse(iframe.contentWindow));
elements = elements.concat(contentWindow.document.body.querySelectorAll(selector));
}
recurse();
return elements;
};
querySelectorAllInIframes('#elementToBeFound');
Note: Keep in mind that each of the iframes on the page will need to be of the same-origin, or this function will throw an error.
Below code will help you to find out iframe data.
let iframe = document.getElementById('frameId');
let innerDoc = iframe.contentDocument || iframe.contentWindow.document;

Categories