f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith * Provides extended keyboard support for the "contextmenu" event such that:
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith * <li>The browser's default context menu is suppressed regardless of how the event is triggered.</li>
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith * <li>On Windows the "contextmenu" event is fired consistently regardless of whether the user pressed the Menu key or Shift + F10.</li>
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith * <li>When the "contextmenu" event is fired via the keyboard, the pageX, pageY, clientX and clientY properties reference the center of the event target. This makes it easy for "contextmenu" event listeners to position an overlay in response to the event by not having to worry about special handling of the x and y coordinates based on the device that fired the event.</li>
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith * <li>For Webkit and Gecko on the Mac it enables the use of the Shift + Control + Option + M keyboard shortcut to fire the "contextmenu" event, which (by default) is only available when VoiceOver (the screen reader on the Mac) is enabled.</li>
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith * <li>For Opera on the Mac it ensures the "contextmenu" event is fired when the user presses Shift + Command + M (Opera's context menu keyboard shortcut).</li>
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith * @module event-contextmenu
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith * @requires event
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith on: function (node, subscription, notifier, filter) {
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith handles.push(Event._attach(["contextmenu", function (e) {
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // Any developer listening for the "contextmenu" event is likely
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // going to call preventDefault() to prevent the display of
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // the browser's context menu. So, you know, save them a step.
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith handles.push(node[filter ? "delegate" : "on"]("keydown", function (e) {
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith macWebkitAndGeckoShortcut = (isMac && (webkit || gecko) && ctrlKey && shiftKey && e.altKey && mKey),
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // Note: The context menu keyboard shortcut for Opera on the Mac is Shift + Cmd (metaKey) + M,
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // but e.metaKey is false for Opera, and Opera sets e.ctrlKey to true instead.
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith macOperaShortcut = (isMac && opera && ctrlKey && shiftKey && mKey),
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith (macWebkitAndGeckoShortcut || macOperaShortcut)) {
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // Need to call preventDefault() here b/c:
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // 1) To prevent IE's menubar from gaining focus when the
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // user presses Shift + F10
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // 2) In Firefox and Opera for Win, Shift + F10 will display a
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // context menu, but won't fire the "contextmenu" event. So, need
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // to call preventDefault() to prevent the display of the
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // browser's context menu
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // 3) For Opera on the Mac the context menu keyboard shortcut
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // (Shift + Cmd + M) will display a context menu, but like Firefox
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // and Opera on windows, Opera doesn't fire a "contextmenu" event,
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // so preventDefault() is just used to supress Opera's
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // default context menu.
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith if (((ie || (isWin && (gecko || opera))) && shiftF10) || macOperaShortcut) {
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // Protect against instances where xy and might not be returned,
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // for example if the target is the document.
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith clientX = (x + (target.offsetWidth/2)) - scrollX;
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith clientY = (y + (target.offsetHeight/2)) - scrollY;
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // When the "contextmenu" event is fired from the keyboard
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // clientX, clientY, pageX or pageY aren't set to useful
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // values. So, we follow Safari's model here of setting
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // the x & x coords to the center of the event target.
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // Don't need to call notifier.fire(e) when the Menu key
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // is pressed as it fires the "contextmenu" event by default.
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // In IE the call to preventDefault() for Shift + F10
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // prevents the "contextmenu" event from firing, so we need
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith // to call notifier.fire(e)
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // Need to also call notifier.fire(e) for Gecko and Opera since
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // neither Shift + F10 or Shift + Cmd + M fire the "contextmenu" event.
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // Lastly, also need to call notifier.fire(e) for all Mac browsers
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // since neither Shift + Ctrl + Option + M (Webkit and Gecko) or
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith // Shift + Command + M (Opera) fire the "contextmenu" event.
2b57c2557a233b760f9178d792804d2c402f2d9cLuke Smith if (((ie || (isWin && (gecko || opera))) && shiftF10) || isMac) {
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith detach: function (node, subscription, notifier) {
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith Y.each(subscription._handles, function (handle) {
f66812a0791dd11c23b677fc167c30a4aff065f8Luke Smith}, '@VERSION@' ,{requires:['event-synthetic', 'dom-screen']});