-
Notifications
You must be signed in to change notification settings - Fork 312
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
ServiceWorkerClient to Client #588
Comments
@mounirlamouri, does implicit |
It seems like an interesting idea to make Client available everywhere, I had not actually considered that. I was mostly suggesting to remove the "ServiceWorker" prefix since they were scoped to service workers anyway. But this makes sense if we want the ability to open new windows using I'm not sure this satisfies the constructor camp as the user agent will still need to use the token approach to construct these objects in a way that works for user agents (e.g. otherwise there's no way to get one that returns "worker" for I don't really like |
Out of curiosity, why are we allowing creation of window clients but not worker ones? Why are we trying to squash windows and workers into a single class? visibilityState, focused, frameType, and focus() all seem inapplicable to workers. Seems better to move the rest of the properties to a base class and have a WindowClient, or similar. Real Talk about constructors: In general with constructors, all I want you to do is outline a clear story for how the objects the author sees came into being. If that can be "the browser called I don't like the idea of It seems more likely you want a design where |
There is something else that irks me about this design. It does not considers workers fully (we've been seeing this a lot with service workers). To create a worker, you use It seems weird therefore that for the equivalent case for |
I thought the
We can do subclassing but then we'd have to define |
Before I respond to specific points, I really should have provided example usage code: Responding to a push message: self.addEventListener('push', function(event) {
if (event.message.data == 'new-chat-message') {
fetch('/latest-messages').then(r => r.json()).then(function(data) {
clients.getAll().then(function(clients) {
// filter clients to relevant urls
clients = clients.filter(c => new URL(c.url).pathname.indexof('/chat/') === 0);
// tell them about the new messages
clients.forEach(c => c.postMessage(data));
// if we don't have a focused & visible window, show notification
if (!clients.find(c => !c.hidden && c.focused)) {
registration.showNotification(data[0].username, {
body: data[0].message,
icon: data[0].avatarURL,
tag: 'chat-' + data[0].username
});
}
});
});
}
}); Responding to a notification activation: self.addEventListener('notificationclick', function(event) {
// chat notification clicked
if (event.notification.tag.indexOf('chat-') === 0) {
clients.getAll().then(function(clients) {
// look for relevent window, or make a new one
var client = clients.find(c => new URL(c.url).pathname.indexof('/chat/') === 0 && c.type == 'window')
|| new Client('/chat/');
// focus it
client.focus();
});
}
}; |
Ohh, I thought that's what you were asking for. Happy to keep it ServiceWorker specific.
If we're making this ServiceWorker specific, can we make
I was looking to solve this issue: client.focused; // false
client.focus().then(function() {
client.focused; // still false
}); But perhaps "it's a snapshot, deal with it" is good enough. The focus method resolving is indication enough. |
Given this, I'd much rather go with this and introduce something like |
Why?
Yes, definitely. |
If
Assuming you mean the above, it isn't too bad right now. If your code encounters a Adding stuff to Assuming we went with the above, what API would you prefer for opening a window, considering a constructor here is undesirable? |
Good point. Very interesting. Is there a scenario when getAll() is useful without filtering by type? Your examples seem like they would benefit from a filter on window. Perhaps
If I'm understanding correctly, any new window clients will be added to the collection of all clients, right? If so, then I think the former seems a bit nicer, since |
There's already (includeUncontrolled, ugh, maybe includeUnclaimed if we're going for |
Incorporated the result of the discussion up to the point: 868eaea. Summary:
|
@domenic It seems like a slam-dunk exceptional case, but |
No need for a |
sgtm |
Also make sure the default is to return only window clients.
Sounds good to me, unless
is for security reasons or something.
Interesting; didn't know Web IDL was covariant. |
Addressed: 04d5734.
Yes it does so. The default (without options attribute) returns only controlled window clients indeed. |
/cc @irori @KenjiBaheux |
A few follow up questions.
client.focus().then(function() {
client.focused === false;
}); It's very odd to have a method that can change the state of an object on an object that is meant to be a snapshot.
clients.getAll().then(function(clients) {
clients.forEach(function(c) {
c.focus();
});
}); If this code is called from inside a
|
|
What about having:
We could even return a new WindowClient in the Promise. It feels less odd to me to have the method outside of the snapshot object. |
It should reject rather than throw.
God no :D Let's keep it simple for now, we can add to it later. |
Had a quick chat with @annevk in IRC. Thinking about usability, I think people will look for methods that act on the client, on the client object. How about: client.focus().then(function(updatedClient) {
updatedClient.focued === true;
}) Basically, your idea of returning an updated snapshot, but leaving the focus method on client. |
Just had a chat with @mounirlamouri. To clarify,
When it comes to permission, it'll probably be a MAY in the spec. As in "If the call is not within the context of an interaction event, the browser MAY reject" |
For It wasn't clear we wanted to do more there (e.g. try and abort the navigation once we realize it's not going to be controlled, etc). I erred on the side of thinking of it as just a |
So @mounirlamouri had a great use-case. A news aggregation app may wish to show a notification about breaking news, which when clicked, opens the news website with the story. This would be another origin. For other-origin URLs we can resolve with null, rather than a client object. I don't think there's any problem opening a window outside the scope of the SW & same origin, we can return a client object for that. |
Should we close that issue and open specific ones if needed? |
Yeah, will continue in #602 |
These shouldn't be specific to ServiceWorker, and should move into the Fetch spec.
These bits stay the same:
Here's the different bits:
The properties of a client do not change after construction unless update is called.
The constructor takes a
url
andoptions
. The options are a bit useless at the moment, as it should throw iftype
is set to anything other thanwindow
. Iftype
iswindow
(the default), the user agent is requested to open a new tab/window. This may depend on a user-interaction event, aswindow.open
does now.update causes
visibilityState
,focused
,url
, andserviceWorkerRegistration
to refresh to the client's current values. If the client hasn't yet succeeded/failed to open, it waits. It rejects if the client is no longer running, or failed to ever run. It doubles as a ready method. Question: Do we need a ready method regardless?visibilityState is from Page Visibility. It reports
hidden
for non-window types.focused is the result of
hasFocus()
from the focus management APIs. Question: Or should it be true if the browser window has focus and the containing tab is active? As in, should it be true for a top-level client if a contained client (such as an iframe) has focus? Should it be true for a frame in a frameset even if focus is in one of the other frames in the frameset? Should it be true for a top-level client if docked devtools has focus?url is the current url of the client. This is the script url for workers, but can change throughout the life of a window via hash changes and
pushState
. Question: Or should this be the creation url, therefore static for windows too? Once we getclients.claim()
, it'll be taking over clients based on creation url sopushState
cannot allow pages to "jump scope" and be claimed by a registration they otherwise wouldn't be.frameType comes from the fetch spec. It lets you tell iframes apart from top-level windows.
type lets you tell windows apart from different types of worker.
serviceWorkerRegistration lets you know if the client is controlled by a worker or not.
postMessage does what you'd expect.
focus rejects if the type is not "window". Calls
window.focus()
on the related window. Resolves if successful, rejects otherwise. This may depend on a user-interaction event. Question: Should this implicitly call update?I thought about having separate constructors rather than a
type
attribute, such asWindowClient
,WorkerClient
etc etc, but that means we'd have more constructors that'd throw, and I know how y'all hate that!The text was updated successfully, but these errors were encountered: