Skip to content

Commit

Permalink
minor
Browse files Browse the repository at this point in the history
  • Loading branch information
iliakan committed Aug 14, 2019
1 parent 4635abd commit aa4273f
Showing 1 changed file with 32 additions and 79 deletions.
111 changes: 32 additions & 79 deletions 2-ui/3-event-details/1-mouse-events-basics/article.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# Mouse events basics

Mouse events come not only from "mouse manipulators", but are also emulated on touch devices, to make them compatible.

In this chapter we'll get into more details about mouse events and their properties.

Please note: such events may come not only from "mouse devices", but are also from other devices, such as phones and tablets, where they are emulated for compatibility.

## Mouse event types

We can split mouse events into two categories: "simple" and "complex"
Expand Down Expand Up @@ -42,7 +42,7 @@ An action may trigger multiple events.

For instance, a click first triggers `mousedown`, when the button is pressed, then `mouseup` and `click` when it's released.

In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order `mousedown` -> `mouseup` -> `click`. Events are handled in the same sequence: `onmouseup` finishes before `onclick` runs.
In cases when a single action initiates multiple events, their order is fixed. That is, the handlers are called in the order `mousedown` -> `mouseup` -> `click`.

```online
Click the button below and you'll see the events. Try double-click too.
Expand Down Expand Up @@ -74,12 +74,14 @@ The middle button is somewhat exotic right now and is very rarely used.

All mouse events include the information about pressed modifier keys.

The properties are:
Event properties:

- `shiftKey`
- `altKey`
- `ctrlKey`
- `metaKey` (`key:Cmd` for Mac)
- `shiftKey`: `key:Shift`
- `altKey`: `key:Alt` (or `key:Opt` for Mac)
- `ctrlKey`: `key:Ctrl`
- `metaKey`: `key:Cmd` for Mac

They are `true` if the corresponding key was pressed during the event.

For instance, the button below only works on `key:Alt+Shift`+click:

Expand All @@ -98,15 +100,17 @@ For instance, the button below only works on `key:Alt+Shift`+click:
```

```warn header="Attention: on Mac it's usually `Cmd` instead of `Ctrl`"
On Windows and Linux there are modifier keys `key:Alt`, `key:Shift` and `key:Ctrl`. On Mac there's one more: `key:Cmd`, it corresponds to the property `metaKey`.
On Windows and Linux there are modifier keys `key:Alt`, `key:Shift` and `key:Ctrl`. On Mac there's one more: `key:Cmd`, corresponding to the property `metaKey`.

In most applications, when Windows/Linux uses `key:Ctrl`, on Mac `key:Cmd` is used.

In most cases when Windows/Linux uses `key:Ctrl`, on Mac people use `key:Cmd`. So where a Windows user presses `key:Ctrl+Enter` or `key:Ctrl+A`, a Mac user would press `key:Cmd+Enter` or `key:Cmd+A`, and so on, most apps use `key:Cmd` instead of `key:Ctrl`.
That is: where a Windows user presses `key:Ctrl+Enter` or `key:Ctrl+A`, a Mac user would press `key:Cmd+Enter` or `key:Cmd+A`, and so on.

So if we want to support combinations like `key:Ctrl`+click, then for Mac it makes sense to use `key:Cmd`+click. That's more comfortable for Mac users.
So if we want to support combinations like `key:Ctrl`+click, then for Mac it makes sense to use `key:Cmd`+click. That's more comfortable for Mac users.

Even if we'd like to force Mac users to `key:Ctrl`+click -- that's kind of difficult. The problem is: a left-click with `key:Ctrl` is interpreted as a *right-click* on Mac, and it generates the `contextmenu` event, not `click` like Windows/Linux.
Even if we'd like to force Mac users to `key:Ctrl`+click -- that's kind of difficult. The problem is: a left-click with `key:Ctrl` is interpreted as a *right-click* on MacOS, and it generates the `contextmenu` event, not `click` like Windows/Linux.

So if we want users of all operational systems to feel comfortable, then together with `ctrlKey` we should use `metaKey`.
So if we want users of all operational systems to feel comfortable, then together with `ctrlKey` we should check `metaKey`.

For JS-code it means that we should check `if (event.ctrlKey || event.metaKey)`.
```
Expand All @@ -126,60 +130,30 @@ All mouse events have coordinates in two flavours:
For instance, if we have a window of the size 500x500, and the mouse is in the left-upper corner, then `clientX` and `clientY` are `0`. And if the mouse is in the center, then `clientX` and `clientY` are `250`, no matter what place in the document it is, how far the document was scrolled. They are similar to `position:fixed`.

````online
Move the mouse over the input field to see `clientX/clientY` (it's in the `iframe`, so coordinates are relative to that `iframe`):
Move the mouse over the input field to see `clientX/clientY` (the example is in the `iframe`, so coordinates are relative to that `iframe`):
```html autorun height=50
<input onmousemove="this.value=event.clientX+':'+event.clientY" value="Mouse over me">
```
````

Document-relative coordinates are counted from the left-upper corner of the document, not the window.
Coordinates `pageX`, `pageY` are similar to `position:absolute` on the document level.
Document-relative coordinates `pageX`, `pageY` are counted from the left-upper corner of the document, not the window. You can read more about coordinates in the chapter <info:coordinates>.

You can read more about coordinates in the chapter <info:coordinates>.
## Disabling selection

## Disabling selection on mousedown

Mouse clicks have a side-effect that may be disturbing in some interfaces: a double click selects the text.

If we want to handle click events ourselves, then the "extra" selection doesn't look good.
Double mouse click has a side-effect that may be disturbing in some interfaces: it selects the text.

For instance, a double-click on the text below selects it in addition to our handler:

```html autorun height=50
<b ondblclick="alert('dblclick')">Double-click me</b>
```

There's a CSS way to stop the selection: the `user-select` property from [CSS UI Draft](https://www.w3.org/TR/css-ui-4/).

Most browsers support it with prefixes:

```html autorun height=50
<style>
b {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
</style>

Before...
<b ondblclick="alert('Test')">
Unselectable
</b>
...After
<span ondblclick="alert('dblclick')">Double-click me</span>
```

Now if you double-click on "Unselectable", it doesn't get selected. Seems to work.
If one presses the left mouse button and, without releasing it, moves the mouse, that also makes the selection, often unwanted.

...But there is a potential problem! The text became truly unselectable. Even if a user starts the selection from "Before" and ends with "After", the selection skips "Unselectable" part. Do we really want to make our text unselectable?
There are multiple ways to prevent the selection, that you can read in the chapter <info:selection-range>.

Most of time, we don't. A user may have valid reasons to select the text, for copying or other needs. That may be inconvenient if we don't allow them to do it. So this solution is not that good.

What we want is to prevent the selection on double-click, that's it.

A text selection is the default browser action on `mousedown` event. So the alternative solution would be to handle `mousedown` and prevent it, like this:
In this particular case the most reasonable way is to prevent the browser action on `mousedown`. It prevents both these selections:

```html autorun height=50
Before...
Expand All @@ -189,28 +163,12 @@ Before...
...After
```

Now the bold element is not selected on double clicks.

The text inside it is still selectable. However, the selection should start not on the text itself, but before or after it. Usually that's fine for users.

````smart header="Canceling the selection"
Instead of *preventing* the selection, we can cancel it "post-factum" in the event handler.
Here's how:
```html autorun height=50
Before...
<b ondblclick="*!*getSelection().removeAllRanges()*/!*">
Double-click me
</b>
...After
```
Now the bold element is not selected on double clicks, and pressing the left button on it won't start the selection.

If you double-click on the bold element, then the selection appears and then is immediately removed. That doesn't look nice though.
````
Please note: the text inside it is still selectable. However, the selection should start not on the text itself, but before or after it. Usually that's fine for users.

````smart header="Preventing copying"
If we want to disable selection to protect our content from copy-pasting, then we can use another event: `oncopy`.
If we want to disable selection to protect our page content from copy-pasting, then we can use another event: `oncopy`.
```html autorun height=80 no-beautify
<div *!*oncopy="alert('Copying forbidden!');return false"*/!*>
Expand All @@ -221,7 +179,7 @@ If we want to disable selection to protect our content from copy-pasting, then w
```
If you try to copy a piece of text in the `<div>`, that won't work, because the default action `oncopy` is prevented.
Surely that can't stop the user from opening HTML-source, but not everyone knows how to do it.
Surely the user has access to HTML-source of the page, and can take the content from there, but not everyone knows how to do it.
````

## Summary
Expand All @@ -230,16 +188,11 @@ Mouse events have the following properties:

- Button: `which`.
- Modifier keys (`true` if pressed): `altKey`, `ctrlKey`, `shiftKey` and `metaKey` (Mac).
- If you want to handle `key:Ctrl`, then don't forget Mac users, they use `key:Cmd`, so it's better to check `if (e.metaKey || e.ctrlKey)`.
- If you want to handle `key:Ctrl`, then don't forget Mac users, they usually use `key:Cmd`, so it's better to check `if (e.metaKey || e.ctrlKey)`.

- Window-relative coordinates: `clientX/clientY`.
- Document-relative coordinates: `pageX/pageY`.

It's also important to deal with text selection, it may be an unwanted side-effect of clicks.

There are several ways to do this, for instance:
1. The CSS-property `user-select:none` (with browser prefixes) completely disables text-selection.
2. Cancel the selection post-factum using `getSelection().removeAllRanges()`.
3. Handle `mousedown` and prevent the default action (usually the best).
The default browser action of `mousedown` is text selection, if it's not good for the interface, then it should be prevented.

The selection is a separate topic, covered in another chapter <info:selection-range>.
In the next chapter we'll see more details about events that follow pointer movement and how to track element changes under it.

0 comments on commit aa4273f

Please sign in to comment.