The history navigation analogy is a good one: pages presumably already
have to handle the pageshow event to deal with being revived from the
history, and the browser already needs to know how to fire that event.
Why not reuse those mechanisms? A strawman claim: Nothing may be
changing from the perspective of the iframe, but it certainly is
changing from the perspective of the container or the user: detaching an
iframe from a page is like navigating a browsing context away from a
page, putting it into hibernation until it's reattached to an active
document/browsing context. What subtle or important facet of the web am
I missing that breaks this analogy? (It wouldn't surprise me if I missed
something obvious, either... :)
Another reason to consider suspending detached iframes: suppose that in
the chat window example below, the iframe wasn't just a same-origin
place to store global state, but also had its own UI, with callbacks and
event handlers and whatnot. If, during the interim while the iframe was
being detached, adopted and reattached, that frame executed a timer that
popped up a modal alert or prompt to the user, how would the user
reasonably know where that alert came from? And what document(s?)
should be paused while the alert is shown?
To stretch an analogy a bit: detaching an iframe, saving a reference to
it, and then attaching it/adopting it later to another document is a bit
like using DVR to record the rest of a TV show to watch later: I should
get the same show, paused wherever I left off watching it, on whatever
TV is convenient for me to watch it on. I shouldn't have to immediately
start watching on the second screen in order to preserve state, and it
shouldn't keep playing while I move from one screen to the other :)
Regarding XHR and such -- I guess what I'm suggesting is suspending the
event loop, but not necessarily suspending asynch processes. So XHR can
continue to queue tasks; media can continue to buffer; resources can
continue to load. When the document is reattached, it finds itself with
a backlog of events to handle, which is the exact same situation as a
very bursty network connection :)
On 8/24/2010 3:42 PM, Dirk Pranke wrote:
On a related note, the behavior of onUnload in this situation is quite
unclear. Should onUnload() fire if an iframe is detached from the DOM?
Indeed -- it seems to me from the spec that it should not fire, until
(following the snippet Dmitry quoted below) the last reference to the
iframe is dropped and therefore the browsing context can be discarded.
I'm not sure the adoptNode workaround mentioned in the bugs below is a
full fix. It gets us from behavior #1 to behavior #3, but doesn't
consider #2 as a possibility. Certainly some loose ends to think about...
~ben
On 8/24/2010 3:27 PM, Dmitry Titov wrote:
Indeed, in WebKit you normally see #1 (iframe unloads). We have added
the ability to move 'live' iframe, as Adam mentions, potentially
across documents, while keeping it completely alive, with XHRs
loading, events firing etc (aka 'magic iframe' feature). One would
need to use adoptNode() API to do that, something like:
var iframe = document.getElementById("test");
other_document.adoptNode(iframe);
other_document.getElementById("newParent").attachChild(iframe);
WebKit has a bug (https://bugs.webkit.org/show_bug.cgi?id=13574) to
enable moving iframes w/o reloading. FF has a bug on that as well
(https://bugzilla.mozilla.org/show_bug.cgi?id=254144) but it's hard to
say when exactly those will be fixed. I hope to fix WebKit issue at
some point.
While discussing 'magic iframe', Ian Hickson pointed out that nothing
in the spec actually mandates discarding the live document inside
iframe simply because it's iframe element is connected/disconnected to
DOM of the parent document. Here is a note from the HTML5 spec about
that:
Removing
<http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#remove-an-element-from-a-document> an
|iframe
<http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#the-iframe-element>| from
a |Document
<http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#document>| does
not cause its browsing context
<http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#browsing-context> to
be discarded. Indeed, an |iframe
<http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#the-iframe-element>|'s
browsing context
<http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#browsing-context> can
survive its original parent |Document
<http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#document>| if
its |iframe
<http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#the-iframe-element>| is
moved to another |Document
<http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#document>|.
So it seems the right behavior is to keep the content alive. It's not
clear why the events would not fire during DOM operations though.
Perhaps they should, since nothing is changing from the perspective of
the document loaded into iframe - for example, XHR probably should
continue loading content if it was doing so before iframe was
disconnected from its parent node. Doing some suspension (as for
example is done when a page goes into back-forward cache?) would be
way more complex mechanism to have, with necessary events on
pause/unpause so the live document could re-start async operations
correctly.
Dmitry
On Tue, Aug 24, 2010 at 1:38 PM, Adam Barth <[email protected]
<mailto:[email protected]>> wrote:
This seems related to the "magic iframe" concept that was recently
added in WebKit. Basically, magic iframe lets you move an iframe from
one document to another without blowing away the JavaScript/DOM state
of the iframe. The way this works is that the iframe remains "alive"
until the browser returns to the main event loop. If a living iframe
gets added to a document, then it keeps all it's state. This feature
is useful for sites like Gmail that have chat windows that can be
opened from the main document. If the user closes the main document,
the chat windows can adopt some iframe that keeps the proper state.
Adam
On Tue, Aug 24, 2010 at 1:30 PM, Ben Lerner
<[email protected] <mailto:[email protected]>> wrote:
> There seems to be a bit of disagreement among browsers about
how event
> loops and iframes interact when an iframe is removed and then
reinserted
> into its parent document. Consider the following two documents:
the parent
> document has a button that removes or reattaches an iframe to
the document,
> while the second simply sets an interval to update the page content.
>
> Page1.html:
> <!DOCTYPE HTML>
> <html>
> <body>
> <p><button onclick="toggleInDoc();">Show/hide</button></p>
> <iframe id="test" src="page2.html"></iframe>
> <script>
> var test = document.getElementById("test");
> function toggleInDoc() {
> if (test.parentNode == null)
> document.body.appendChild(test);
> else
> document.body.removeChild(test);
> }
> </script>
> </body>
> </html>
>
>
> Page2.html:
> <!DOCTYPE HTML>
> <html>
> <body>
> <p id="test"></p>
> <script>
> window.setInterval(function() {
document.getElementById("test").innerHTML
> += "."; }, 500);
> </script>
> </body>
> </html>
>
>
> Assume the user waits until the interval has fired several
times, then
> presses the button, waits a while, and presses it again. There
are three
> possible outcomes:
> 1. When the iframe is reattached, the inner page reloads. This
seems to go
> beyond the wording of the spec, which says only "When an iframe
element is
> first inserted into a document, the user agent must create a
nested browsing
> context, and then process the iframe attributes for the first
time." (This
> isn't the first time the iframe is inserted into the document, so we
> shouldn't process the iframe attributes again.)
>
> 2. The interval (and presumably, all events) in the iframe is
paused while
> it's been detached (since the document is no longer fully
active, but it
> also has not been discarded because of the global reference to
its container
> element).
>
> 3. The interval (and presumably, all events) continues to fire
while it's
> been detached, and the content of page2 will have changed while
it's been
> detached from page1.
>
> So far, Chrome 6, Opera 10.6 and Firefox 3.6 follow #1, and IE 8
follows #3.
> My reading of the "fully active" clause of the spec leads me to
expect #2.
> Which of these behaviors is the desired one? And/or, would it
be desirable
> to permit authors to specify which behavior they intend?
>
> Thanks,
> ~ben
>