<iframe> and the History API #184

Open
hayatoito opened this Issue Jul 6, 2015 · 92 comments

Comments

Projects
None yet
7 participants
@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Feb 16, 2016

Member

@rniwa what is Apple doing here?

Member

annevk commented Feb 16, 2016

@rniwa what is Apple doing here?

@annevk annevk changed the title from [Shadow]: Figure out how session history should work for <iframe>s in shadow DOM (bugzilla: 27325) to <iframe> and the History API Feb 16, 2016

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Feb 16, 2016

Member

@smaug---- so I guess the problem is all the state exposed on History? If we did not expose that, would we have to expose it somehow on ShadowRoot? That each gets its own history? Presumably defaulting to no history at all for v1?

That kind of approach makes sense if you don't want to influence your container, but if you're a simple layout component that breaks expectations. Not sure if there's a good answer here. (We could make it depend on open vs closed...)

Member

annevk commented Feb 16, 2016

@smaug---- so I guess the problem is all the state exposed on History? If we did not expose that, would we have to expose it somehow on ShadowRoot? That each gets its own history? Presumably defaulting to no history at all for v1?

That kind of approach makes sense if you don't want to influence your container, but if you're a simple layout component that breaks expectations. Not sure if there's a good answer here. (We could make it depend on open vs closed...)

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Feb 16, 2016

For open case I could possibly live with normal nested browsing context handling.
And for closed...no session history at all? I think that is the easiest for now. history.pushState/replaceState would do what? and what about history.go(x)? Throw?
I think throw is the only sane option, except perhaps for go(0)
How should the UI work? If shadow-iframe loads page X and then Y is loaded there, what should back button do? I guess nothing. That shouldn't be too bad. The shadow-iframe container component could manually call push/replaceState when needed, or shadow-iframe.src = "some new page"

Given the recent example, bug in Google Ads where their scripts caused the container page to go back, I'd prefer to never expose history state even in open case, but at least in closed case the state shouldn't be shared.

For open case I could possibly live with normal nested browsing context handling.
And for closed...no session history at all? I think that is the easiest for now. history.pushState/replaceState would do what? and what about history.go(x)? Throw?
I think throw is the only sane option, except perhaps for go(0)
How should the UI work? If shadow-iframe loads page X and then Y is loaded there, what should back button do? I guess nothing. That shouldn't be too bad. The shadow-iframe container component could manually call push/replaceState when needed, or shadow-iframe.src = "some new page"

Given the recent example, bug in Google Ads where their scripts caused the container page to go back, I'd prefer to never expose history state even in open case, but at least in closed case the state shouldn't be shared.

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Feb 17, 2016

Member

I would be okay with blocking history from "shadow-iframe" by default. And then later figuring out if we want to make that work. @hayatoito @rniwa?

Member

annevk commented Feb 17, 2016

I would be okay with blocking history from "shadow-iframe" by default. And then later figuring out if we want to make that work. @hayatoito @rniwa?

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Feb 17, 2016

Member

I'm not sure if throwing would be best by the way. It depends on what kind of things end up being embedded. If you throw a bunch of existing pages will likely break when embedded in this way.

Member

annevk commented Feb 17, 2016

I'm not sure if throwing would be best by the way. It depends on what kind of things end up being embedded. If you throw a bunch of existing pages will likely break when embedded in this way.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Feb 17, 2016

but if the page called go(<not_zero>), it sure would expect something to happen, and if we wouldn't throw, the page would be broken in some other way.
Or pushState(). After that one would expect history.state to be the thing passed to pushState.

This is tricky, but I'm not sure we have any other good option to effectively disable all history API in shadow-iframes.
Hmmm, crazy idea. Could we actually hide History interface and .history propery in the browsing contexts under shadow-iframes?

but if the page called go(<not_zero>), it sure would expect something to happen, and if we wouldn't throw, the page would be broken in some other way.
Or pushState(). After that one would expect history.state to be the thing passed to pushState.

This is tricky, but I'm not sure we have any other good option to effectively disable all history API in shadow-iframes.
Hmmm, crazy idea. Could we actually hide History interface and .history propery in the browsing contexts under shadow-iframes?

@annevk annevk referenced this issue in whatwg/html Feb 29, 2016

Open

Shadow DOM and <iframe> #763

@rniwa rniwa added the v1 label Mar 7, 2016

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Mar 15, 2016

Member

I would be okay with blocking history from "shadow-iframe" by default. And then later figuring out if we want to make that work. @hayatoito @rniwa?

I am okay with this. Blocking history from "shadow-iframe" by default should be a safe option.

[Updated] On the second thought, go() should work, IMO. Let me think further.

Member

hayatoito commented Mar 15, 2016

I would be okay with blocking history from "shadow-iframe" by default. And then later figuring out if we want to make that work. @hayatoito @rniwa?

I am okay with this. Blocking history from "shadow-iframe" by default should be a safe option.

[Updated] On the second thought, go() should work, IMO. Let me think further.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Mar 15, 2016

Member

My opinion is:

  • iframes in a shadow tree does not have any affect on window.history. Thus, states of iframes in a shadow trees is not exposed to window.history. In other words, window.history is owned exclusively by a document tree.
  • go() should work as usual.

We might want to have another APIs, such as DocumentOrShadowRoot.history, if we want to make that work somehow later.

Member

hayatoito commented Mar 15, 2016

My opinion is:

  • iframes in a shadow tree does not have any affect on window.history. Thus, states of iframes in a shadow trees is not exposed to window.history. In other words, window.history is owned exclusively by a document tree.
  • go() should work as usual.

We might want to have another APIs, such as DocumentOrShadowRoot.history, if we want to make that work somehow later.

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Mar 15, 2016

Member

How can go() work if such <iframe>s don't have an effect on the history?

Member

annevk commented Mar 15, 2016

How can go() work if such <iframe>s don't have an effect on the history?

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Mar 15, 2016

Member

go() works in a history of a document tree. So I guess calling window.history.go() from a (developer of) shadow tree is a bad practice and does not bring a desired behavior in most cases.

Member

hayatoito commented Mar 15, 2016

go() works in a history of a document tree. So I guess calling window.history.go() from a (developer of) shadow tree is a bad practice and does not bring a desired behavior in most cases.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Mar 15, 2016

To be a tad more precise, go() works in browsing context tree.

Not putting shadow dom iframe loads to session history, but having go() to work would lead to very surprising behavior. The browsing context in iframe could expect its page loads are in session history, but go() wouldn't actually know about those loads so it would always affect to some ancestor or sibling browsing context, never the browsing context in iframe.

(go() is super error prone API to use :/ )

To be a tad more precise, go() works in browsing context tree.

Not putting shadow dom iframe loads to session history, but having go() to work would lead to very surprising behavior. The browsing context in iframe could expect its page loads are in session history, but go() wouldn't actually know about those loads so it would always affect to some ancestor or sibling browsing context, never the browsing context in iframe.

(go() is super error prone API to use :/ )

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 1, 2016

Member

Yeah, I think we can not have a perfect solution here. We have to compromise for window.history because it's globally accessible.

Member

hayatoito commented Apr 1, 2016

Yeah, I think we can not have a perfect solution here. We have to compromise for window.history because it's globally accessible.

@hayatoito hayatoito closed this in 08793be Apr 8, 2016

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Apr 8, 2016

Member

That doesn't really solve this issue though, does it? I guess we still have the corresponding issue against the HTML Standard to define what should happen here...

Member

annevk commented Apr 8, 2016

That doesn't really solve this issue though, does it? I guess we still have the corresponding issue against the HTML Standard to define what should happen here...

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 8, 2016

Member

Let me reopen. Should we define how go() works?

Member

hayatoito commented Apr 8, 2016

Let me reopen. Should we define how go() works?

@hayatoito hayatoito reopened this Apr 8, 2016

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Apr 8, 2016

Member

Yeah, and all the other members.

Member

annevk commented Apr 8, 2016

Yeah, and all the other members.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Apr 13, 2016

Member

So the conclusion here is to leave the history API work as is, even in closed shadow root,
and no blocking for shadow-iframes?
i.e. any <iframe> navigation history will be included in joint session history.

As dimitri's comment pointed out, whether shadow DOM is detectable is not a concern.

I'll work on a draft for pull request.

Member

TakayoshiKochi commented Apr 13, 2016

So the conclusion here is to leave the history API work as is, even in closed shadow root,
and no blocking for shadow-iframes?
i.e. any <iframe> navigation history will be included in joint session history.

As dimitri's comment pointed out, whether shadow DOM is detectable is not a concern.

I'll work on a draft for pull request.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 14, 2016

Member

That does not seem the conclusion here... ;)

Let me explain the context:

I and @TakayoshiKochi discussed this topic yesterday, and we got a rough consensus:
"Let window.history API work as is. <iframe> in a shadow tree will contribute a top-level browsing context's joint session history."

Member

hayatoito commented Apr 14, 2016

That does not seem the conclusion here... ;)

Let me explain the context:

I and @TakayoshiKochi discussed this topic yesterday, and we got a rough consensus:
"Let window.history API work as is. <iframe> in a shadow tree will contribute a top-level browsing context's joint session history."

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Apr 14, 2016

Member

That conclusion seems directly opposed to comments from folks from Apple and Mozilla that very much want encapsulation at all cost, even if it means losing features like document.currentScript.

Member

annevk commented Apr 14, 2016

That conclusion seems directly opposed to comments from folks from Apple and Mozilla that very much want encapsulation at all cost, even if it means losing features like document.currentScript.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 14, 2016

Member

Yeah, this is the opposite. Actually, I have changed my mind.

Yesterday, I tried to have a good proposal, but I can not have any concrete proposal if we are to block iframe in a shadow tree. That made me in a trouble. Some of the concerns in #184 (comment) can not be resolved.

After that, I am starting to tend to agree with Dimitir's comment in this particular case:

there is no big concern if In this perspective, exposing information or making Shadow DOM presence detectable is not as big of a concern.

Maybe I might change my mind again, but as of now, I am fine with "not blocking at all".

Member

hayatoito commented Apr 14, 2016

Yeah, this is the opposite. Actually, I have changed my mind.

Yesterday, I tried to have a good proposal, but I can not have any concrete proposal if we are to block iframe in a shadow tree. That made me in a trouble. Some of the concerns in #184 (comment) can not be resolved.

After that, I am starting to tend to agree with Dimitir's comment in this particular case:

there is no big concern if In this perspective, exposing information or making Shadow DOM presence detectable is not as big of a concern.

Maybe I might change my mind again, but as of now, I am fine with "not blocking at all".

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Apr 14, 2016

I'm very worried about exposing shadow iframes in the the light DOM's session history. It would make using history API in light DOM super error prone: it would become really hard for light DOM to know what the current state actually is.
History API is error prone enough even without shadow DOM. The recent incident where Google Ads started to do random history.go(-1) and forcing browser to go to the previous top level page (since go(-1) was called at wrong state or something) is just a hint of that.

I'm very worried about exposing shadow iframes in the the light DOM's session history. It would make using history API in light DOM super error prone: it would become really hard for light DOM to know what the current state actually is.
History API is error prone enough even without shadow DOM. The recent incident where Google Ads started to do random history.go(-1) and forcing browser to go to the previous top level page (since go(-1) was called at wrong state or something) is just a hint of that.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Apr 15, 2016

Member

@smaug---- is the concern shadow-dom specific?

I may not be understanding the case you quoted. In my understanding the injected Google Ads script mistakenly ran history.go(-1) which expected to navigate some <iframe> to go back to its history, but the history was empty and the main document went back, right?
This can easily happen if there are more than one injected <iframe>s and script tries to go back and forth independently for each <iframe>.

That's a reasonable concern but it should be addressed at nested browsing context and history API's behavior about joint session history, not at the level of shadow tree boundary.

Member

TakayoshiKochi commented Apr 15, 2016

@smaug---- is the concern shadow-dom specific?

I may not be understanding the case you quoted. In my understanding the injected Google Ads script mistakenly ran history.go(-1) which expected to navigate some <iframe> to go back to its history, but the history was empty and the main document went back, right?
This can easily happen if there are more than one injected <iframe>s and script tries to go back and forth independently for each <iframe>.

That's a reasonable concern but it should be addressed at nested browsing context and history API's behavior about joint session history, not at the level of shadow tree boundary.

@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Apr 15, 2016

Contributor

Let's say a social network site starts using shadow DOM and an iframe for its own widget to display comments. Then, you don't want navigations within that iframe to affect the navigation history of the embedding page. It DOES happen today but I don't think that's really intended / desirable.

Contributor

rniwa commented Apr 15, 2016

Let's say a social network site starts using shadow DOM and an iframe for its own widget to display comments. Then, you don't want navigations within that iframe to affect the navigation history of the embedding page. It DOES happen today but I don't think that's really intended / desirable.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 15, 2016

Member

Yeah, that's one of concerns. However, I do not want Shadow DOM to control the behavior of iframes.
Shadow DOM should not have such a huge responsibility, IMO.

I prefer separating responsibilities to more primitives, in order to isolate our concerns.
For example, a new attribute for iframe, such as <iframe joinhistory=false>.

Member

hayatoito commented Apr 15, 2016

Yeah, that's one of concerns. However, I do not want Shadow DOM to control the behavior of iframes.
Shadow DOM should not have such a huge responsibility, IMO.

I prefer separating responsibilities to more primitives, in order to isolate our concerns.
For example, a new attribute for iframe, such as <iframe joinhistory=false>.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 15, 2016

Member

In general, that's component user's fault if they use a bad component.

As a general rule,

  1. A component can do anything for outer trees. A component developer should have a responsibility to make a component a good citizen.
  2. The opposite should not be true. An outer tree can not invade the inside of the component. That should be honored.

In this particular case, <ifarme> and history , this should be categorized to 1, I think.
This would not be a big concern, I hope.

Member

hayatoito commented Apr 15, 2016

In general, that's component user's fault if they use a bad component.

As a general rule,

  1. A component can do anything for outer trees. A component developer should have a responsibility to make a component a good citizen.
  2. The opposite should not be true. An outer tree can not invade the inside of the component. That should be honored.

In this particular case, <ifarme> and history , this should be categorized to 1, I think.
This would not be a big concern, I hope.

@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Apr 15, 2016

Contributor

This DOES seem like a pretty significant concern given changing this behavior later would not be backwards compatible.

I don't understand where your rule comes from. As far as I could recall, we've never reached a consensus on such a general principles (or even a consensus that having such a principle is a good idea).

Contributor

rniwa commented Apr 15, 2016

This DOES seem like a pretty significant concern given changing this behavior later would not be backwards compatible.

I don't understand where your rule comes from. As far as I could recall, we've never reached a consensus on such a general principles (or even a consensus that having such a principle is a good idea).

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Apr 15, 2016

Member

The general rule that Hayato wrote in #184 (comment) isn't the matter of concern in this thread, and everyone doesn't have to agree on it at least here. He just expressed the reasoning behind our opinion.

BTW, I read Hayato's #184 (comment) wrong and I thought keeping the behavior as is was the conclusion of this thread in my previous #184 (comment). As everyone already pointed it out, it was totally opposite to what was changed in the spec change 08793be. Sorry for any confusion incurred by my message.

Member

TakayoshiKochi commented Apr 15, 2016

The general rule that Hayato wrote in #184 (comment) isn't the matter of concern in this thread, and everyone doesn't have to agree on it at least here. He just expressed the reasoning behind our opinion.

BTW, I read Hayato's #184 (comment) wrong and I thought keeping the behavior as is was the conclusion of this thread in my previous #184 (comment). As everyone already pointed it out, it was totally opposite to what was changed in the spec change 08793be. Sorry for any confusion incurred by my message.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 15, 2016

Member

I don't understand where your rule comes from.

Yeah, that comes from my attempt to honer a well-established rule (I believe):

  • Access from Inner To Outer: Allowed
  • Access from Outer To Inner: Disallowed

We see a similar rule in most of programming languages. Thus, I think having this principle in our mind would be good for us.

Actually, you can see several instances of this rule in the current Shadow DOM:
e.g.

  • a retargeting algorithm
  • a concept of a unclosed node
Member

hayatoito commented Apr 15, 2016

I don't understand where your rule comes from.

Yeah, that comes from my attempt to honer a well-established rule (I believe):

  • Access from Inner To Outer: Allowed
  • Access from Outer To Inner: Disallowed

We see a similar rule in most of programming languages. Thus, I think having this principle in our mind would be good for us.

Actually, you can see several instances of this rule in the current Shadow DOM:
e.g.

  • a retargeting algorithm
  • a concept of a unclosed node
@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Apr 15, 2016

Contributor

The problem here is that exposing iframe history in the outer world breaks that very principle. Now the outer DOM can influence what gets shown in the iframe inside a shadow tree by using history.go(-1) and other history APIs.

Contributor

rniwa commented Apr 15, 2016

The problem here is that exposing iframe history in the outer world breaks that very principle. Now the outer DOM can influence what gets shown in the iframe inside a shadow tree by using history.go(-1) and other history APIs.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 15, 2016

Member

Now the outer DOM can influence what gets shown in the iframe inside a shadow tree by using history.go(-1) and other history APIs.

Oh. That makes sense. This is a kind of "Outer to Inner".
However, given that history APIs is available via global window object, that sounds a historical technical debt and hard to avoid.

The problem here is that we do not have any concrete proposal other than "Not blocking at all".
Does someone have a clever idea?

Member

hayatoito commented Apr 15, 2016

Now the outer DOM can influence what gets shown in the iframe inside a shadow tree by using history.go(-1) and other history APIs.

Oh. That makes sense. This is a kind of "Outer to Inner".
However, given that history APIs is available via global window object, that sounds a historical technical debt and hard to avoid.

The problem here is that we do not have any concrete proposal other than "Not blocking at all".
Does someone have a clever idea?

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Apr 15, 2016

Member

We have options, I see about three paths:

  1. Leak. Not a lot of work, has objections from Apple and Mozilla.
  2. Don't make the iframe element work in shadow trees. Even less work, this is the status quo in the HTML Standard.
  3. Design iframe elements differently inside shadow trees so they do not put properties on the global object and don't interfere with the history of the browsing context. Could be quite a bit of work, I haven't had time to investigate yet.
Member

annevk commented Apr 15, 2016

We have options, I see about three paths:

  1. Leak. Not a lot of work, has objections from Apple and Mozilla.
  2. Don't make the iframe element work in shadow trees. Even less work, this is the status quo in the HTML Standard.
  3. Design iframe elements differently inside shadow trees so they do not put properties on the global object and don't interfere with the history of the browsing context. Could be quite a bit of work, I haven't had time to investigate yet.
@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Apr 15, 2016

  1. (4) throw in all the History attributes and methods when iframe is in shadow dom
  2. (5) make attributes and methods of History no-ops
  3. (6) hide .history property in shadow iframes.
  4. (7) make .history property to be null in shadow iframes

(all these also need that loads in shadow iframes don't end up to session history)

(7) might not be too bad. Since it is not really acceptable for shadow iframe to affect to the global history, no pages using history API should be loaded to shadow iframes.

Or then (3), so that shadow iframe becomes a root of a session history itself. (but then, how would the UI work with several different session histories)

smaug---- commented Apr 15, 2016

  1. (4) throw in all the History attributes and methods when iframe is in shadow dom
  2. (5) make attributes and methods of History no-ops
  3. (6) hide .history property in shadow iframes.
  4. (7) make .history property to be null in shadow iframes

(all these also need that loads in shadow iframes don't end up to session history)

(7) might not be too bad. Since it is not really acceptable for shadow iframe to affect to the global history, no pages using history API should be loaded to shadow iframes.

Or then (3), so that shadow iframe becomes a root of a session history itself. (but then, how would the UI work with several different session histories)

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Apr 18, 2016

Member

Thank you, @annevk , @smaug---- .

Blink is fine with 1 in #184 (comment).

Shadow DOM is originally designed to provide an encapsulation for DOM tree structures. It was not designed to provide an encapsulation for scripts. Thus, as long as nodes in a shadow tree are not leaked to outer trees, I am okay.

A behavior leakage (I am not sure how I can call this..) which would be caused by scripts is not what I expect Shadow DOM to prevent that. I do not want Shadow DOM to own such a role magically beyond its original role.

It would be nice that we could have a separate primitive which prevents these kinds of the behavior influences from happening, other than reusing a tree structure boundary provided by Shadow DOM.

A unit of a shadow tree and a unit of joint session history do not have to be always the same, I guess.

Member

hayatoito commented Apr 18, 2016

Thank you, @annevk , @smaug---- .

Blink is fine with 1 in #184 (comment).

Shadow DOM is originally designed to provide an encapsulation for DOM tree structures. It was not designed to provide an encapsulation for scripts. Thus, as long as nodes in a shadow tree are not leaked to outer trees, I am okay.

A behavior leakage (I am not sure how I can call this..) which would be caused by scripts is not what I expect Shadow DOM to prevent that. I do not want Shadow DOM to own such a role magically beyond its original role.

It would be nice that we could have a separate primitive which prevents these kinds of the behavior influences from happening, other than reusing a tree structure boundary provided by Shadow DOM.

A unit of a shadow tree and a unit of joint session history do not have to be always the same, I guess.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- May 17, 2016

shadow iframe should have its own session history, and that could be exposed only to web page using history API. User doesn't know what is iframe and what is just some random element which content is changed dynamically. So there is no need to have any UI for the shadow iframe history.

shadow iframe should have its own session history, and that could be exposed only to web page using history API. User doesn't know what is iframe and what is just some random element which content is changed dynamically. So there is no need to have any UI for the shadow iframe history.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito May 18, 2016

Member

I think the point is:

e.g.

  1. User visits A1.
  2. User clicks a link in A1 => User visits A2, which contains shadow iframe B1 and shadow iframe C1
  3. User clicks a link in B1 => User sees: A2 + B2 + C1
  4. User clicks a link in B2 => User sees: A2 + B3 + C1
  5. User clicks a link in C1 => User sees: A2 + B3 + C2
  6. User clicks a back button in UA's toolbar => Back to state 1 (A1), rather than state 4 (A2 + B3 + C1), because we do not keep a joint-history anywhere.

As far as I understand, this is the current proposal, right?

From user's perspective, 6 looks a weird movement.
Users would feel that one click of a back button rewinded 4 history items, rather than one history item.

Member

hayatoito commented May 18, 2016

I think the point is:

e.g.

  1. User visits A1.
  2. User clicks a link in A1 => User visits A2, which contains shadow iframe B1 and shadow iframe C1
  3. User clicks a link in B1 => User sees: A2 + B2 + C1
  4. User clicks a link in B2 => User sees: A2 + B3 + C1
  5. User clicks a link in C1 => User sees: A2 + B3 + C2
  6. User clicks a back button in UA's toolbar => Back to state 1 (A1), rather than state 4 (A2 + B3 + C1), because we do not keep a joint-history anywhere.

As far as I understand, this is the current proposal, right?

From user's perspective, 6 looks a weird movement.
Users would feel that one click of a back button rewinded 4 history items, rather than one history item.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 18, 2016

Member

Yeah, the point is that navigation within <iframe> works regardless of Shadow DOM,
but browser UI back/forward button works differently after iframe navigation, whether
it is in Shadow DOM or not. Is this difference acceptable?

This is slightly diverged from the original topic (window.history API) and the spec only says
in non-normative section:
https://html.spec.whatwg.org/multipage/browsers.html#history-notes
So, even when history API's go()/back()/forward() follow its own history list, browser UI can still
follow the whole joint session history, which is implementation specific.

Member

TakayoshiKochi commented May 18, 2016

Yeah, the point is that navigation within <iframe> works regardless of Shadow DOM,
but browser UI back/forward button works differently after iframe navigation, whether
it is in Shadow DOM or not. Is this difference acceptable?

This is slightly diverged from the original topic (window.history API) and the spec only says
in non-normative section:
https://html.spec.whatwg.org/multipage/browsers.html#history-notes
So, even when history API's go()/back()/forward() follow its own history list, browser UI can still
follow the whole joint session history, which is implementation specific.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 18, 2016

Member

To amend what hayato said(#184 (comment)), we can keep a joint session history somewhere, and browser can use it for
back/forward buttons. We don't expose the joint session history to any window.history
interface.

We used to have (implicit?) assumption that history objects in main page/iframes has
history list synced with browser UI's back/forward button,
but in the new world, any history.go() in each iframe in shadow DOM is local,
and such local movement doesn't necessarily matches the old world's synced,
linear movement, and there can be multiple possibility of how browser's back/forward
button works.

Member

TakayoshiKochi commented May 18, 2016

To amend what hayato said(#184 (comment)), we can keep a joint session history somewhere, and browser can use it for
back/forward buttons. We don't expose the joint session history to any window.history
interface.

We used to have (implicit?) assumption that history objects in main page/iframes has
history list synced with browser UI's back/forward button,
but in the new world, any history.go() in each iframe in shadow DOM is local,
and such local movement doesn't necessarily matches the old world's synced,
linear movement, and there can be multiple possibility of how browser's back/forward
button works.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 18, 2016

Member

@smaug----, in my #184 (comment)
I had a mental model that user "clicked" some link within an iframe and navigated to the
new content in the iframe. Reading your comment

what is just some random element which content is changed dynamically

I am not sure you got that point.

Usually a user who clicks on a link would expect browser's back button would bring him/her
back to the previous state, I guess.

Member

TakayoshiKochi commented May 18, 2016

@smaug----, in my #184 (comment)
I had a mental model that user "clicked" some link within an iframe and navigated to the
new content in the iframe. Reading your comment

what is just some random element which content is changed dynamically

I am not sure you got that point.

Usually a user who clicks on a link would expect browser's back button would bring him/her
back to the previous state, I guess.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 18, 2016

Member

To pose the problem in a flipped way, after the following user-initiated (click on link) navigation
happend in the demo, assuming
each iframe were in the Shadow DOM.

Entry1: A1
Entry2: A2 + B1 + C1
Entry3: A2 + B1 + C2
Entry4: A2 + B2 + C2

Each history object has the following list:

A: [A1, A2] current index = 1
B: [B1, B2] current index = 1
C: [C1, C2] current index = 1

then history.back() is executed in frame C, each history object looks like:

A: [A1, A2] current index = 1
B: [B1, B2] current index = 1
C: [C1, C2] current index = 0 (showing C1 content)

What will happen for each frame and each history object if browser UI's back/forward button
is pressed?
(again, this may be out of scope for the HTML spec, but everyone here has to implement something for each browser :)

Member

TakayoshiKochi commented May 18, 2016

To pose the problem in a flipped way, after the following user-initiated (click on link) navigation
happend in the demo, assuming
each iframe were in the Shadow DOM.

Entry1: A1
Entry2: A2 + B1 + C1
Entry3: A2 + B1 + C2
Entry4: A2 + B2 + C2

Each history object has the following list:

A: [A1, A2] current index = 1
B: [B1, B2] current index = 1
C: [C1, C2] current index = 1

then history.back() is executed in frame C, each history object looks like:

A: [A1, A2] current index = 1
B: [B1, B2] current index = 1
C: [C1, C2] current index = 0 (showing C1 content)

What will happen for each frame and each history object if browser UI's back/forward button
is pressed?
(again, this may be out of scope for the HTML spec, but everyone here has to implement something for each browser :)

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 19, 2016

Member

In summary, here are options:
3. <iframe> in Shadow DOM doesn't participate in parent's session history (no joint)
3.1 such <iframe> has its own session history list. history.go()/back()/forward() follows the list.
3.2 such <iframe> doesn't have its own session history list. history.go()/back()/forward() won't work, except history.go(0). (probably pushState()/replaceState() won't, either)

3.1:
pro: from the scripting perspective, it cleanly separates the session history, no leak.
con: breaks browser's back/forward buttons in a weird way once navigation is done in shadow iframe via History API (if browser implementation still keeps the joint session history from the whole frame tree and use it for back/forward navigation, as described in my previous comments)

3.2:
pro: can maintain browser back/forward button behvaior, as usage of any history API won't navigate
con: embedded page doesn't know whether history API restriction exists, and some may be broken.

One solution for the con of 3.1 could be that browser UI back/forward buttons don't follow the internal joint session history from the whole frame tree, but use the joint session history of top-level browsing context in the new world (i.e. session history exposed to the top-level window.history).
Quoting #184 (comment) from @smaug----

what should back button do? I guess nothing. That shouldn't be too bad.

But this is with the downside that the browser back/forward behavior is different from
when <iframe> is used in light DOM.

Implementation feedback for 3.1 (specific to Chrome/Blink) is that lots of current code assumes the joint session history and the top-level page has 1:1 mapping, quite a lot of rework has to be done to separate the list, and UX breakage of browser back/forward buttons is anticipated.

Member

TakayoshiKochi commented May 19, 2016

In summary, here are options:
3. <iframe> in Shadow DOM doesn't participate in parent's session history (no joint)
3.1 such <iframe> has its own session history list. history.go()/back()/forward() follows the list.
3.2 such <iframe> doesn't have its own session history list. history.go()/back()/forward() won't work, except history.go(0). (probably pushState()/replaceState() won't, either)

3.1:
pro: from the scripting perspective, it cleanly separates the session history, no leak.
con: breaks browser's back/forward buttons in a weird way once navigation is done in shadow iframe via History API (if browser implementation still keeps the joint session history from the whole frame tree and use it for back/forward navigation, as described in my previous comments)

3.2:
pro: can maintain browser back/forward button behvaior, as usage of any history API won't navigate
con: embedded page doesn't know whether history API restriction exists, and some may be broken.

One solution for the con of 3.1 could be that browser UI back/forward buttons don't follow the internal joint session history from the whole frame tree, but use the joint session history of top-level browsing context in the new world (i.e. session history exposed to the top-level window.history).
Quoting #184 (comment) from @smaug----

what should back button do? I guess nothing. That shouldn't be too bad.

But this is with the downside that the browser back/forward behavior is different from
when <iframe> is used in light DOM.

Implementation feedback for 3.1 (specific to Chrome/Blink) is that lots of current code assumes the joint session history and the top-level page has 1:1 mapping, quite a lot of rework has to be done to separate the list, and UX breakage of browser back/forward buttons is anticipated.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- May 19, 2016

Well, shadow DOM is a different beast, effectively trying to hide some implementation details of random elements, which is why I think it is totally fine that the session history API inside shadow iframes is just an API thing, not affecting UI. And the API there is exposed anyhow largely to keep existing pages which use history API working even inside shadow iframes.

3.1, if implemented so that shadow iframe's session history doesn't show up in the UI, should be quite easy to implement in Gecko, but if we need to somehow combine the light and various shadow histories, the implementation, and UI, becomes a lot harder to implement.

Well, shadow DOM is a different beast, effectively trying to hide some implementation details of random elements, which is why I think it is totally fine that the session history API inside shadow iframes is just an API thing, not affecting UI. And the API there is exposed anyhow largely to keep existing pages which use history API working even inside shadow iframes.

3.1, if implemented so that shadow iframe's session history doesn't show up in the UI, should be quite easy to implement in Gecko, but if we need to somehow combine the light and various shadow histories, the implementation, and UI, becomes a lot harder to implement.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 20, 2016

Member

@smaug---- thanks for the feedback. we are also concerned about compatibility of existing pages embedded in shadow iframes. So 3.2 is not a viable option for us, though with 3.1 some implementation difficulties are foreseen as you wrote.

@rniwa any opinions or ideas?

@travisleithead anything from Microsoft?

Member

TakayoshiKochi commented May 20, 2016

@smaug---- thanks for the feedback. we are also concerned about compatibility of existing pages embedded in shadow iframes. So 3.2 is not a viable option for us, though with 3.1 some implementation difficulties are foreseen as you wrote.

@rniwa any opinions or ideas?

@travisleithead anything from Microsoft?

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 26, 2016

Member

Let me try to move forward - we seem to get stuck, no perfect idea to solve all the constraints and concerns so far.

As we illustrated in #184 (comment) and #184 (comment), if we had separated joint session history to document and shadow iframes, it is expected that there would be inevitable browser back/forward button behavior inconsistency against user expectation.

If anyone cannot come up with a way to make it compatible with how back/forward button behaves on current browsers, we cannot mandate the separate list idea in V1.

As in @annevk's #184 (comment)

That kind of approach makes sense if you don't want to influence your container, but if you're a simple layout component that breaks expectations.

there's much possibility that current behavior is anticipated.

Any wisdom?
@rniwa @smaug---- @annevk @travisleithead @domenic

Member

TakayoshiKochi commented May 26, 2016

Let me try to move forward - we seem to get stuck, no perfect idea to solve all the constraints and concerns so far.

As we illustrated in #184 (comment) and #184 (comment), if we had separated joint session history to document and shadow iframes, it is expected that there would be inevitable browser back/forward button behavior inconsistency against user expectation.

If anyone cannot come up with a way to make it compatible with how back/forward button behaves on current browsers, we cannot mandate the separate list idea in V1.

As in @annevk's #184 (comment)

That kind of approach makes sense if you don't want to influence your container, but if you're a simple layout component that breaks expectations.

there's much possibility that current behavior is anticipated.

Any wisdom?
@rniwa @smaug---- @annevk @travisleithead @domenic

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- May 26, 2016

If anyone cannot come up with a way to make it compatible with how back/forward button behaves on current browsers, we cannot mandate the separate list idea in V1.

Why such limitation? Why does the shadow iframe need to show up in the browser UI?
One could also consider (conceptually) navigation in shadow iframes as replacing iframe with a new iframe[1]. That ends up removing the previous entries from session history and just add the new current one. Remember, user doesn't know what an iframe is. One way to consider this all is that, effectively session history is top level page navigations and state changes inside those which user can back<->forward. Iframe navigations are states within the top level page, not much different to pushState. And shadow iframes don't add such states.
([1] Note, webkit/blink are broken when doing dynamic changes. In some cases they end up loading session history entries to browsing contexts which never had such url loaded.
http://mozilla.pettay.fi/moztests/history2/Start.html is an old test for that.)

However if we do want to expose shadow iframe navigations in UI, UI could merge the various session history trees by looking at the creation time of the entries. That is anyhow the approach the HTML spec has taken for the normal DOM.
So, back button would end up checking which session history tree has the previous entry created most recently and navigate that tree.
Whether the shadow iframes should be exposed in the UI should be spec'ed.
Now that I think this some more, this shouldn't be too hard to implement in Gecko.
Session history transaction list would just contain entries for various session histories. And if history.go(...) was used, that would need to skip entries not for that particular session history.
UI would operate on the transaction list in the normal way.

One problem with merging various session history trees in UI is that top level page's history.back()/forward()/go() wouldn't map to it anymore. I guess that is fine.

If anyone cannot come up with a way to make it compatible with how back/forward button behaves on current browsers, we cannot mandate the separate list idea in V1.

Why such limitation? Why does the shadow iframe need to show up in the browser UI?
One could also consider (conceptually) navigation in shadow iframes as replacing iframe with a new iframe[1]. That ends up removing the previous entries from session history and just add the new current one. Remember, user doesn't know what an iframe is. One way to consider this all is that, effectively session history is top level page navigations and state changes inside those which user can back<->forward. Iframe navigations are states within the top level page, not much different to pushState. And shadow iframes don't add such states.
([1] Note, webkit/blink are broken when doing dynamic changes. In some cases they end up loading session history entries to browsing contexts which never had such url loaded.
http://mozilla.pettay.fi/moztests/history2/Start.html is an old test for that.)

However if we do want to expose shadow iframe navigations in UI, UI could merge the various session history trees by looking at the creation time of the entries. That is anyhow the approach the HTML spec has taken for the normal DOM.
So, back button would end up checking which session history tree has the previous entry created most recently and navigate that tree.
Whether the shadow iframes should be exposed in the UI should be spec'ed.
Now that I think this some more, this shouldn't be too hard to implement in Gecko.
Session history transaction list would just contain entries for various session histories. And if history.go(...) was used, that would need to skip entries not for that particular session history.
UI would operate on the transaction list in the normal way.

One problem with merging various session history trees in UI is that top level page's history.back()/forward()/go() wouldn't map to it anymore. I guess that is fine.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi May 27, 2016

Member

Why such limitation? Why does the shadow iframe need to show up in the browser UI?

The rationale for us is that "it works that way without shadow, why do we limit iframe history
would not show up in the browser UI?".

I'd say that having a separate history list for each iframe is a saner design
if we could do from scratch, as you also said, e.g. history.go() is very error prone API.
So I tried to have a working proposal, but failed to come up with a solution to provide
consistent behavior when history API in iframe (which has separate history list)
and browser global back/forward button are used.

For us, not including any shadow iframe history in browser UI back/forward button at all is not an option.

Now that I think this some more, this shouldn't be too hard to implement in Gecko.
Session history transaction list would just contain entries for various session histories. And if history.go(...) was used, that would need to skip entries not for that particular session history.
UI would operate on the transaction list in the normal way.

I thought a similar solution, and but once history API is used in shadow iframes and UI back button is used, it easily went to weird state or weird behavior, and we haven't come up with a clear solution.
If one of the two is exclusively used, it can be very consistent, but both are mixed, it can go some
weird state in a few steps.

Could you have a more formal proposal/algorithm how it sanely works?

Member

TakayoshiKochi commented May 27, 2016

Why such limitation? Why does the shadow iframe need to show up in the browser UI?

The rationale for us is that "it works that way without shadow, why do we limit iframe history
would not show up in the browser UI?".

I'd say that having a separate history list for each iframe is a saner design
if we could do from scratch, as you also said, e.g. history.go() is very error prone API.
So I tried to have a working proposal, but failed to come up with a solution to provide
consistent behavior when history API in iframe (which has separate history list)
and browser global back/forward button are used.

For us, not including any shadow iframe history in browser UI back/forward button at all is not an option.

Now that I think this some more, this shouldn't be too hard to implement in Gecko.
Session history transaction list would just contain entries for various session histories. And if history.go(...) was used, that would need to skip entries not for that particular session history.
UI would operate on the transaction list in the normal way.

I thought a similar solution, and but once history API is used in shadow iframes and UI back button is used, it easily went to weird state or weird behavior, and we haven't come up with a clear solution.
If one of the two is exclusively used, it can be very consistent, but both are mixed, it can go some
weird state in a few steps.

Could you have a more formal proposal/algorithm how it sanely works?

@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Jun 3, 2016

Contributor

I played a little bit with iframe but it looks like all browsers merge session history even for cross-origin navigations. Given that we're not certain special casing session history for iframe inside a shadow tree makes much sense but we don't have a strong opinion either way.

We're curious what @travisleithead and the rest of Microsoft folks think of this matter.

Contributor

rniwa commented Jun 3, 2016

I played a little bit with iframe but it looks like all browsers merge session history even for cross-origin navigations. Given that we're not certain special casing session history for iframe inside a shadow tree makes much sense but we don't have a strong opinion either way.

We're curious what @travisleithead and the rest of Microsoft folks think of this matter.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Jun 20, 2016

Member

I am now checking the status of all Shadow DOM v1 spec issues.
It looks that there is no interoperability risk if we do not have any special handling for session history for iframe in a shadow tree.

I would like to send an "Intent to ship: Shadow DOM v1" in Blink next week or later.
Regarding iframes in a shadow tree, if someone still think this is an important issue and there is a great risk for interoperability, please let me know that.

Member

hayatoito commented Jun 20, 2016

I am now checking the status of all Shadow DOM v1 spec issues.
It looks that there is no interoperability risk if we do not have any special handling for session history for iframe in a shadow tree.

I would like to send an "Intent to ship: Shadow DOM v1" in Blink next week or later.
Regarding iframes in a shadow tree, if someone still think this is an important issue and there is a great risk for interoperability, please let me know that.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Jun 20, 2016

Why wouldn't this be an important issue?
I'm still rather strongly against using the same session history for shadow iframes, since it causes really unexpected behavior.

And of course there isn't interoperability risk atm if there are no browsers shipping Shadow DOMv1, we can ship whatever random stuff at that point. The thing is that we need to get this kind of core issues sorted out before anyone ships, otherwise we'll end up to the same mess we have/had with previous Shadow DOM version. (Is it v0)

Why wouldn't this be an important issue?
I'm still rather strongly against using the same session history for shadow iframes, since it causes really unexpected behavior.

And of course there isn't interoperability risk atm if there are no browsers shipping Shadow DOMv1, we can ship whatever random stuff at that point. The thing is that we need to get this kind of core issues sorted out before anyone ships, otherwise we'll end up to the same mess we have/had with previous Shadow DOM version. (Is it v0)

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Jun 20, 2016

Member

@smaug---- Thank you for the feedback.

@TakayoshiKochi, @rniwa, @smaug----, @travisleithead
Could you discuss the pros and cons? We need to have a consensus.
As far as I can read, only Mozilla is still strongly against using the same session history for shadow iframes.
Other browser vendors do not have a strong opinion on this, I think.

Member

hayatoito commented Jun 20, 2016

@smaug---- Thank you for the feedback.

@TakayoshiKochi, @rniwa, @smaug----, @travisleithead
Could you discuss the pros and cons? We need to have a consensus.
As far as I can read, only Mozilla is still strongly against using the same session history for shadow iframes.
Other browser vendors do not have a strong opinion on this, I think.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Jun 20, 2016

I could rephrase that a bit. s/Mozilla/smaug/ and a question is here that why would we be ok to break encapsulation here when we're trying to achieve it elsewhere?

And functionally it is very surprising if the light dom can affect to the state of shadow iframes via history API, and even more surprising is if different shadow trees can affect to each others via history API.

I could rephrase that a bit. s/Mozilla/smaug/ and a question is here that why would we be ok to break encapsulation here when we're trying to achieve it elsewhere?

And functionally it is very surprising if the light dom can affect to the state of shadow iframes via history API, and even more surprising is if different shadow trees can affect to each others via history API.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Jun 20, 2016

Member

We understand your concern.

The point we'd argue is that "history API usages cause unexpected behavior" (current behavior) vs "splitting session history for shadow iframes causes unexpected behavior for browser UI back/forward navigation".

As I understand, no one has come up with a clear solution to the question posed in #184 (comment).
(I tried in several comments but failed, which is a shame)

In @smaug---- 's #184 (comment)

Session history transaction list would just contain entries for various session histories. And if history.go(...) was used, that would need to skip entries not for that particular session history.
UI would operate on the transaction list in the normal way.

"UI would operate on the transaction list" is the tricky part.
For example, when an iframe did history.go(-1), it would create a new transaction.
Then UI back button would forward the iframe?

I don't think there are infinite options how UI back button would behave in this case,
but there are only a few possible ways. As far as we explored for Blink, they were either
too complex to implement (if not impossible) or more confusing behavior to users.

The most plausible idea I came up with was that such separated session history for
shadow iframes would not be added to the list for UI back/forward button. This turned
out to be implementable, but I got comments internally that users would get confused.

So we are comparing cost/benefit of implementing the session history split vs
keeping the current behavior.

Keeping the current behavior, basically no cost, but has negative benefit that you already
mentioned several times. Pro is that there is no change in iframe and history API behavior,
in a sense.

On the other hand, splitting the session history, we foresee some non-ignorable implementation
cost (plus cost for inventing/defining a reasonable behavior), clear benefit for encapsulation,
and uncertain con for unexpected inconsistency for UI back/forward button behavior.

We are in the pragmatic position to favor the former.

One problem with merging various session history trees in UI is that top level page's history.back()/forward()/go() wouldn't map to it anymore. I guess that is fine.

I'd agree that UI back/forward list and top-level session can diverge, but this is not the
point we are against.

Member

TakayoshiKochi commented Jun 20, 2016

We understand your concern.

The point we'd argue is that "history API usages cause unexpected behavior" (current behavior) vs "splitting session history for shadow iframes causes unexpected behavior for browser UI back/forward navigation".

As I understand, no one has come up with a clear solution to the question posed in #184 (comment).
(I tried in several comments but failed, which is a shame)

In @smaug---- 's #184 (comment)

Session history transaction list would just contain entries for various session histories. And if history.go(...) was used, that would need to skip entries not for that particular session history.
UI would operate on the transaction list in the normal way.

"UI would operate on the transaction list" is the tricky part.
For example, when an iframe did history.go(-1), it would create a new transaction.
Then UI back button would forward the iframe?

I don't think there are infinite options how UI back button would behave in this case,
but there are only a few possible ways. As far as we explored for Blink, they were either
too complex to implement (if not impossible) or more confusing behavior to users.

The most plausible idea I came up with was that such separated session history for
shadow iframes would not be added to the list for UI back/forward button. This turned
out to be implementable, but I got comments internally that users would get confused.

So we are comparing cost/benefit of implementing the session history split vs
keeping the current behavior.

Keeping the current behavior, basically no cost, but has negative benefit that you already
mentioned several times. Pro is that there is no change in iframe and history API behavior,
in a sense.

On the other hand, splitting the session history, we foresee some non-ignorable implementation
cost (plus cost for inventing/defining a reasonable behavior), clear benefit for encapsulation,
and uncertain con for unexpected inconsistency for UI back/forward button behavior.

We are in the pragmatic position to favor the former.

One problem with merging various session history trees in UI is that top level page's history.back()/forward()/go() wouldn't map to it anymore. I guess that is fine.

I'd agree that UI back/forward list and top-level session can diverge, but this is not the
point we are against.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Jun 20, 2016

The most plausible idea I came up with was that such separated session history for
shadow iframes would not be added to the list for UI back/forward button.

This is what I'd do. Users don't know what an "iframe" is. and iframe could be implement by the page using just random div element which doesn't add anything to the session history.

This turned
out to be implementable, but I got comments internally that users would get confused.

Why? If user doesn't even know there is an iframe to navigate back<->forward, what is there to get confused?

I would, at least initially, make shadow iframes to have separate session history so that we don't break existing pages using session history, yet don't leak information about shadow iframes to other shadow iframes or light DOM and not expose shadow history in UI.
Then, if we later figure out that shadow iframe history needs to be exposed to the UI, we try to come up with some solution.
That is my pragmatic proposal for this issue.

(In my mind not fixing session history for shadow DOM case is similar to the v0 shadow DOM where is-in-document issue was totally not figured out at all.)

smaug---- commented Jun 20, 2016

The most plausible idea I came up with was that such separated session history for
shadow iframes would not be added to the list for UI back/forward button.

This is what I'd do. Users don't know what an "iframe" is. and iframe could be implement by the page using just random div element which doesn't add anything to the session history.

This turned
out to be implementable, but I got comments internally that users would get confused.

Why? If user doesn't even know there is an iframe to navigate back<->forward, what is there to get confused?

I would, at least initially, make shadow iframes to have separate session history so that we don't break existing pages using session history, yet don't leak information about shadow iframes to other shadow iframes or light DOM and not expose shadow history in UI.
Then, if we later figure out that shadow iframe history needs to be exposed to the UI, we try to come up with some solution.
That is my pragmatic proposal for this issue.

(In my mind not fixing session history for shadow DOM case is similar to the v0 shadow DOM where is-in-document issue was totally not figured out at all.)

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Jun 20, 2016

Member

This turned
out to be implementable, but I got comments internally that users would get confused.

Why? If user doesn't even know there is an iframe to navigate back<->forward, what is there to get confused?

Suppose there are 2 components, one with Shadow DOM and the other without Shadow DOM
otherwise identical. Even when history API is used only within <iframe> in the components,
once history API is used, browser UI back/forward button behaves differently if shadow-iframe
history isn't exposed to UI. Users cannot distinguish them from what they appear. Therefore
it gets confusing.

I don't have the backing data to support this, such as how frequently this pattern would be used in real world, unfortunately. But I guess the situation happens for polyfilled Shadow DOM and native Shadow DOM for the time being until everyone implements.

Having separate list and not exposing history to UI doesn't come as free. Even when we can
ignore the cost for implementation, users may have to pay the cost for incompatible behavior,
in turn for developer (history API user, component developer)'s convenience and sanity.

So the question is whether we (browser implementors) can impose the (possible) pain to the users,
or the benefit of the separation wins against the pain.

Member

TakayoshiKochi commented Jun 20, 2016

This turned
out to be implementable, but I got comments internally that users would get confused.

Why? If user doesn't even know there is an iframe to navigate back<->forward, what is there to get confused?

Suppose there are 2 components, one with Shadow DOM and the other without Shadow DOM
otherwise identical. Even when history API is used only within <iframe> in the components,
once history API is used, browser UI back/forward button behaves differently if shadow-iframe
history isn't exposed to UI. Users cannot distinguish them from what they appear. Therefore
it gets confusing.

I don't have the backing data to support this, such as how frequently this pattern would be used in real world, unfortunately. But I guess the situation happens for polyfilled Shadow DOM and native Shadow DOM for the time being until everyone implements.

Having separate list and not exposing history to UI doesn't come as free. Even when we can
ignore the cost for implementation, users may have to pay the cost for incompatible behavior,
in turn for developer (history API user, component developer)'s convenience and sanity.

So the question is whether we (browser implementors) can impose the (possible) pain to the users,
or the benefit of the separation wins against the pain.

@trusktr

This comment has been minimized.

Show comment
Hide comment
@trusktr

trusktr Jun 28, 2016

I haven't read too far past #184 (comment), but for number 3 to be possible, which is

Design iframe elements differently inside shadow trees so they do not put properties on the global object and don't interfere with the history of the browsing context. Could be quite a bit of work, I haven't had time to investigate yet.

then this means that Nodes that are distributed into a ShadowDOM tree (into slot elements) must somehow be aware that they have been distributed into a ShadowDOM tree (even if the tree is closed) in order to decide to behave differently than when not in a ShadowDOM tree. There is currently no part of webcomponents spec (as far as I'm aware, please let me know if otherwise) that would explain how a Node can possibly be aware of such a thing as having been distributed into a shadow tree.

So, this leads me to link here to an idea I made earlier: distributedCallback. The slot argument to distributedCallback is null when the shadow tree that the element is distributed into is closed. This method could possibly be the explanation as to how an <iframe> can possibly know to behave differently inside a shadow tree, if that route is taken with iframes.

trusktr commented Jun 28, 2016

I haven't read too far past #184 (comment), but for number 3 to be possible, which is

Design iframe elements differently inside shadow trees so they do not put properties on the global object and don't interfere with the history of the browsing context. Could be quite a bit of work, I haven't had time to investigate yet.

then this means that Nodes that are distributed into a ShadowDOM tree (into slot elements) must somehow be aware that they have been distributed into a ShadowDOM tree (even if the tree is closed) in order to decide to behave differently than when not in a ShadowDOM tree. There is currently no part of webcomponents spec (as far as I'm aware, please let me know if otherwise) that would explain how a Node can possibly be aware of such a thing as having been distributed into a shadow tree.

So, this leads me to link here to an idea I made earlier: distributedCallback. The slot argument to distributedCallback is null when the shadow tree that the element is distributed into is closed. This method could possibly be the explanation as to how an <iframe> can possibly know to behave differently inside a shadow tree, if that route is taken with iframes.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Jun 28, 2016

Possible answer B: the new history state replaces Entry3.

Entry1: A1
Entry2: A2 + B1 + C1
Entry3': A2 + B2 + C1
Entry4: A2 + B2 + C2

I'm leaning to this. (I got the same idea and then realized that perhaps it was proposed already)
The replacement happens only when history.back()/go(<0) is explicitly used in shadow browsing contexts. If that doesn't happen, the UI works just the way it works now, since there is the session history transaction list of session history entry trees

Possible answer B: the new history state replaces Entry3.

Entry1: A1
Entry2: A2 + B1 + C1
Entry3': A2 + B2 + C1
Entry4: A2 + B2 + C2

I'm leaning to this. (I got the same idea and then realized that perhaps it was proposed already)
The replacement happens only when history.back()/go(<0) is explicitly used in shadow browsing contexts. If that doesn't happen, the UI works just the way it works now, since there is the session history transaction list of session history entry trees

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Jun 30, 2016

Member

Thanks @smaug---- for giving more thought on this.

How feasible do you feel for implementing it in Gecko/Firefox?
I guess it is implementable in Chromium/Blink, but with much effort - it needs huge refactoring;)

I'm curious what do you think if you get back to Entry3' state now, and if iframe B navigates B3,
a new entry (Entry3'' = A2 + B3 + C1) will be created. Usually going back the history and make a new
navigation, will prune the old forward history, in this case Entry4, which means we lose "C2".
But still in iframe C's history list, C2 exists, so history.forward() in C could navigate to C2.
Do you think you allow UI forward button to make C1->C2 navigation (with keeping B3 in
iframe B) in this case?

Entry1: A1
Entry2: A2 + B1 + C1
Entry3': A2 + B2 + C1
Entry3'': A2 + B3 + C1 <== new entry after Entry3'
Entry4: A2 + B2 + C2 <== ???

Member

TakayoshiKochi commented Jun 30, 2016

Thanks @smaug---- for giving more thought on this.

How feasible do you feel for implementing it in Gecko/Firefox?
I guess it is implementable in Chromium/Blink, but with much effort - it needs huge refactoring;)

I'm curious what do you think if you get back to Entry3' state now, and if iframe B navigates B3,
a new entry (Entry3'' = A2 + B3 + C1) will be created. Usually going back the history and make a new
navigation, will prune the old forward history, in this case Entry4, which means we lose "C2".
But still in iframe C's history list, C2 exists, so history.forward() in C could navigate to C2.
Do you think you allow UI forward button to make C1->C2 navigation (with keeping B3 in
iframe B) in this case?

Entry1: A1
Entry2: A2 + B1 + C1
Entry3': A2 + B2 + C1
Entry3'': A2 + B3 + C1 <== new entry after Entry3'
Entry4: A2 + B2 + C2 <== ???

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Jul 21, 2016

Member

I am now triaging issues. Is there any update on this issue?

Member

hayatoito commented Jul 21, 2016

I am now triaging issues. Is there any update on this issue?

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Sep 13, 2016

Member

@smaug---- any update on this?

Member

TakayoshiKochi commented Sep 13, 2016

@smaug---- any update on this?

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Sep 13, 2016

Sorry, no. I'm hoping this can be chatted during TPAC. But I'll try to look at this before that anyhow.

Sorry, no. I'm hoping this can be chatted during TPAC. But I'll try to look at this before that anyhow.

@TakayoshiKochi

This comment has been minimized.

Show comment
Hide comment
@TakayoshiKochi

TakayoshiKochi Sep 14, 2016

Member

Thanks for the update. I'll be at TPAC next week.
Let's chat about this.

Member

TakayoshiKochi commented Sep 14, 2016

Thanks for the update. I'll be at TPAC next week.
Let's chat about this.

@hayatoito

This comment has been minimized.

Show comment
Hide comment
@hayatoito

hayatoito Nov 30, 2017

Member

@TakayoshiKochi , @rniwa
Is there any progress on this? I think Mozilla wants to know that status of this issue.

Member

hayatoito commented Nov 30, 2017

@TakayoshiKochi , @rniwa
Is there any progress on this? I think Mozilla wants to know that status of this issue.

@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Dec 3, 2017

Contributor

We didn't have a time to discuss it at TPAC 2017.

Contributor

rniwa commented Dec 3, 2017

We didn't have a time to discuss it at TPAC 2017.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Dec 6, 2017

This was discussed at TPAC 2016, and the approach we agreed to try out was going to be implemented in webkit, IIRC, to get more experience on this issue before spec'ing it.

This was discussed at TPAC 2016, and the approach we agreed to try out was going to be implemented in webkit, IIRC, to get more experience on this issue before spec'ing it.

@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Dec 6, 2017

Contributor

Yeah, sorry, I haven't had a time to implement it. If Gecko or some other engine is interested in implementing the proposed approach, please move ahead & give us any feedback.

Contributor

rniwa commented Dec 6, 2017

Yeah, sorry, I haven't had a time to implement it. If Gecko or some other engine is interested in implementing the proposed approach, please move ahead & give us any feedback.

@annevk

This comment has been minimized.

Show comment
Hide comment
@annevk

annevk Dec 7, 2017

Member

So do you disable <iframe> altogether or are we going to run into compatibility issues?

Member

annevk commented Dec 7, 2017

So do you disable <iframe> altogether or are we going to run into compatibility issues?

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Dec 7, 2017

Yeah, I don't know what blink and webkit do now. Probably something somewhat random, which exposes the existence of shadow DOM to the outside world by using the same session history.

Did anyone take pictures of the plan we draw 2016?
It was separate session history for shadow iframes, since otherwise iframes in different shadow DOMs could end up affecting each others.

Yeah, I don't know what blink and webkit do now. Probably something somewhat random, which exposes the existence of shadow DOM to the outside world by using the same session history.

Did anyone take pictures of the plan we draw 2016?
It was separate session history for shadow iframes, since otherwise iframes in different shadow DOMs could end up affecting each others.

@smaug----

This comment has been minimized.

Show comment
Hide comment
@smaug----

smaug---- Dec 7, 2017

But, if there are two iframe in a shadow DOM, should those use the same session history?

But, if there are two iframe in a shadow DOM, should those use the same session history?

@rniwa

This comment has been minimized.

Show comment
Hide comment
@rniwa

rniwa Feb 19, 2018

Contributor

We're willing to make backwards incompatible changes on our end to match the new spec if any.

Contributor

rniwa commented Feb 19, 2018

We're willing to make backwards incompatible changes on our end to match the new spec if any.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment