Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a cross-browser sub document with iframe or shadow dom?

I want to create a totally encapsulated sub-document in JavaScript, with its own <head>, <body>, styles, html, and js. Basically a shadow dom, or an iframe, but without an src attribute.

Though I love the idea of shadow dom, its support is very low, and thus is not ready for prime time.

So I have been working on creating an iframe, but have been hitting various road-blocks along the way. Here is a jsFiddle demonstrating my various attempts.

The iframe cannot exist in the dom. This part is critical. To clarify, it is okay if it momentarily exists in the dom, but it must be able to be extracted and exist only in JS.

$('body').append('<iframe id="iframeGenerator" />');
var iframe3 = $('#iframeGenerator');
var iframe3Contents = iframe3.contents();
$('#iframeGenerator').remove();
var head = iframe3.contents().find('head');

sweet, we have the head

console.log(head.length);

but what do the contents look like?

console.log(iframe3Contents.get(0));

It is a document, but not inside of an element so lets try to put it in the dom or inside of another element? both of the following attempts don't work because the selector has no context or something ...

$('body').append(iframe3Contents);
var generatedIframe = $('<iframe />').append(iframe3Contents);

I would love to be able to create the iframe / subdocuemnt without appending anything to the dom... but if I must, I would still like to be able to subsequently remove it from the dom and manage it further in js.

I have this little function, which doesn't work, but illustrates the kind of iframe or subdocument generator I would like to create

var iframeHtml;
giveMeIframe = function() {
  var iframeContents;
  if (iframeHtml) {
    return iframeHtml;
  } else {
    $('body').append('<iframe id="iframeGenerator" style="display: none" />');
    iframeContents = $('#iframeGenerator').contents();
    iframeHtml = $('<iframe />');
    iframeHtml.append(iframeContents);
    $('#iframeGenerator').remove();
    return iframeHtml;
  }
}
like image 519
dezman Avatar asked Feb 12 '14 20:02

dezman


People also ask

Is iframe a shadow DOM?

While iframes were the only solution for a long time, these days we have the shadow DOM. If you need a basic explainer, I've written about web components in the past. Part of the web component spec is the shadow DOM. The shadow DOM lets us define a “shadow root”.

How do I get shadow DOM on Google Chrome?

To enable shadow dom in chrome browser open Developer tools by Ctrl+Shift+I. Click on 3 vertical dots on the top right corner of dev tools before close button. Now click on settings there you will find “Show user agent shadow DOM” checkbox under the Elements section in General Tab.

What is shadow DOM example?

Shadow DOM allows hidden DOM trees to be attached to elements in the regular DOM tree — this shadow DOM tree starts with a shadow root, underneath which you can attach any element, in the same way as the normal DOM.

How do I get shadow DOM in JavaScript?

We can only access the shadow DOM by the reference returned by attachShadow (and probably hidden inside a class). Browser-native shadow trees, such as <input type="range"> , are closed. There's no way to access them.


1 Answers

To access info from the frame (or write to the frame), it must be in the DOM. It can be hidden, but it still must live in the frames object. JQuery is accessing the iFrame through the frames object and when removed from the dom, it's removed from the frames object

For future reference to anyone stumbling across this question, you can get the encapsulation like so:

$('#iframeGenerator2').contents().find('html').html(frame2HTML);

Here's an example: http://jsfiddle.net/yP34y/4/

In the jsfiddle example, notice everything only works after it's been added to the DOM.

like image 154
Paul Way Avatar answered Oct 12 '22 22:10

Paul Way