- From: Nicolò Ribaudo via GitHub <sysbot+gh@w3.org>
- Date: Sat, 26 Oct 2024 16:38:26 +0000
- To: public-css-archive@w3.org
nicolo-ribaudo has just created a new issue for https://github.com/w3c/csswg-drafts:
== [css-highlight-api] Feedback: the global registry string-keyed makes usage very hard ==
Example use case: I have a contenteditable `div` that marks as `::highlight(has-x)` all the words that contain `x`.
The simplest way of doing it is:
```js
function highlightWords(div) {
const highlight = new Highlight();
for (const child of div.childNodes) {
if (child.nodeType !== Node.TEXT_NODE) continue;
const regexp = /\w*x\w*/g;
let match;
while (match = regexp.exec(child.textContent)) {
const range = document.createRange();
range.setStart(node, match.index);
range.setEnd(node, match[0].length + match.index);
highlight.add(range);
}
}
CSS.highlights.set("has-x", highlight);
}
highlightWords(myElement);
myElement.addEventListener("input", () => highlightWords(myElement));
```
This works perfectly as long as I only call this function once on a single element.
One day I decide that actually, I need this behavior on two different elements on my page, so I try doing this:
```js
highlightWords(myElement1);
myElement1.addEventListener("input", () => highlightWords(myElement1));
highlightWords(myElement2);
myElement1.addEventListener("input", () => highlightWords(myElement2));
```
Except that this doesn't work at all: the highlighting logic over `myElement1` and `myElement2` fight over control of the `has-x` entry in the global `CSS.highlights` registry, and delete each other's highlights as they get updated.
To make it work, I need to instead update the logic in `highlightWords` to _never_ overwrite an existing entry in the `CSS.highlights` map. Instead, it must check through all the ranges in the entry and only remove/add its own, and then _if the map ends up being empty_ it can remove it.
The global registry introduces a synchronization point between different parts of the page that is easier to get wrong than it's to get right, and if you are a library author (for example, publishing the logic above in a custom element) you won't notice unless you explicitly test multiple instances on the same page.
---
There are multiple ways that the API can be changed to make it difficult to do the wrong thing.
**Do not allow reading `Highlight` objects from the global registry, and do not allow removing `Highlight` objects that you do not control**:
- `.get()` is removed
- to check whether an highlight has been registered, you have to do `CSS.highlights.has(name, highlight)` instead of `CSS.highlights.has(name)`
- `.set(name, highlight)` throws if there is already an entry called `name`
- to delete an highlight, you must use `.delete(name, highlight)` instead of `.delete(name)`
This keeps the synchronization complexity, but forces developers to think about it.
**Allow registering multiple `Highlights` with the same name**:
Similar to above, except that instead of it makes conflicts work well together instead of overwriting each other
- `.get()` is removed, or it returns an array of `Highlight` objecs
- to check whether an highlight has been registered, you have to do `CSS.highlights.has(name, highlight)` instead of `CSS.highlights.has(name)`
- `.set(name, highlight)` adds a new highlight named `name`, without removing any existing highlight with the same name.
- to delete an highlight, you must use `.delete(name, highlight)` instead of `.delete(name)`
**Allow using local registries**
Allow the function above to create its own `highlights` registry by doing something like `const highlights = new HighlightsRegistry(document)`. Different registries can declare the same name without conflicting with each other. The example above would become
```js
const registry1 = new HighlightsRegistry(document);
highlightWords(registry1, myElement1);
myElement1.addEventListener("input", () => highlightWords(registry1, myElement1));
const registry2 = new HighlightsRegistry(document);
highlightWords(registry2, myElement2);
myElement1.addEventListener("input", () => highlightWords(registry2, myElement2));
```
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/11095 using your GitHub account
--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Saturday, 26 October 2024 16:38:27 UTC