Skip to content

Commit

Permalink
Fix handling of navigations before/during load
Browse files Browse the repository at this point in the history
* Fix handling of navigations before/during load

Several types of navigations have a special handling, where if they happen "before load", they are converted into "replace" navigations (instead of "default" navigations). However, this special handling had several interoperability problems and the specification was somewhat broken due to a bad definition of "completely loaded". The result here mostly aligns with Blink behavior.

Notable changes from the previous spec:

* "completely loaded" gets flipped only after the load event has run. It is mostly used to determine "default" vs. "replace" navigations, and in almost all cases browsers treat navigations before or during the load event as getting the special "replace" treatment. This includes the below cases, as well as <iframe> src="" assignment (which is otherwise untouched). The other thing this improves is that it ensures load events on iframe/embed/object elements are only fired (or at least queued) after the corresponding load event on the contained Document.

* location.assign() gets special handling before/during the load event; previously this special handling was only applied to the location setters. (This allows us to roll "Location-object-setter navigate" into "Location-object navigate".)

* Location APIs now override the special handling and force "default" navigation if transient user activation is present, not just if running specifically in a click handler.

* All form submissions can get converted to "replace" if they target a non-completely loaded document. Previously this special handling was only applied to form submissions initiated by the formElement.submit() API.

Notable non-changes (backed by tests):

* Following hyperlinks never varies its "replace" vs. "default" behavior based on completely loaded status.

* window.open() navigating an existing browsing context never varies its "replace" vs. "default" behavior based on completely loaded status.

Closes #6579. Closes #3247.
  • Loading branch information
domenic committed Jun 23, 2021
1 parent 254c179 commit 524485a
Showing 1 changed file with 49 additions and 79 deletions.
128 changes: 49 additions & 79 deletions source
Expand Up @@ -23730,9 +23730,17 @@ document.body.appendChild(wbr);</code></pre>
<var>request</var>'s <span data-x="concept-request-referrer">referrer</span> to "<code
data-x="">no-referrer</code>".</p></li>

<li><p>Let <var>historyHandling</var> be "<code data-x="hh-replace">replace</code>" if
<var>windowType</var> is not "<code data-x="">existing or none</code>"; otherwise, "<code
data-x="hh-default">default</code>".</p></li>
<li>
<p>Let <var>historyHandling</var> be "<code data-x="hh-replace">replace</code>" if
<var>windowType</var> is not "<code data-x="">existing or none</code>"; otherwise, "<code
data-x="hh-default">default</code>".</p>

<p class="note">Unlike many other types of navigations, following hyperlinks does not have
special "<code data-x="hh-replace">replace</code>" behavior for when documents are not
<span>completely loaded</span>. This is true for both user-initiated instances of following
hyperlinks, as well as script-triggered ones via, e.g., <code
data-x="">aElement.click()</code>.</p>
</li>

<li><p><span>Queue an element task</span> on the <span>DOM manipulation task source</span> given
<var>subject</var> to <span>navigate</span><!--DONAV hyperlink--> <var>target</var> to
Expand Down Expand Up @@ -56541,9 +56549,8 @@ fur

<li><p>If <var>target browsing context</var> is null, then return.</p></li>

<li><p>If <var>form document</var> has not yet <span>completely loaded</span> and the
<var>submitted from <code data-x="dom-form-submit">submit()</code> method</var> flag is set, then
set <var>historyHandling</var> to "<code data-x="hh-replace">replace</code>".</p></li>
<li><p>If <var>form document</var> has not yet <span>completely loaded</span>, then set
<var>historyHandling</var> to "<code data-x="hh-replace">replace</code>".</p></li>

<li>
<p>If the value of <var>method</var> is <span
Expand Down Expand Up @@ -84884,37 +84891,9 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
<li><p><i>End</i>: Return <var>output</var>.</p></li>
</ol>

<p>A <code>Location</code> object has an associated <dfn><code>Location</code>-object-setter
navigate</dfn> algorithm, which given a <var>url</var>, runs these steps:</p>

<ol>
<li><p>Let <var>historyHandling</var> be "<code data-x="hh-replace">replace</code>".</p></li>

<li>
<p>If any of the following conditions are met, then set <var>historyHandling</var> to "<code
data-x="hh-default">default</code>":</p>

<ul class="brief">
<li>This <code>Location</code> object's <span>relevant <code>Document</code></span> has
<span>completely loaded</span>, or</li>

<li>In the <span data-x="concept-task">task</span> in which the algorithm is running, an
<span>activation behavior</span> is currently being processed whose <code
data-x="event-click">click</code> event's <code data-x="dom-Event-isTrusted">isTrusted</code>
attribute is true, or</li>

<li>In the <span data-x="concept-task">task</span> in which the algorithm is running, the event
listener for a <code data-x="event-click">click</code> event, whose <code
data-x="dom-Event-isTrusted">isTrusted</code> attribute is true, is being handled.</li>
</ul>
</li>

<li><p><span><code>Location</code>-object navigate</span>, given <var>url</var> and
<var>historyHandling</var>.</p></li>
</ol>

<p>To <dfn><code>Location</code>-object navigate</dfn>, given a <var>url</var> and
<var>historyHandling</var>:</p>
<p>To <dfn><code>Location</code>-object navigate</dfn>, given a <span>URL</span> <var>url</var>
and an optional <span>history handling behavior</span> <var>historyHandling</var> (default "<code
data-x="hh-default">default</code>"):</p>

<ol>
<li><p>Let <var>browsingContext</var> be the <span>current global object</span>'s <span
Expand All @@ -84928,6 +84907,11 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
<code>Document</code></span>, then set <var>historyHandling</var> to "<code
data-x="hh-replace">replace</code>".</p></li>

<li><p>If this <code>Location</code> object's <span>relevant <code>Document</code></span> is not
yet <span>completely loaded</span>, and the <span data-x="concept-incumbent-global">incumbent
global object</span> does not have <span>transient activation</span>, then set
<var>historyHandling</var> to "<code data-x="hh-replace">replace</code>".</p></li>

<li><p><span>Navigate</span><!--DONAV location--> <var>browsingContext</var> to <var>url</var>,
with <var><span>exceptionsEnabled</span></var> set to true, <var
data-x="navigation-hh">historyHandling</var> set to <var>historyHandling</var>, and the
Expand Down Expand Up @@ -84957,7 +84941,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
<li><p><span data-x="parse a url">Parse</span> the given value relative to the <span>entry
settings object</span>. If that failed, throw a <code>TypeError</code> exception.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> given the <span>resulting URL
<li><p><span><code>Location</code>-object navigate</span> given the <span>resulting URL
record</span>.</p></li>
</ol>

Expand Down Expand Up @@ -85026,7 +85010,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
<li><p>If <var>copyURL</var>'s <span data-x="concept-url-scheme">scheme</span> is not an
<span>HTTP(S) scheme</span>, then terminate these steps.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p>The <dfn attribute for="Location"><code data-x="dom-location-host">host</code></dfn>
Expand Down Expand Up @@ -85076,7 +85060,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
state</span> as <span data-x="basic url parser state override"><i>state
override</i></span>.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p>The <dfn attribute for="Location"><code data-x="dom-location-hostname">hostname</code></dfn>
Expand Down Expand Up @@ -85119,7 +85103,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
state</span> as <span data-x="basic url parser state override"><i>state
override</i></span>.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p>The <dfn attribute for="Location"><code data-x="dom-location-port">port</code></dfn>
Expand Down Expand Up @@ -85165,7 +85149,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
state</span> as <span data-x="basic url parser state override"><i>state
override</i></span>.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p>The <dfn attribute for="Location"><code data-x="dom-location-pathname">pathname</code></dfn>
Expand Down Expand Up @@ -85217,7 +85201,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
state</span> as <span data-x="basic url parser state override"><i>state
override</i></span>.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p>The <dfn attribute for="Location"><code data-x="dom-location-search">search</code></dfn>
Expand Down Expand Up @@ -85275,7 +85259,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
</ol>
</li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p>The <dfn attribute for="Location"><code data-x="dom-location-hash">hash</code></dfn>
Expand Down Expand Up @@ -85322,7 +85306,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
state</span> as <span data-x="basic url parser state override"><i>state
override</i></span>.</p></li>

<li><p><span><code>Location</code>-object-setter navigate</span> to <var>copyURL</var>.</p></li>
<li><p><span><code>Location</code>-object navigate</span> to <var>copyURL</var>.</p></li>
</ol>

<p class="note">Unlike the equivalent API for the <code>a</code> and <code>area</code> elements,
Expand All @@ -85349,7 +85333,7 @@ interface <dfn interface>Location</dfn> { // but see also <a href="#the-location
<code>DOMException</code>.</p></li>

<li><p><span><code>Location</code>-object navigate</span> given the <span>resulting URL
record</span> and "<code data-x="hh-default">default</code>".</p></li>
record</span>.</p></li>
</ol>

<p>When the <dfn method for="Location"><code
Expand Down Expand Up @@ -112842,62 +112826,48 @@ document.body.appendChild(text);

<li>
<p><span>Queue a global task</span> on the <span>DOM manipulation task source</span> given the
<code>Document</code>'s <span>relevant global object</span> to run the following substeps:</p>
<code>Document</code>'s <span>relevant global object</span> to run the following steps:</p>

<ol>
<li><p><span>Update the current document readiness</span> to "<code
data-x="">complete</code>".</p></li>

<li>
<p><i>Load event</i>: If the <code>Document</code> object's <span
data-x="concept-document-bc">browsing context</span> is non-null, then:</p>
<li><p>If the <code>Document</code> object's <span data-x="concept-document-bc">browsing
context</span> is null, then abort these steps.</p></li>

<ol>
<li><p>Set the <code>Document</code>'s <span>load timing info</span>'s <span>load event start
time</span> to the <span>current high resolution time</span> given the
<code>Document</code>'s <span>relevant global object</span>.</p></li>

<li><p><span data-x="concept-event-fire">Fire an event</span> named <code
data-x="event-load">load</code> at the <code>Document</code> object's <span>relevant global
object</span>, with <var>legacy target override flag</var> set.</p></li>
<li><p>Let <var>window</var> be the <code>Document</code>'s <span>relevant global
object</span>.</p></li>

<li><p>Set the <code>Document</code>'s <span>load timing info</span>'s <span>load event end
time</span> to the <span>current high resolution time</span> given the
<code>Document</code>'s <span>relevant global object</span>.</p></li>
<li><p>Set the <code>Document</code>'s <span>load timing info</span>'s <span>load event start
time</span> to the <span>current high resolution time</span> given <var>window</var>.</p></li>

<li><p><span>Queue the navigation timing entry</span> for <var>document</var>.</p></li>
</ol>
</li>
</ol>
</li>
<li><p><span data-x="concept-event-fire">Fire an event</span> named <code
data-x="event-load">load</code> at <var>window</var>, with <var>legacy target override
flag</var> set.</p></li>

<li>
<p>If the <code>Document</code> object's <span data-x="concept-document-bc">browsing
context</span> is non-null, then <span>queue a global task</span> on the <span>DOM manipulation
task source</span> given the <code>Document</code>'s <span>relevant global object</span> to run
these steps:</p>
<li><p>Set the <code>Document</code>'s <span>load timing info</span>'s <span>load event end
time</span> to the <span>current high resolution time</span> given <var>window</var>.</p></li>

<ol>
<li><p>If the <code>Document</code>'s <span>page showing</span> flag is true, then return
(i.e. don't fire the event below).</p></li> <!-- i don't see how this could be, but just
to be sure... -->
<li><p>Assert: <code>Document</code>'s <span>page showing</span> is false.</p></li>

<li><p>Set the <code>Document</code>'s <span>page showing</span> flag to true.</p></li>

<li><p><span data-x="concept-event-fire">Fire an event</span> named <code
data-x="event-pageshow">pageshow</code> at the <code>Document</code> object's <span>relevant
global object</span>, using <code>PageTransitionEvent</code>, with the <code
data-x="event-pageshow">pageshow</code> at <var>window</var>, using
<code>PageTransitionEvent</code>, with the <code
data-x="dom-PageTransitionEvent-persisted">persisted</code> attribute initialized to false, and
<var>legacy target override flag</var> set.</p></li>

<li><p><span>Completely finish loading</span> the <code>Document</code>.</p></li>

<li><p><span>Queue the navigation timing entry</span> for the <code>Document</code>.</p></li>
</ol>
</li>

<li><p>If the <code>Document</code>'s <span>print when loaded</span> flag is set, then run the
<span>printing steps</span>.</p></li>

<li><p>The <code>Document</code> is now <dfn>ready for post-load tasks</dfn>.</p></li>

<li><p><span>Completely finish loading</span> the <code>Document</code>.</p></li>
</ol>

<p>When the user agent is to <dfn>abort a parser</dfn>, it must run the following steps:</p>
Expand Down

0 comments on commit 524485a

Please sign in to comment.