observablehq / stdlib

The Observable standard library.
https://observablehq.com/@observablehq/standard-library
ISC License
969 stars 83 forks source link

A built-in for passing in data from the URL. #66

Closed mbostock closed 6 years ago

mbostock commented 6 years ago

It’d be nice if there were a way to encode information in the URL, say using the query string, and expose that information in the notebook. Currently the parent URL is not accessible to the notebook.

Maybe DOM.href would just be the URL in the address bar as a string?

jashkenas commented 6 years ago

I'm not sure how relevant the whole URL as a string would be to notebooks — but the queryString (ideally, parsed), and the fragment certainly would be.

Perhaps:

... to mirror the window.location API?

tmcw commented 6 years ago

My gut here is... 😟I'm a little worried about making any part of the page URL accessible to the notebook. I totally see how it could be great for certain notebooks to embed / share data or something like that, but making the entire hash or querystring user-accessible sounds like it could make future UI changes tricky, like if we start using hashes to anchor people to inline comments, or the search portion of the UI to pin to a version in history.

Maybe we could only pass down a part of the querystring? Or have some other well-defined subset of the location object that we could mark as 'in userspace' but be confident that it won't pwn future system features?

jashkenas commented 6 years ago

It's true that we already use the location.hash to anchor link to specific named cells: https://beta.observablehq.com/@mbostock/five-minute-introduction#slider

mbostock commented 6 years ago

The URL of a notebook is not a secret. I don’t see that hiding the current URL from the notebook buys us much, or conversely that exposing it overcommits. We could even pass through the window.location.search and window.location.hash to the iframe src directly, so that they work as-is within the worker iframe without a new built-in (though we’d want to prevent the query string from breaking the CDN cache).

That said, we could instead provide a more limited mechanism to pass data through the URL if desired. Like, say, special-casing the query parameter, and exposing that as DOM.query. Then in /@mbostock/my-notebook?query=foo, DOM.query would be the string "foo".

aman-tiwari commented 6 years ago

I would love to be able to get to the query string so that I could send people links to visualizations with certain notebook parameters filled in (for instance, as location hashes on a map, or parameters for a webgl vis).

mbostock commented 6 years ago

As discussed in the most-recent changelog, we’ve fixed the document’s base URL to include the query string. Strangely, there doesn’t seem to be a more obvious way to access the document’s base URL from JavaScript. The most concise way we’ve found is by constructing an A element, setting the href attribute to the empty string, then looking at the element’s search property (if you’re just interested in the query string):

Object.assign(document.createElement("a"), {href: ""}).search

Or more concisely:

html`<a href>`.search

This can then be passed to the URLSearchParams constructor, like so:

new URLSearchParams(html`<a href>`.search)

You can see this in use in my Function Plot notebook.

aman-tiwari commented 6 years ago

Ah okay, thank you!

simonw commented 5 years ago

I have a use-case for this which isn't covered by the html`<a href>`.search workaround.

I want to build a Notebook that uses client-side OAuth to authenticate against an API. The API I am using redirects back to my notebook like this:

https://beta.observablehq.com/d/6bd2b8b749afe254#token_type=Bearer&access_token=7230017A3E7D5B33A003250756

I'd like to be able to read the fragment hash (to get the token) and then store that token in localStorage.

This is a really nice way of working with APIs like this: because the access token is not passed in the querystring there is no chance of it accidentally ending up in a log file somewhere.

But... in order to do this, I need to be able to read the #token_type=Bearer&access_token=... bit that was passed in the URL.

simonw commented 5 years ago

I totally get @tmcw's concern above about wanting to preserve the # namespace for potential future Observable features.

Maybe whitelist token_type and access_token? That's a bit obscure though.

Better suggestion: define a reserved prefix (obs. or _obs. for example) and allow through everything else. So for the following URL:

https://beta.observablehq.com/d/6bd2b8b749afe254#token_type=Bearer&access_token=7230017A3E7D5B33A003250756&obs.commentref=923449734

The notebook could access DOM.location.hash and would get back this string:

token_type=Bearer&access_token=7230017A3E7D5B33A003250756

With the obs.commentref=923449734 bit stripped out.