Right-click here for the document context menu
+ + + +``` + +The problem is that when we click on `elem`, we get two menus: the button-level and (the event bubbles up) the document-level menu. + +How to fix it? One of solutions is to think like: "We fully handle the event in the button handler, let's stop it" and use `event.stopPropagation()`: + +```html autorun height=80 no-beautify run +Right-click for the document menu
+ + + +``` + +Now the button-level menu works as intended. But the price is high. We forever deny access to information about right-clicks for any outer code, including counters that gather statistics and so on. That's quite unwise. + +An alternative solution would be to check in the `document` handler if the default action was prevented? If it is so, then the event was handled, and we don't need to react on it. + + +```html autorun height=80 no-beautify run +Right-click for the document menu (fixed with event.defaultPrevented)
+ + + +``` + +Now everything also works correctly. If we have nested elements, and each of them has a context menu of its own, that would also work. Just make sure to check for `event.defaultPrevented` in each `contextmenu` handler. + +```smart header="event.stopPropagation() and event.preventDefault()" +As we can clearly see, `event.stopPropagation()` and `event.preventDefault()` (also known as `return false`) are two different things. They are not related to each other. +``` + +```smart header="Nested context menus architecture" +There are also alternative ways to implement nested context menus. One of them is to have a special global object with a method that handles `document.oncontextmenu`, and also methods that allow to store various "lower-level" handlers in it. + +The object will catch any right-click, look through stored handlers and run the appropriate one. + +But then each piece of code that wants a context menu should know about that object and use its help instead of the own `contextmenu` handler. +``` + ## Summary -- Browser has default actions for many events -- following a link, submitting a form etc. -- To prevent a default action -- use either `event.preventDefault()` or `return false`. The second method works only for handlers assigned with `on|\ /| \|_|/ @@ -187,46 +187,49 @@ The `detail` can be anything. Once again, technically we can assign any properti``` +## Summary +To generate an event, we first need to create an event object. +The generic `Event(name, options)` constructor accepts an arbitrary event name and the `options` object with two properties: + - `bubbles:true` if the event should bubble. + - `cancelable:true` is the `event.preventDefault()` should work. +Other constructors of native events like `MouseEvent`, `KeyboardEvent` and so on accept properties specific to that event type. For instance, `clientX` for mouse events. -## Итого +For custom events we should use `CustomEvent` constructor. It has an additional option named `detail`, we should assign the event-specific data to it. Then all handlers can access it as `event.detail`. -- Все браузеры, кроме IE9-11, позволяют генерировать любые события, следуя стандарту DOM4. -- В IE9+ поддерживается более старый стандарт, можно легко сделать полифилл, например для `CustomEvent` он рассмотрен в этой главе. -- IE8- может генерировать только встроенные события. +Despite the technical possibility to generate browser events like `click` or `keydown`, we should use with the great care. -Несмотря на техническую возможность генерировать встроенные браузерные события типа `click` или `keydown` -- пользоваться ей стоит с большой осторожностью. +We shouldn't generate browser events as a hacky way to run handlers. That's a bad architecture most of the time. -В 98% случаев, когда разработчик начинающего или среднего уровня хочет сгенерировать *встроенное* событие -- это вызвано "кривой" архитектурой кода, и взаимодействие нужно на уровне выше. +Native events might be generated: -Как правило события имеет смысл генерировать: +- As a dirty hack to make 3rd-party libraries work the needed way, if they don't provide other means of interaction. +- For automated testing, to "click the button" in the script and see if the interface reacts correctly. -- Либо как явный и грубый хак, чтобы заставить работать сторонние библиотеки, в которых не предусмотрены другие средства взаимодействия. -- Либо для автоматического тестирования, чтобы скриптом "нажать на кнопку" и посмотреть, произошло ли нужное действие. -- Либо при создании своих "элементов интерфейса". Например, никто не мешает при помощи JavaScript создать из `