diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md
index fc3bf652..99dde5bc 100644
--- a/2-ui/1-document/05-basic-dom-node-properties/article.md
+++ b/2-ui/1-document/05-basic-dom-node-properties/article.md
@@ -10,7 +10,7 @@ Different DOM nodes may have different properties. For instance, an element node
Each DOM node belongs to the corresponding built-in class.
-The root of the hierarchy is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), that is inherited by [Node](http://dom.spec.whatwg.org/#interface-node), and other DOM nodes inherit from it.
+The root of the hierarchy is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), that is inherited by [Node](https://dom.spec.whatwg.org/#interface-node), and other DOM nodes inherit from it.
Here's the picture, explanations to follow:
@@ -18,16 +18,39 @@ Here's the picture, explanations to follow:
The classes are:
-- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class. Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later.
-- [Node](http://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and more exotic ones like `Comment` for comment nodes.
-- [Element](http://dom.spec.whatwg.org/#interface-element) -- is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. A browser supports not only HTML, but also XML and SVG. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`.
-- [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) -- is finally the basic class for all HTML elements. It is inherited by concrete HTML elements:
+- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class for everything.
+
+ Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later.
+
+- [Node](https://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes.
+
+ It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are other classes that inherit from it (and so inherit the `Node` functionality).
+
+- [Document](https://dom.spec.whatwg.org/#interface-document), for historical reasons often inherited by `HTMLDocument` (though the latest spec doesn't dictate it) -- is a document as a whole.
+
+ The `document` global object belongs exactly to this class. It serves as an entry point to the DOM.
+
+- [CharacterData](https://dom.spec.whatwg.org/#interface-characterdata) -- an "abstract" class, inherited by:
+ - [Text](https://dom.spec.whatwg.org/#interface-text) -- the class corresponding to a text inside elements, e.g. `Hello` in `
Once upon a time there was a mother pig who had three little pigs.
-
The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you."
+
The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you."
The three little pigs set off. "We will take care that the wolf does not catch us," they said.
Once upon a time there was a mother pig who had three little pigs.
-
The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you."
+
The three little pigs grew so big that their mother said to them, "You are too big to live here any longer. You must go and build houses for yourselves. But take care that the wolf does not catch you."
The three little pigs set off. "We will take care that the wolf does not catch us," they said.
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/solution.view/hoverIntent.js b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/solution.view/hoverIntent.js
index 4e6e2a3e..7503ca9c 100644
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/solution.view/hoverIntent.js
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/2-hoverintent/solution.view/hoverIntent.js
@@ -88,7 +88,7 @@ class HoverIntent {
if (speed < this.sensitivity) {
clearInterval(this.checkSpeedInterval);
this.isHover = true;
- this.over.call(this.elem, event);
+ this.over.call(this.elem);
} else {
// speed fast, remember new coordinates as the previous ones
this.prevX = this.lastX;
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-bubble-nested.svg b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-bubble-nested.svg
index 07830295..6044eff1 100644
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-bubble-nested.svg
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-bubble-nested.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.svg b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.svg
index 07176ba2..22335b52 100644
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.svg
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-from-outside.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.svg b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.svg
index 262ddf59..437f03b1 100644
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.svg
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout-over-elems.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.svg b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.svg
index 784f435d..1277ddff 100644
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.svg
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-mouseout.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.svg b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.svg
index b38d76fb..78210845 100644
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.svg
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseover-to-child.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/script.js b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/script.js
index 6d87199c..5752e83a 100755
--- a/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/script.js
+++ b/2-ui/3-event-details/3-mousemove-mouseover-mouseout-mouseenter-mouseleave/mouseoverout-fast.view/script.js
@@ -3,7 +3,7 @@ parent.onmouseover = parent.onmouseout = parent.onmousemove = handler;
function handler(event) {
let type = event.type;
- while (type < 11) type += ' ';
+ while (type.length < 11) type += ' ';
log(type + " target=" + event.target.id)
return false;
diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg
index ca8bbc3b..f5bd9f4f 100644
--- a/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg
+++ b/2-ui/3-event-details/4-mouse-drag-and-drop/2-drag-heroes/solution.view/field.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md
index 49ab88be..4c928eef 100644
--- a/2-ui/3-event-details/4-mouse-drag-and-drop/article.md
+++ b/2-ui/3-event-details/4-mouse-drag-and-drop/article.md
@@ -18,19 +18,19 @@ The basic Drag'n'Drop algorithm looks like this:
2. Then on `mousemove` move it by changing `left/top` with `position:absolute`.
3. On `mouseup` - perform all actions related to finishing the drag'n'drop.
-These are the basics. Later we'll see how to other features, such as highlighting current underlying elements while we drag over them.
+These are the basics. Later we'll see how to add other features, such as highlighting current underlying elements while we drag over them.
Here's the implementation of dragging a ball:
```js
-ball.onmousedown = function(event) {
+ball.onmousedown = function(event) {
// (1) prepare to moving: make absolute and on top by z-index
ball.style.position = 'absolute';
ball.style.zIndex = 1000;
// move it out of any current parents directly into body
// to make it positioned relative to the body
- document.body.append(ball);
+ document.body.append(ball);
// centers the ball at (pageX, pageY) coordinates
function moveAt(pageX, pageY) {
@@ -93,14 +93,14 @@ So we should listen on `document` to catch it.
## Correct positioning
-In the examples above the ball is always moved so, that it's center is under the pointer:
+In the examples above the ball is always moved so that its center is under the pointer:
```js
ball.style.left = pageX - ball.offsetWidth / 2 + 'px';
ball.style.top = pageY - ball.offsetHeight / 2 + 'px';
```
-Not bad, but there's a side-effect. To initiate the drag'n'drop, we can `mousedown` anywhere on the ball. But if "take" it from its edge, then the ball suddenly "jumps" to become centered under the mouse pointer.
+Not bad, but there's a side effect. To initiate the drag'n'drop, we can `mousedown` anywhere on the ball. But if "take" it from its edge, then the ball suddenly "jumps" to become centered under the mouse pointer.
It would be better if we keep the initial shift of the element relative to the pointer.
@@ -219,7 +219,7 @@ That's why the initial idea to put handlers on potential droppables doesn't work
So, what to do?
-There's a method called `document.elementFromPoint(clientX, clientY)`. It returns the most nested element on given window-relative coordinates (or `null` if given coordinates are out of the window).
+There's a method called `document.elementFromPoint(clientX, clientY)`. It returns the most nested element on given window-relative coordinates (or `null` if given coordinates are out of the window). If there are multiple overlapping elements on the same coordinates, then the topmost one is returned.
We can use it in any of our mouse event handlers to detect the potential droppable under the pointer, like this:
diff --git a/2-ui/3-event-details/4-mouse-drag-and-drop/ball_shift.svg b/2-ui/3-event-details/4-mouse-drag-and-drop/ball_shift.svg
index 3aa2541d..29fdb31e 100644
--- a/2-ui/3-event-details/4-mouse-drag-and-drop/ball_shift.svg
+++ b/2-ui/3-event-details/4-mouse-drag-and-drop/ball_shift.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/6-pointer-events/article.md b/2-ui/3-event-details/6-pointer-events/article.md
index 4b58f3ff..b8873e9d 100644
--- a/2-ui/3-event-details/6-pointer-events/article.md
+++ b/2-ui/3-event-details/6-pointer-events/article.md
@@ -111,7 +111,7 @@ Such causes are:
We'll demonstrate `pointercancel` on a practical example to see how it affects us.
-Let's say we're impelementing drag'n'drop for a ball, just as in the beginning of the article .
+Let's say we're implementing drag'n'drop for a ball, just as in the beginning of the article .
Here is the flow of user actions and the corresponding events:
@@ -271,7 +271,7 @@ Pointer events allow handling mouse, touch and pen events simultaneously, with a
Pointer events extend mouse events. We can replace `mouse` with `pointer` in event names and expect our code to continue working for mouse, with better support for other device types.
-For drag'n'drops and complex touch interactions that the browser may decide to hijack and handle on its own - remember to cancel the default action on events and set `touch-events: none` in CSS for elements that we engage.
+For drag'n'drops and complex touch interactions that the browser may decide to hijack and handle on its own - remember to cancel the default action on events and set `touch-action: none` in CSS for elements that we engage.
Additional abilities of pointer events are:
diff --git a/2-ui/3-event-details/7-keyboard-events/article.md b/2-ui/3-event-details/7-keyboard-events/article.md
index 51c1618f..12fe6320 100644
--- a/2-ui/3-event-details/7-keyboard-events/article.md
+++ b/2-ui/3-event-details/7-keyboard-events/article.md
@@ -107,7 +107,7 @@ So, `event.code` may match a wrong character for unexpected layout. Same letters
To reliably track layout-dependent characters, `event.key` may be a better way.
-On the other hand, `event.code` has the benefit of staying always the same, bound to the physical key location, even if the visitor changes languages. So hotkeys that rely on it work well even in case of a language switch.
+On the other hand, `event.code` has the benefit of staying always the same, bound to the physical key location. So hotkeys that rely on it work well even in case of a language switch.
Do we want to handle layout-dependant keys? Then `event.key` is the way to go.
@@ -149,7 +149,7 @@ The `onkeydown` handler here uses `checkPhoneKey` to check for the key pressed.
As we know, the `false` value returned from the event handler, assigned using a DOM property or an attribute, such as above, prevents the default action, so nothing appears in the `` for keys that don't pass the test. (The `true` value returned doesn't affect anything, only returning `false` matters)
-Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side-effect of the strict filter `checkPhoneKey`. These keys make it return `false`.
+Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side effect of the strict filter `checkPhoneKey`. These keys make it return `false`.
Let's relax the filter a little bit by allowing arrow keys `key:Left`, `key:Right` and `key:Delete`, `key:Backspace`:
diff --git a/2-ui/3-event-details/7-keyboard-events/german-layout.svg b/2-ui/3-event-details/7-keyboard-events/german-layout.svg
index 8a880e8e..7ac9a400 100644
--- a/2-ui/3-event-details/7-keyboard-events/german-layout.svg
+++ b/2-ui/3-event-details/7-keyboard-events/german-layout.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html
index 40106283..a0d5a4f4 100644
--- a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html
+++ b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html
@@ -28,7 +28,7 @@
-
+
diff --git a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js
index 5eba24c7..d97f7a7b 100644
--- a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js
+++ b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js
@@ -5,6 +5,8 @@ let lastTime = Date.now();
function handle(e) {
if (form.elements[e.type + 'Ignore'].checked) return;
+ area.scrollTop = 1e6;
+
let text = e.type +
' key=' + e.key +
' code=' + e.code +
diff --git a/2-ui/3-event-details/7-keyboard-events/us-layout.svg b/2-ui/3-event-details/7-keyboard-events/us-layout.svg
index 699277e0..353f225f 100644
--- a/2-ui/3-event-details/7-keyboard-events/us-layout.svg
+++ b/2-ui/3-event-details/7-keyboard-events/us-layout.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/4-forms-controls/1-form-elements/article.md b/2-ui/4-forms-controls/1-form-elements/article.md
index 689301e4..f22518d9 100644
--- a/2-ui/4-forms-controls/1-form-elements/article.md
+++ b/2-ui/4-forms-controls/1-form-elements/article.md
@@ -155,7 +155,7 @@ Let's talk about form controls.
### input and textarea
-We can access their value as `input.value` (string) or `input.checked` (boolean) for checkboxes.
+We can access their value as `input.value` (string) or `input.checked` (boolean) for checkboxes and radio buttons.
Like this:
diff --git a/2-ui/4-forms-controls/1-form-elements/form-navigation.svg b/2-ui/4-forms-controls/1-form-elements/form-navigation.svg
index b112e250..2c908070 100644
--- a/2-ui/4-forms-controls/1-form-elements/form-navigation.svg
+++ b/2-ui/4-forms-controls/1-form-elements/form-navigation.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md
index b866a5e2..c253dc11 100644
--- a/2-ui/4-forms-controls/2-focus-blur/article.md
+++ b/2-ui/4-forms-controls/2-focus-blur/article.md
@@ -90,6 +90,8 @@ If we enter something into the input and then try to use `key:Tab` or click away
Please note that we can't "prevent losing focus" by calling `event.preventDefault()` in `onblur`, because `onblur` works *after* the element lost the focus.
+In practice though, one should think well, before implementing something like this, because we generally *should show errors* to the user, but *should not prevent their progress* in filling our form. They may want to fill other fields first.
+
```warn header="JavaScript-initiated focus loss"
A focus loss can occur for many reasons.
diff --git a/2-ui/4-forms-controls/3-events-change-input/article.md b/2-ui/4-forms-controls/3-events-change-input/article.md
index 6865e2a4..097217f5 100644
--- a/2-ui/4-forms-controls/3-events-change-input/article.md
+++ b/2-ui/4-forms-controls/3-events-change-input/article.md
@@ -58,31 +58,50 @@ So we can't use `event.preventDefault()` there -- it's just too late, there woul
These events occur on cutting/copying/pasting a value.
-They belong to [ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboard-event-interfaces) class and provide access to the data that is copied/pasted.
+They belong to [ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboard-event-interfaces) class and provide access to the data that is cut/copied/pasted.
We also can use `event.preventDefault()` to abort the action, then nothing gets copied/pasted.
-For instance, the code below prevents all such events and shows what we are trying to cut/copy/paste:
+For instance, the code below prevents all `cut/copy/paste` events and shows the text we're trying to cut/copy/paste:
```html autorun height=40 run
```
-Please note, that it's possible to copy/paste not just text, but everything. For instance, we can copy a file in the OS file manager, and paste it.
+Please note: inside `cut` and `copy` event handlers a call to `event.clipboardData.getData(...)` returns an empty string. That's because technically the data isn't in the clipboard yet. If we use `event.preventDefault()` it won't be copied at all.
-That's because `clipboardData` implements `DataTransfer` interface, commonly used for drag'n'drop and copy/pasting. It's bit beyond our scope now, but you can find its methods [in the specification](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface).
+So the example above uses `document.getSelection()` to get the selected text. You can find more details about document selection in the article .
-```warn header="ClipboardAPI: user safety restrictions"
-The clipboard is a "global" OS-level thing. So most browsers allow read/write access to the clipboard only in the scope of certain user actions for the safety, e.g. in `onclick` event handlers.
+It's possible to copy/paste not just text, but everything. For instance, we can copy a file in the OS file manager, and paste it.
-Also it's forbidden to generate "custom" clipboard events with `dispatchEvent` in all browsers except Firefox.
-```
+That's because `clipboardData` implements `DataTransfer` interface, commonly used for drag'n'drop and copy/pasting. It's a bit beyond our scope now, but you can find its methods in the [DataTransfer specification](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface).
+
+Also, there's an additional asynchronous API of accessing the clipboard: `navigator.clipboard`. More about it in the specification [Clipboard API and events](https://www.w3.org/TR/clipboard-apis/), [not supported by Firefox](https://caniuse.com/async-clipboard).
+
+### Safety restrictions
+
+The clipboard is a "global" OS-level thing. A user may switch between various applications, copy/paste different things, and a browser page shouldn't see all that.
+
+So most browsers allow seamless read/write access to the clipboard only in the scope of certain user actions, such as copying/pasting etc.
+
+It's forbidden to generate "custom" clipboard events with `dispatchEvent` in all browsers except Firefox. And even if we manage to dispatch such event, the specification clearly states that such "syntetic" events must not provide access to the clipboard.
+
+Even if someone decides to save `event.clipboardData` in an event handler, and then access it later -- it won't work.
+
+To reiterate, [event.clipboardData](https://www.w3.org/TR/clipboard-apis/#clipboardevent-clipboarddata) works solely in the context of user-initiated event handlers.
+
+On the other hand, [navigator.clipboard](https://www.w3.org/TR/clipboard-apis/#h-navigator-clipboard) is the more recent API, meant for use in any context. It asks for user permission, if needed.
## Summary
@@ -92,4 +111,4 @@ Data change events:
|---------|----------|-------------|
| `change`| A value was changed. | For text inputs triggers on focus loss. |
| `input` | For text inputs on every change. | Triggers immediately unlike `change`. |
-| `cut/copy/paste` | Cut/copy/paste actions. | The action can be prevented. The `event.clipboardData` property gives read/write access to the clipboard. |
+| `cut/copy/paste` | Cut/copy/paste actions. | The action can be prevented. The `event.clipboardData` property gives access to the clipboard. All browsers except Firefox also support `navigator.clipboard`. |
diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md
index cd926742..42d10fe7 100644
--- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md
+++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md
@@ -88,7 +88,7 @@ But there's a pitfall. If we have a script after the style, then that script mus
```html run
```
@@ -185,6 +185,26 @@ window.onbeforeunload = function() {
The behavior was changed, because some webmasters abused this event handler by showing misleading and annoying messages. So right now old browsers still may show it as a message, but aside of that -- there's no way to customize the message shown to the user.
+````warn header="The `event.preventDefault()` doesn't work from a `beforeunload` handler"
+That may sound weird, but most browsers ignore `event.preventDefault()`.
+
+Which means, following code may not work:
+```js run
+window.addEventListener("beforeunload", (event) => {
+ // doesn't work, so this event handler doesn't do anything
+ event.preventDefault();
+});
+```
+
+Instead, in such handlers one should set `event.returnValue` to a string to get the result similar to the code above:
+```js run
+window.addEventListener("beforeunload", (event) => {
+ // works, same as returning from window.onbeforeunload
+ event.returnValue = "There are unsaved changes. Leave now?";
+});
+```
+````
+
## readyState
What happens if we set the `DOMContentLoaded` handler after the document is loaded?
diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html b/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html
index a4685a71..27df7093 100644
--- a/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html
+++ b/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html
@@ -9,8 +9,8 @@
[20] readyState:interactive
[21] DOMContentLoaded
[30] iframe onload
- [40] readyState:complete
[40] img onload
+ [40] readyState:complete
[40] window onload
-->
diff --git a/2-ui/5-loading/02-script-async-defer/article.md b/2-ui/5-loading/02-script-async-defer/article.md
index 93c32a7f..f97c000d 100644
--- a/2-ui/5-loading/02-script-async-defer/article.md
+++ b/2-ui/5-loading/02-script-async-defer/article.md
@@ -133,8 +133,12 @@ Async scripts are great when we integrate an independent third-party script into
```
+```smart header="The `async` attribute is only for external scripts"
+Just like `defer`, the `async` attribute is ignored if the `