User:Bryner

From MozillaWiki
Jump to: navigation, search

With the advent of fast-back, some DOM events that are listened for by chrome have become quite ambiguous. For example, chrome extensions may be listening to the onload event for one of two reasons:

 1. They want to notice that the currently shown page has changed, so that some UI can be updated.
 2. They want to change the DOM of the loaded page in some way.

Clearly, when restoring a document from session history, listeners such as #1 need to be notified. However, DOM modifications should only happen once.

To solve this, I propose the following:

  • The "load" event is fired only when a document is initially constructed.
  • The "unload" event is fired only when a document is destroyed. It will fire on a document that's in session history when the document drops out of session history, for the benefit of the chrome (the content area, by definition, does not have an unload listener if the document is in session history).
  • When a document is shown in a content area, the "PageShow" event is fired. On initial load, this event fires immediately after the normal load event. The semantics are the same as load with respect to firing on subframes.
  • When a document is no longer being shown in a content area, the "PageHide" event is fired. If the document is not saved in session history, this fires immediately after the normal unload event. The semantics are the same as unload with respect to firing on subframes. The event can be cancelled the same way as unload.
  • WebProgressListener notifications fire when documents are restored from session history, with the STATE_IS_RESTORE bit set in addition to the standard bits.
  • The DOMContentLoaded and DOMFrameContentLoaded events are not fired when restoring a page from session history.
  • The DOMLinkAdded and DOMLinkRemoved events fire for all <link> elements in a document when the document is saved or restored from session history.

The two new events, PageShow and PageHide, support a new interface, nsIDOMPageChangeEvent. This interface defines a single attribute:

interface nsIDOMPageChangeEvent : nsIDOMEvent
{
 /**
  * Set to true if the document has been or will be persisted across
  * firing of the event.  For example, if a document is being cached in
  * session history, |persisted| is true for the PageHide event.
  */
 readonly attribute boolean persisted;
 /* Initialize a new PageShow or PageHide event. */
 void initPageChangeEvent(in DOMString typeArg,
                          in boolean canBubbleArg,
                          in boolean canCancelArg,
                          in boolean persisted);
};

With these new events, chrome can register handlers as follows:

  • Handlers which want to modify the content DOM when it is initially loaded can continue to listen to the load event. It will only ever fire once for a given document.
  • Handlers which want to watch for page transitions can listen for PageShow and PageHide, instead of load and unload. The |persisted| property can be used to clarify the context of the event if needed.

I expect this change to break several extensions, but it's likely that about as many would break if they started receiving multiple load events per document. This approach provides us with a consistent event model going forward.

Open questions:

  • DOMHeadLoaded