Skip to content

<a download> is a navigation; how does it interact with the navigation API? #76

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

Closed
domenic opened this issue Mar 16, 2021 · 13 comments · Fixed by #218
Closed

<a download> is a navigation; how does it interact with the navigation API? #76

domenic opened this issue Mar 16, 2021 · 13 comments · Fixed by #218

Comments

@domenic
Copy link
Collaborator

domenic commented Mar 16, 2021

Background: whatwg/html#5548, which is basically about how <a download> is a type of navigation, even though the specs currently don't treat it as such.

This means the navigation API should have a well-defined interaction with such downloads, in the spec and tests. Speccing this properly might require fixing whatwg/html#5548.

My instinct is that such downloads should not trigger the navigation API's navigate event.

@Yay295
Copy link

Yay295 commented Mar 16, 2021

If it did trigger a navigate, would that allow you to change the file being downloaded? I suppose some people might find that useful. I do think fixing the spec probably needs to happen first though, because if it's just a navigate then we don't need to treat it differently, but if it's something different, then it probably does need to be treated differently.

@tbondwilkinson
Copy link
Contributor

I think that a "navigate" has to enter into the history stack. If it doesn't change something about history, it's not a navigate.

Clicking on a link to open in a new tab, I think, is not a navigate (for instance)

@domenic
Copy link
Collaborator Author

domenic commented May 27, 2021

There are essentially two cases here:

  1. We know it's a download, because it used <a download> or the user right-clicke and chose download. In that case I think we're agreed no navigate event should fire.

  2. We don't know it's a download until we hit the network and get back Content-Disposition: attachment. In this case we're going to fire the navigate event anyway (because we haven't hit the network yet so we have no information to prevent us from doing so). And if the page does event.respondWith() then we'll never hit the network and the download-ness will be ignored.

    This does mean that if you navigate to a Content-Disposition: attachment page and the navigate event handler does neither event.respondWith() or event.preventDefault(), you'll end up getting a navigate event for something that never enters the history stack. I don't see a real way to avoid this. Probably it's OK though.

@Yay295
Copy link

Yay295 commented May 27, 2021

I agree that it's probably fine. Just need to put a note in the documentation so people know to expect it, or can find out what's going on.

@samthor
Copy link
Contributor

samthor commented Aug 19, 2021

Should this be merged into #137?

@domenic
Copy link
Collaborator Author

domenic commented Aug 19, 2021

They're slightly different. #137 is about what happens if you do a non-download navigation but then the server sends Content-Disposition: attachment, which forces your browser into a download. In that case we'll definitely have to fire the navigate event since we don't know ahead of time what the server is going to do.

This case is about <a download> where you know that a download is being performed ahead of time. We have the option of not firing the navigate event in that case (just like we don't fire the navigate event when someone does, e.g., right-click save image as).

@domenic domenic added this to the Might block v1 milestone Nov 4, 2021
@smaug----
Copy link

For consistency there should be navigate in both cases but I guess also some notification that the navigation stopped/was cancelled.

@annevk
Copy link

annevk commented Mar 9, 2022

One scenario I'm concerned about is when <a download> is used and you end up with a resource on another origin that does not have Content-Disposition. Do browsers have uniform behavior there? (I vaguely recall that resulting in a non-download navigation in some browsers, but I'm not sure.) Mainly raising this because of @smaug----'s suggestion around "navigation stopped" above.

I think a navigate event makes sense. Perhaps with a download attribute that reveals the desired filename? I.e., give the same context the navigate algorithm gets. (I could see waiting with adding the attribute to see if there's demand first.)

@domenic
Copy link
Collaborator Author

domenic commented Mar 9, 2022

I'm torn on whether to expose a boolean or filename in v1.

On the one hand, it's probably helpful for developers to avoid handling <a download>s in their navigate handlers.

On the other hand, if we have navigateEvent.download, people might be surprised when Content-Disposition: attachment-caused downloads end up with navigateEvent.download === false.

Maybe if we gave it a really explicit name, like knownAheadOfTimeDownload(Filename) or downloadViaLink or something.

@domenic domenic changed the title <a download> is a navigation; how does it interact with app history? <a download> is a navigation; how does it interact with the navigation API? Mar 14, 2022
@domenic
Copy link
Collaborator Author

domenic commented Mar 17, 2022

@annevk, @smaug----, @natechapin and I discussed this offline. We were roughly agreed on the plan of firing a navigate event for <a download> cases. (Or future analogous APIs such as #82.) And, per #137, we cannot fire any navigatesuccess or similar for such downloads, if they succeed.

The remaining discussion is then whether and how to signal the fact that a given navigation is attempting to download, to the navigate event handler. We came up with navigateEvent.requestDownload, which works as follows:

  • <a href="foo">: navigateEvent.requestDownload === null
  • <a href="foo" download>: navigateEvent.requestDownload === ""
  • <a href="foo" download="bar">: navigateEvent.requestDownload === "bar".

(I was voting for false/true/"bar", but others disliked multi-typed values.)

We think this name communicates that (a) it only covers "requested" downloads, not all downloads; e.g. it doesn't cover Content-Disposition: attachment cases (which we cannot know about at the time of the navigate event); (b) the browser might not download anyway, even if you do nothing with the event. This is because of whatwg/html#7718 (which is not specified), and perhaps also because of the part of the spec which says "Optionally, the user agent may return false, if it believes doing so would safeguard the user from a potentially hostile download".

There is an additional question as to whether you can transitionWhile() on such download-triggered navigate events. Although we could vaguely imagine some use cases for this, we decided to just throw on such transitionWhile()s for now, until or unless we get more concrete signals from developers that converting downloads into same-document navigations would be useful.

I will work on spec/implementation/test updates for this soon! Although the spec updates are probably going to be a bit vague until we improve the general HTML download spec, which is blocked on whatwg/html#6315.

@domenic
Copy link
Collaborator Author

domenic commented Mar 21, 2022

There is an additional question as to whether you can transitionWhile() on such download-triggered navigate events. Although we could vaguely imagine some use cases for this, we decided to just throw on such transitionWhile()s for now, until or unless we get more concrete signals from developers that converting downloads into same-document navigations would be useful.

In Matrix @annevk pointed out that expanding this in the future would change canTransition from false to true, which might have more significant compat risks than changing transitionWhile() from throwing to not-throwing.

This inclines me toward trying to see how hard it is to implement with transitionWhile() allowed, and if it's easy, then we should allow it in v1 after all.

@domenic
Copy link
Collaborator Author

domenic commented Mar 23, 2022

What does right click > Save Link As... do?

I think it should not fire any event. The current HTML spec does not distinguish between these possibilities but allowing interception of that UI gesture seems not-great.

domenic added a commit that referenced this issue Mar 23, 2022
domenic added a commit that referenced this issue Mar 23, 2022
@domenic
Copy link
Collaborator Author

domenic commented Mar 24, 2022

After writing up some small usage examples I prefer the name "downloadRequest" to "requestDownload". "request download" sounds like a verb or method name. "downloadRequest" is also more consistent with "hashChange".

domenic added a commit that referenced this issue Mar 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants