- From: Dael Jackson <daelcss@gmail.com>
- Date: Mon, 29 Aug 2022 19:59:42 -0400
- To: www-style@w3.org
=========================================
These are the official CSSWG minutes.
Unless you're correcting the minutes,
Please respond by starting a new thread
with an appropriate subject line.
=========================================
CSS Highlight API
-----------------
- dandclark explained the current 3 proposals for issue #7513
(Approaches for dispatching highlight pointer events) and
indicated a preference for option C which is having two events,
one for highlight and one for DOM.
- emilio introduced a fourth option to add an API to answer if a
certain point intersects a highlight. There was significant
discussion around the feasibility of the approach and
interest in investigating more to see if some concerns could
be mitigated. emilio added more details to github after the
meeting:
https://github.com/w3c/csswg-drafts/issues/7513#issuecomment-1201631397
- TabAtkins raised the possibility of changing option A where
each highlight gets its own event to require registration
before dispatch.
- Discussion will continue on github to determine the feasibility
of these new options.
- Having an API to return what highlights intersected broadly made
sense as a solution to issue #7512 (Is a HighlightPointerEvent
type needed?) however the final discussion will need to wait on a
decision for issue #7513.
===== FULL MEETING MINUTES ======
Agenda: https://github.com/w3c/csswg-drafts/projects/30
Scribe: TabAtkins
CSS Highlight API
=================
Approaches for dispatching highlight pointer events
---------------------------------------------------
github: https://github.com/w3c/csswg-drafts/issues/7513
dandclark: So pointer events with highlights, this is about making
highlight pseudos interactive like for a spellchecker
dandclark: First question is how do we dispatch these events, what's
the event order
dandclark: I assume the highlight object is the right thing to
receive the event, rather than the individual ranges
dandclark: If I have a bunch of ranges on a single highlight, I
probably want to do the same thing for each
dandclark: seems silly to have to set an event listener on each
range, especially as the highlight moves
dandclark: and when considering dispatches, need to consider there
can be multiple types of highlights, and possibly
overlapping
dandclark: like a find-on-page that emphasizes and scrolls, and also
a spellcheck that underlines misspelled words and shows
spelling suggestions
dandclark: might want one of those to eat the click, so spelling
error can win over find-on-page
dandclark: so I can talk about a few approaches
dandclark: In the issue, version A is each highlight gets its own
event, in descending priority order
dandclark: They can be cancelable, so the default is to advance to
the next highlight, and you can preventDefault()
dandclark: Suspicious to fire an arbitrary number of events for a
single action though
dandclark: Approach B is a single event for the top priority
highlight, define event path so it goes through other
highlights, then bubbles to dom tree
dandclark: this seems like pretty normal approach. But there's a web
compat problem
dandclark: Currently pointer events can only ever be an element
dandclark: but now suddenly they can have non-element targets
dandclark: so might break assumptions
dandclark: The Edge explainer suggests lying about the event target
to get around this
dandclark: Thinking about it more, think it's not the right approach
dandclark: Approach C is a combo. We dispatch two events, one for
highlights, one for dom tree. Highlight one propagates
through overlapping highlights. If it's not
preventDefault'd by the end, we fire a new one on the dom
tree
dandclark: That dual-event approach is where I lean now
emilio: Rather than messing with the dom events and re-targeting, can
we add an API to highlight that tells "is point X
intersecting the highlight?"? seems like that would let you
do what you want with regular dom events
emilio: you handle the pointer event and ask the highlights if the
point overlaps, and just deal with normal dom event
emilio: Seems simpler but still gives all the use-cases
emilio: If you have two objects, handling pointer event on one or the
other...
emilio: the normal element pointer event should still work even if
you click on the highlight
emilio: Seems simpler and less risky, and doesn't introduce new event
model
emilio: and will work with touch events, etc
emilio: Curious if it's been considered?
TabAtkins: So assumption is you'd iterate through all your highlights
and check?
emilio: Yes. and they can check if it's been defaulted, you can deal
with the order yourself, etc.
dandclark: This seems useful for- given I have a click with an
offset, show me all the highlights under this location? or
go through each highlight in the registry and check?
dandclark: Can def see if there's a pointer event handler on the
body, and I get an event, could ask platform for all the
highlights at this point
<emilio> boolean intersects(long clientX, long clientY)
<bkardell> emilio: that is on highlight?
emilio: Was thinking about method on the highlight object
emilio: so you iterate over the highlights in the order you want
emilio: but that should provide all the flexibility you'll ever need
emilio: If we want something more convenient, could put one on the
highlight registry that gives back all of them
emilio: would just be sugar over a for loop
emilio: so could use if you want a central place to handle all the
highlights
emilio: but might also want to deal with each highlight separately
flackr: My point was partially overlapped with emilio, concerned
about a special event before the dom event
flackr: Could consider the highlight to be the normal action, so if
the normal event wasn't defaulted you dispatch to highlight
flackr: Longer term, we want to support css pseudo targets, wondering
if that helps so we can just target those
dandclark: The highlight pseudo is a pseudo object, it's a little
special...
flackr: I think my main concern is whether those should be given the
event first
flackr: I think visually the highlight is behind the text, so from
dev pov the element should get first crack, and pseudo gets
opportunity after
dbaron: I think it's worth trying to get event.stopPropagation vs
preventDefault to behave as closely as possible to normal
dbaron: I think what Dan was originally defining was to make
preventDefault act like stopPropagation
dbaron: Hope we can do something better even if the dom event spec
needs to expose some extra concepts
dbaron: Thoughts on emilio's proposal
dbaron: first is I'm a little concerned about an approach that forces
you to add event listeners to the doc, for cases where impls
want to make optimizations for passive listeners
dbaron: If it's an event type where registering a non-passive
listener, and you need to register non-passive for the
highlight, you have to take the perf penalty document-wide
dbaron: That seems undesirable
dbaron: so I think that's a reason you might want to have
eventListener registration be on more specific targets
dandclark: I like the simplicity of emilio's idea
dandclark: if we can find a way around the perf hit
emilio: The initial proposal was about clicks
emilio: Don't think we can get much opt about passive vs non-passive
event listeners
emilio: don't see how having highlights doesn't prevent you from
losing optimizations
dbaron: What you said about the way to use the proposal is put an
Event Listener on the document, and look up the point
dbaron: And that way of using it can be problematic
emilio: Right, if you care about scroll and things that benefit from
passive
emilio: But API doesn't let you use it for other event types
dbaron: I think when it's like "this is only for clicks *right now*",
unsure we want to design around that
emilio: So API right now takes an x/y
emilio: Have clear text for mouse events to resolve that
emilio: Could let the method take an event object instead, so we can
limit it to certain event types
dbaron: Ah yeah, other point I'd forgot. I think taking x/y doesn't
handle [missed]
dbaron: you might click a piece of text with highlights that obscures
another piece with highlights
dbaron: you're probably interested in the top element's highlights,
not the obscured one
emilio: Could define the api similar to getelementfrompoint where you
do account for hit-testing
emilio: Could define to only care about rects, like union the ranges
emilio: or like elementFromPoint which cares about hit-testing and
p-e:none/etc
emilio: Seems you could get that with just an x/y if you define it to
do hit-testing
dbaron: yeah that sounds like it works
emilio: So define it in terms of elementsFromPoint
emilio: If any of the elements intersect the highlight... something
like that
emilio: specific semantics for intersecting highlights could be left
to...
emilio: if both intersect the consumer can choose
flackr: I think x/y works if you can get highlights on the targeted
element
flackr: that'll account for hit-testing
flackr: but this is def going to be a performance issue, even if
limited to mouse events
flackr: people might want to drag highlights, so they'll have
pointerstart, and that means we have to delay scrolling
flackr: but if we fire on the highlight we can recognize it won't
stop scrolling
emilio: But that would penalize other scenarios
emilio: not sure what the best way to do it is
emilio: needs real thought especially for pointerdown
emilio: [missed]
emilio: There are use-cases for pointerdown
emilio: If we extend proposal, we'd dispatch to highlights, then to
web content... we'd do it for every event type anyone would
care about
flackr: Highlight needs to be in the event target tree, but yeah
currently tree is strictly ancestor tree so that would be a
disconnect
astearns: Question about emilio's proposal
astearns: You get coords, ask document for highlights.
astearns: Are we still able to have top priority highlight prevent
other highlights from responding?
emilio: Yes, just check if the event was preventDefault'd and return
rather than moving on to the next highlight
<dbaron> (do you mean stopPropagation or preventDefault for that
case?)
<TabAtkins> (don't think it matters for the discussion)
astearns: So it's manual?
TabAtkins: Yes, all fully manually handled, they're not fired on the
highlights by the browser stuff
fremy: So if you have multiple types of code doing highlights they
don't know about each other
fremy: How can they work together?
emilio: Initial proposal was a bool on the highlight
emilio: If you need to be aware of one vs the other you need a
central place to do it
TabAtkins: Right, given dan's initial use-cases (scroll and
spellcheck) you *need* them to coordinate with each other
anyway
emilio: With my proposal there's no change to event prop. You fire
the same events as with no highlights
emilio: Up to the website to either centralize their highlight
handling, or have different listeners that handle them
separately
fremy: But you can't decide which acts first
emilio: With a bool and two coords approach, that's right because you
have to handle the highlights
emilio: But if we have the method on the highlight registry that
returns highlights in order, you can check yourself if the
one you're in charge of is first
fremy: So if you're not, do you try again?
emilio: If you don't have event listeners in the right order you can
have weirdness
fremy: But order isn't one order
fremy: Not sure there's one correct order
dbaron: I think emilio's proposal is that page author has to write
their own event registration system if they want to deal with
multiple highlights
dbaron: We provide an api in the platform that says "here's the
ordered list of highlights affected by this" and the author
can process the list with their own reg system however they
want
fremy: Yeah, just weird we don't provide that
fremy: You assume libraries will cooperate, not clear to me they will
if they're different sources
fremy: strange to assume that
<fantasai> +1 fremy
<GameMaker> +1 fremy as well
emilio: my proposal is minimum that lets you build this
emilio: but solving general case firing event listeners in an order
that solves every use case, yeah it's a much more complicated
problem
emilio: have to define which events do this, we start with click but
have a million events
fremy: Another option is we provide it. For each highlight, define
which events you want to receive, and we have an api that
dispatches to them in a pseudo-event manner
fremy: So does preventDefault for you, etc
emilio: I'm not even sure there's a canonical order you want to define
events on
emilio: spellcheck error with a link inside
emilio: Might seem reasonable to fire spellcheck first and link if
not handled, but might be reasonable other way around
emilio: I think easiest is to make website choose
dandclark: Advantage of having platform handle this, where we just
propagate the event, is we already had an order of
highlights
dandclark: so think there is an advantage to use the existing order
since things are built in already
emilio: There is reasons to do before, but also after
emilio: Not clear to me why we should do them before or after in
specific
fremy: I think this makes sense, let authors to do this
emilio: I think having an api that gives you ranges in order would be
low level
emilio: if libraries say we can't use this because there's no good
way to coordinate, then we can decide whether to fire events
before or after
emilio: seems like an elegant way to handle the use-cases without
making a call
scribe: fantasai
TabAtkins: I think one detail of fremy's proposal is being missed,
which is getting the list ordered is reasonable and
authors handling on his own
TabAtkins: The problem is that you have to re-invent event dispatch,
and hope other libraries can coordinate with you
TabAtkins: Given a list of highlights to dispatch on, it fires events
using normal event listener mechanics
TabAtkins: handles preventDefault etc, as if part of the normal event
dispatch order
TabAtkins: so don't have to re-invent
TabAtkins: doesn't require cross-library coordination of the events
themselves
TabAtkins: e.g. fire highlight event, take a list of highlights,
cranks through them in order as if part of event chain
emilio: So would be equivalent to making highlight event listener
emilio: so basically it would be a matter of writing that loop with
the current event and dealing the pD/etc in that order
emilio: with api from before, give me a list of highlights, would be
a matter of writing that loop with current event and dealing
with event propagation and stuff manually
emilio: that seems reasonable
emilio: page would be responsible at some point, to propagate the
highlight events
TabAtkins: on the highlight registry, yeah
emilio: Seems like either extension or replacement
emilio: Still requires page's coordination
astearns: Tab described your first option from the issue?
dandclark: Sounds similar, except instead of dispatching, need to
register to dispatch
TabAtkins: Yes, page author still has to handle ordering and do what
they need to do
TabAtkins: but otherwise platform handles events for you
dandclark: So if I have highlights on my page
TabAtkins: Ask the highlight registry are at this x,y, then call this
with all of those
TabAtkins: in priority order
TabAtkins: if a highlight preventsDefault, then later things don't
get the event
TabAtkins: which is what you want
TabAtkins: [missed]
dandclark: How do we know it's not happening twice?
dandclark: If my final page library says, okay, I need to trigger
this ? and propagate the highlights
dandclark: [too fast]
dandclark: I have two different libraries
TabAtkins: If you have 2 libraries both installing event handler on
the element
TabAtkins: If not preventDefault, each one would run through list,
and you'd get repetitious behavior
florian: This approach both allows but also requires you to coordinate
florian: simple scenarios can coordinate by accident, but overall, if
doing with multiple independent libraries
florian: need some kind of plan for interaction
florian: you need to think through it
florian: Another thing I wanted to ask, unsure if decides,
florian: all this discussion here, we're going to have a very similar
discussion for every other type of pseudo
florian: e.g. ellipsis
florian: We shouldn't have 3-4 different solutions for each type of
pseudo
florian: I think this approach works better, you're in charge of
coordinating, coordinate to your heart's delight
florian: but it is a low-level approach, you *have to* coordinate
florian: For those who have thought about this, how do you generalize
to other pseudos?
TabAtkins: Only concern I have is the actual invocation of your
behavior, already have API for that called event listeners
TabAtkins: not using that sucks
TabAtkins: but if we recommend to authors to call dispatchEvent on
your things, that's probably sufficient
TabAtkins: we have communication API ... but at least not inventing a
new callback system
florian: can we do both? By default have a dispatcher that that walks
up the highlight priority list
florian: and if you don't like that, do your own?
florian: If you don't say anything, we dispatch like this. If you
don't like it, roll your own
fremy: If you want [missed]
fremy: we already have mechanism for that
emilio: But initial proposal fires at DOM
fremy: If you decide that you want to dispatch something, if it's
important, you can say it's capture phase. We already have
mechanism for it, this coordination happens every day
fremy: We have bubble phase, capturing, etc.
fremy: we already have these
fremy: it works
emilio: If the page hasn't called dispatchEvent on the registry
emilio: if we do ourselves, prevents page from doing it later
emilio: so only default we could choose is after DOM dispatch
emilio: but might want to dispatch earlier than that
emilio: so I think making highlight inherit from EventTarget makes
sense
emilio: and propagating to highlight whenever page wants is reasonable
emilio: but how would that look like?
emilio: undefined ?? x,?
emilio: do for mouse events normally?
emilio: do the list thing?
TabAtkins: Do the list thing manually
TabAtkins: You can check preventDefault by defaultPrevented
TabAtkins: We can put example code in the spec
emilio: So you don't want an API that does it for you?
TabAtkins: Probably not
*fantasai would like a summary
dandclark: If we have 2 libraries that are not coordinating, which
one writes the for loop?
TabAtkins: You should check to see if default has been prevented
TabAtkins: if you're first, you can preventDefault() if you've
handled things
TabAtkins: or you can just stop propagation immediately
TabAtkins: Event system can handle that
fremy: You may say that you don't want to prevent, but still click on
the button
TabAtkins: Events should check themselves to see if prevented
fremy: if you preventDefault, the button won't click
emilio: That's the key of the issue, there's no good answer on
whatever is the good answer
emilio: if you have a spelling error on a button, you might want a
popup to suggest a fix
emilio: or you might want to click the button
emilio: It's not known which you want
fremy: I agree, but if every library makes its own for loop because
it's necessary, then ??
emilio: We're not suggesting that
emilio: The library doesn't need to write the for loop. They add e.g.
click event listener on its object
emilio: something on the page writes the for loop once, and
dispatches to all highlights
emilio: So no library needs to write the for loop
emilio: That's done once whenever page wants to handle that
fremy: If I use grammarly, grammarly needs to write the for loop or
else it doesn't work
fremy: So they will write it because they need it
emilio: Then they would only handle ranges that they register
fremy: But it still does not solve issue of order
fremy: run the grammarly thing and no consideration that some other
things on top of them
emilio: If preventDefaulted then ???
fremy: Still the same issue, it's not preventDefaulted if there's
another highlight before it
fremy: You have multiple highlights. Grammarly wants to work. So they
will need to add an event to handle fix. If they want to make
for loop, they can only include grammarly stuff
fremy: but they might want to run grammarly code only if no highlight
on top of them
emilio: If the page has dispatched the same event to the highlight
already
emilio: like you would dispatch the mouse event from the platform
emilio: If another highlight provider did something, registered dom
event in capturephase, and have preventDefaulted it, then
grammarly can check that and bail out
emilio: This event has been handled before, we may not even need our
for loop
fremy: I don't quite understand, it's not clear what are we doing
TabAtkins: There are various ways for event handler to check if I've
been called with this before
TabAtkins: In most cases not required, all first-party content, and
don't care much
TabAtkins: should be generally OK, and complex cases need complexity
anyway
TabAtkins: You can say I only want to be dispatched once, and
guarantee that on your own, by checking and immediately
returning if you get called a second time
fremy: ...
TabAtkins: Normal event dispatch would not call the same event on the
same element more than once
TabAtkins: but we're not using normal event dispatch
<TabAtkins> (store the last event you saw dispatched to yourself, and
check if the new one is the same as the last; if so
return immediately)
<TabAtkins> so you can avoid the "double-dispatch" entirely on your
own without any 3rd party coordination
astearns: Any other lingering questions, or take back to the issue to
discuss the current state of this fourth way
* fantasai doesn't quite understand what the proposal is
dandclark: I agree with taking back to the issue, I'm also a bit lost
astearns: Emilio, can I ask you to write up the proposal with all the
details so that Dan has something to digest more easily
than the minutes?
dandclark: Does this still have the perf issue dbaron raised?
dandclark: [missed]
emilio: For clicks sure there's no perf issue
emilio: For things like pointerDown, if you want notPassive handling
of pointerDown, it feels like a global event listener is
maybe not ideal
emilio: This may be fixable another way
emilio: like, maybe we need another member of listenerOptions
emilio: I don't have an answer for that right now
flackr: Maybe the highlight could have a different touchAction?
flackr: Normally we encourage people to use passive events and use
touch Action to specify whether to scroll or not
flackr: if we had a way to specify the touch-action on the highlights
to not depend
emilio: Yes, you might want to allow touch-action on highlight
pseudos, make that behave properly
emilio: it's a very good idea
astearns: Anything more on this issue?
dandclark: Yes, I think we're good
astearns: Do we discuss next issue? or wait on the details of this
one?
dandclark: I think we wait
dandclark: Next one is about answering question of given dispatch,
how to we determine which range was targetted. I suggested
adding a new event type
astearns: so closing off current issue and going to next issue
Is a HighlightPointerEvent type needed?
---------------------------------------
github: https://github.com/w3c/csswg-drafts/issues/7512
dandclark: If the solution we go with here involves highlight being
an event target
dandclark: which either way I think will be the case
dandclark: how do I know which range was targeted?
dandclark: e.g. I'm a spell checker, but got a click, but which range
was clicked?
dandclark: Multiple ways to fix
dandclark: Original solution maybe doesn't make sense, but if we do
have some kind of intersects API then maybe that answers
the question
dandclark: If we're re-using the existing pointer events, then
[missed]
dandclark: Call some kind of API, what were my intersection ranges?
dandclark: I need to know which ranges and which highlight
dandclark: perhaps API could be just onHighlight? similar to what ??
was proposing
dandclark: I add intersects() function to Highlight, it takes x,y and
it returns a list of ranges in the highlight
dandclark: maybe that's the simplest
dandclark: highlight could potentially have several overlapping on
the same text
dandclark: Does that sound reasonable?
emilio: yes...
emilio: given we already have a hit testing function that gives you
list of highlights, maybe also takes ranges
emilio: I think this is related to previous issue
emilio: Either way, if we go through event listener path or dom event
thing, or the thing we were discussing
emilio: I'd rather resolve that first, even if it's not the final
solution
emilio: maybe instead of sequence of highlights we need to return
sequence of highlights and ranges
dandclark: Sounds good, just want to make sure the problem is on the
radar
flackr: I don't think we should have a specific event type, because I
think we will want to target multiple types of events at
highlights
flackr: prefer to have event that bubbles up. You dispatch to
specific range, and then on the highlight you can check for
which range
emilio: but target would be the DOM element
flackr: right, but ...
emilio: But unsure about event target
emilio: [missed]
emilio: We may need to figure out a way... obviously, if we provide
the API so that if we dispatch both highlights and ranges,
the page could put the ranges property and expand all of the
object
emilio: It's worth thinking about, but depends on other issues
GameMaker: I just want to make sure that when we're talking about
ranges that highlights are done in abstract ranges, so
keep that in mind
GameMaker: make sure we remember they're AbstractRanges
emilio: You can build highlights with StaticRange and Range
GameMaker: Yeah, AbstractRange can be either
emilio: Right
astearns: Anything else on this issue?
astearns: OK, we'll come back to both of these relatively soon
Received on Tuesday, 30 August 2022 00:00:23 UTC