diff --git a/2-ui/99-ui-misc/01-mutation-observer/article.md b/2-ui/99-ui-misc/01-mutation-observer/article.md index 6e710ed1..f1e10369 100644 --- a/2-ui/99-ui-misc/01-mutation-observer/article.md +++ b/2-ui/99-ui-misc/01-mutation-observer/article.md @@ -25,12 +25,14 @@ observer.observe(node, config); - `childList` -- changes in the direct children of `node`, - `subtree` -- in all descendants of `node`, - `attributes` -- attributes of `node`, -- `attributeOldValue` -- record the old value of attribute (infers `attributes`), -- `characterData` -- whether to observe `node.data` (text content), -- `characterDataOldValue` -- record the old value of `node.data` (infers `characterData`), - `attributeFilter` -- an array of attribute names, to observe only selected ones. +- `characterData` -- whether to observe `node.data` (text content), -Then after any changes, the `callback` is executed, with a list of [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) objects as the first argument, and the observer itself as the second argument. +Few other options: +- `attributeOldValue` -- if `true`, pass both the old and the new value of attribute to callback (see below), otherwise only the new one (needs `attributes` option), +- `characterDataOldValue` -- if `true`, pass both the old and the new value of `node.data` to callback (see below), otherwise only the new one (needs `characterData` option). + +Then after any changes, the `callback` is executed: changes are passed in the first argument as a list of [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) objects, and the observer itself as the second argument. [MutationRecord](https://dom.spec.whatwg.org/#mutationrecord) objects have properties: @@ -38,12 +40,11 @@ Then after any changes, the `callback` is executed, with a list of [MutationReco - `"attributes"`: attribute modified - `"characterData"`: data modified, used for text nodes, - `"childList"`: child elements added/removed, -- `target` -- where the change occurred: an element for "attributes", or text node for "characterData", or an element for a "childList" mutation, +- `target` -- where the change occurred: an element for `"attributes"`, or text node for `"characterData"`, or an element for a `"childList"` mutation, - `addedNodes/removedNodes` -- nodes that were added/removed, - `previousSibling/nextSibling` -- the previous and next sibling to added/removed nodes, - `attributeName/attributeNamespace` -- the name/namespace (for XML) of the changed attribute, -- `oldValue` -- the previous value, only for attribute or text changes. - +- `oldValue` -- the previous value, only for attribute or text changes, if the corresponding option is set `attributeOldValue`/`characterDataOldValue`. For example, here's a `
@@ -114,20 +130,13 @@ An HTML markup of a code snippet looks like this:
Also we'll use a JavaScript highlighting library on our site, e.g. [Prism.js](https://prismjs.com/). A call to `Prism.highlightElem(pre)` examines the contents of such `pre` elements and adds into them special tags and styles for colored syntax highlighting, similar to what you see in examples here, at this page.
-When to run that method? We can do it on `DOMContentLoaded` event, or at the bottom of the page. At that moment we have DOM ready, can search for elements `pre[class*="language"]` and call `Prism.highlightElem` on them:
+When exactly to run that highlighting method? We can do it on `DOMContentLoaded` event, or at the bottom of the page. At that moment we have DOM ready, can search for elements `pre[class*="language"]` and call `Prism.highlightElem` on them:
```js
// highlight all code snippets on the page
document.querySelectorAll('pre[class*="language"]').forEach(Prism.highlightElem);
```
-Now the `` snippet looks like this (without line numbers by default):
-
-```js
-// here's the code
-let hello = "world";
-```
-
Everything's simple so far, right? There are `` code snippets in HTML, we highlight them.
Now let's go on. Let's say we're going to dynamically fetch materials from a server. We'll study methods for that [later in the tutorial](info:fetch). For now it only matters that we fetch an HTML article from a webserver and display it on demand:
@@ -159,11 +168,11 @@ And what if the content is loaded by a third-party module? E.g. we have a forum
Luckily, there's another option.
-We can use `MutationObserver` to automatically detect code snippets inserted in the page and highlight them.
+We can use `MutationObserver` to automatically detect when code snippets are inserted in the page and highlight them.
So we'll handle the highlighting functionality in one place, relieving us from the need to integrate it.
-## Dynamic highlight demo
+### Dynamic highlight demo
Here's the working example.
@@ -173,7 +182,7 @@ If you run this code, it starts observing the element below and highlighting any
let observer = new MutationObserver(mutations => {
for(let mutation of mutations) {
- // examine new nodes
+ // examine new nodes, is there anything to highlight?
for(let node of mutation.addedNodes) {
// we track only elements, skip other nodes (e.g. text nodes)
@@ -184,7 +193,7 @@ let observer = new MutationObserver(mutations => {
Prism.highlightElement(node);
}
- // maybe there's a code snippet somewhere in its subtree?
+ // or maybe there's a code snippet somewhere in its subtree?
for(let elem of node.querySelectorAll('pre[class*="language-"]')) {
Prism.highlightElement(elem);
}
@@ -198,7 +207,11 @@ let demoElem = document.getElementById('highlight-demo');
observer.observe(demoElem, {childList: true, subtree: true});
```
-Demo element with id="highlight-demo"
, obverved by the example above.
+Here's HTML-element and JavaScript that dynamically fills it using `innerHTML`.
+
+Please run the previous code (above, observes that element), and then the code below. You'll see how `MutationObserver` detects and highlights the snippet.
+
+Демо-элемент с id="highlight-demo"
, за которым следит код примера выше.
The code below populates `innerHTML`. Please run the code above first, it will watch and highlight the new content:
@@ -223,18 +236,17 @@ There's a method to stop observing the node:
- `observer.disconnect()` -- stops the observation.
-Additionally:
+Another method often used with it:
- `mutationRecords = observer.takeRecords()` -- gets a list of unprocessed mutation records, those that happened, but the callback did not handle them.
```js
-// we're going to disconnect the observer
+// we'd like to stop tracking changes
+observer.disconnect();
+
// it might have not yet handled some mutations
let mutationRecords = observer.takeRecords();
// process mutationRecords
-
-// now all handled, disconnect
-observer.disconnect();
```
## Garbage collection
@@ -245,6 +257,6 @@ Observers use weak references to nodes internally. That is: if a node is removed
`MutationObserver` can react on changes in DOM: attributes, added/removed elements, text content.
-We can use it to track changes introduced by other parts of our own or 3rd-party code.
+We can use it to track changes introduced by other parts of our code, as well as to integrate with third-party scripts.
-For example, to post-process dynamically inserted content, as demo `innerHTML`, like highlighting in the example above.
+`MutationObserver` can track any changes. The config "what to observe" options are used for optimizations, not to spend resources on unneeded callback invocations.