Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rough history traversal algorithm #250

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ Navigations within portals are subject to certain security restrictions for load

Navigation errors within portals may cause portal activation to be rejected. Instead of, for example, the user agent showing an error page to the user as with a conventional navigation, the promise returned by the activate method allows a page to gracefully handle the rejection. Furthermore, user agents have existing limitations on navigations initiated by the page where they may be ignored if they are considered to conflict with a user's intent to perform a different navigation. Such cases are not described by the existing navigation spec (see [#218](https://github.com/WICG/portals/issues/218)), but portal activations are subject to these limitations. In the case where another navigation takes precedence over portal activation, the promise returned by the activate method rejects.

See the [rough algorithms](history-traversal.md) for cases where portals may be auto-activated, and pages may be reportaled, when traversing session history.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the right way to link to another doc from a README.md?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, this works.


TODO:

- Talk about how bfcache is tricky.
Expand Down
107 changes: 107 additions & 0 deletions history-traversal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# History traversal

These rough algorithms describe how portal activation, adoption, reportaling, and deportaling should work.

Eventually, these steps will be moved into the portal spec, and the history traversal section of the HTML spec.

## Definitions

<dl>
<dt>Navigable</dt>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i.e., a browsing context?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Portals can navigate, and when they do so they change browsing context each time.

If you navigate and it requires isolation due to COOP+COEP, that also involves a change in browsing context.

This is one of the "boil the ocean" things that needs to happen, because the spec doesn't carter for this at all, it assumes that browsing contexts stay constant within navigable. The spec also makes session history a property of the browsing context, which is similarly broken.

<dd>something that has session history, such as a top level page, an iframe, or a portal (although a portal can only have one item of session history).</dd>
</dl>

## Activate a portal in a 'push' style

This is a regular activation that clears any 'forward' items in join session history and adds a new top-level history entry for the portaled document.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and elsewhere, is this "joint"?


1. Let _document_ be the portal's session history item's document.
1. Let _targetHistoryItem_ be a copy of the portal's session history item.
1. Remove _targetHistoryItem_'s document.
1. Give _targetHistoryItem_ a weak reference to _document_.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually easier/clearer than having the history item has a strong/weak flag rather than two separate fields?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't as easy as I thought.

Good bits:

  • Avoids moving the document from property to property
  • Avoids cases where the weak document and main document are set at the same time (and are different)

Less good bits:

  • Maybe the moving solidifies the 'documents move around model' that we agreed on?
  • It doesn't work with portals. With portals the history item is removed upon activation, so the weak reference is on the portal itself. We could keep the history item and set the weak flag there, but that means any portal rendering/interaction code would need to treat the history entry as absent if the weak flag is set. Although, this would ensure the weak reference is gone when the portal is navigated.

There may be other places where we'd need to avoid doing things with the session history item if the document reference is weak.

I'm undecided.

1. All 'forward' session history items are removed from the parent navigable.
1. Append _targetHistoryItem_ to the parent navigable's history items.
1. [Traverse to session history item](#traverse-to-session-history-item) with _targetHistoryItem_.

Note: Actual activation is handled in history traversal.

## Activate a portal in a 'back' style

This is an activation that goes back through join session history. The API for this hasn't been designed, but if it exists it's likely to be an option to `activate()`.

1. Let _targetHistoryItem_ be the previous history item in the parent navigable, where the browsing context or URL differs from the current history item, ignoring the hash portion of the URLs.
1. If _targetHistoryItem_ does not have a weak reference to the portal's history item's document, reject and abort these steps.
1. [Traverse to session history item](#traverse-to-session-history-item) with _targetHistoryItem_.

Note: Actual activation is handled in history traversal.

## Activate a portal in a 'forwards' style

This is an activation that go forward through join session history, without destroying existing items. The API for this hasn't been designed, but if it exists it's likely to be an option to `activate()`.

1. Let _targetHistoryItem_ be the next history item in the parent navigable, where the browsing context or URL differs from the current history item, ignoring the hash portion of the URLs.
1. If _targetHistoryItem_ does not have a weak reference to the portal's history item's document, reject and abort these steps.
1. [Traverse to session history item](#traverse-to-session-history-item) with _targetHistoryItem_.

Note: Actual activation is handled in history traversal.

## Activate a portal in a 'replace' style

This is an activation that will replace the current top level page. The API for this hasn't been designed, but if it exists it's likely to be an option to `activate()`.

1. Let _document_ be the portal's session history item's document.
1. Let _targetHistoryItem_ be a copy of the portal's session history item.
1. Remove _targetHistoryItem_'s document.
1. Give _targetHistoryItem_ a weak reference to _document_.
1. [Traverse to session history item](#traverse-to-session-history-item) with _targetHistoryItem_ and isReplacement set to true.

Note: Actual activation is handled in history traversal.

## Traverse to session history item

With _targetHistoryItem_ and _isReplacement_.

1. If the _targetHistoryItem_ and the current history item have the same document, and neither is null, traverse to _targetHistoryItem_ in the regular way and abort these steps.

Note: This is an in-document navigation. Nothing portal-related happens in this case.

1. Let _documentChangesInDelta_ be 0.
1. Let _historyItems_ be null.
1. If _isReplacement_, then set _historyItems_ to [the current history item, _targetHistoryItem_].
1. Otherwise, set _historyItems_ to the history items of this navigable, between the current item, and target item, including the current item and _targetHistoryItem_, in order.
1. Remove the first item from _historyItems_.
1. For each _historyItem_ of _historyItems_, if any of the following is true, increment _documentChangesInDelta_:
- _historyItem_ has a different browsing context to the previous item in the list.
- _historyItem_'s URL is different to the previous item in the list, ignoring the hash portion of the URL in both.
1. If _documentChangesInDelta_ is greater than 1, then traverse to _targetHistoryItem_ in the regular way and abort these steps.

Note: To avoid multiple levels of reportaling, reportaling and implicit activation is skipped if the navigation spans across multiple documents

1. Asset: _documentChangesInDelta_ is not 0.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sp: Assert


Note: This should have been catered for in step 1.

1. If _targetHistoryItem_ does not contain a document, and _targetHistoryItem_ has a weak reference to a document that's inside a portal in the current history item's document. then:

1. Let _document_ be that portal's document.
1. For each item in the navigable's session history that has a weak reference to _document_, set its document to _document_, and remove its weak reference to _document_.
1. Give the portal a weak reference to the document inside the portal.
1. Remove the portal's session history item.
1. If adoption is permitted, offer _targetHistoryItem_'s document the opportunity to adopt the current history item. If this opportunity is taken:

1. A new portal element is created in _targetHistoryItem_'s document.
1. Give the portal a weak reference to the current history item's document.

Note: The rest of the process is picked up in step 12.

1. If _targetHistoryItem_ does not contain a document, then traverse to _targetHistoryItem_ in the regular way and abort these steps.
1. If _targetHistoryItem_'s document contains a portal with a weak reference to the current history item's document, then:
1. Let _documentToPortal_ be the current history item's document.
1. Set the portal's history item to a copy of the current history item.
1. Remove the portal's weak reference to _documentToPortal_.
1. For each item in the navigable's session history, remove its document if the document is _documentToPortal_, and give it a weak reference to _documentToPortal_.
1. Otherwise, unload the current history item's document.

Note: This may include excluding it from bfcache.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite follow this but I assume there's a reason.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll improve the language here. During unloading, things can happen that exclude the document from bfcache, such as unload event handlers.


1. Continue traversing to _targetHistoryItem_ in the regular way.