| 1 | efrain | 1 | YUI.add('event-contextmenu', function (Y, NAME) {
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | /**
 | 
        
           |  |  | 4 |  * Provides extended keyboard support for the "contextmenu" event such that:
 | 
        
           |  |  | 5 |  * <ul>
 | 
        
           |  |  | 6 |  * <li>The browser's default context menu is suppressed regardless of how the event is triggered.</li>
 | 
        
           |  |  | 7 |  * <li>On Windows the "contextmenu" event is fired consistently regardless of whether the user
 | 
        
           |  |  | 8 |  * pressed the Menu key or Shift + F10.</li>
 | 
        
           |  |  | 9 |  * <li>When the "contextmenu" event is fired via the keyboard, the pageX, pageY, clientX and clientY
 | 
        
           |  |  | 10 |  * properties reference the center of the event target. This makes it easy for "contextmenu" event listeners
 | 
        
           |  |  | 11 |  * to position an overlay in response to the event by not having to worry about special handling of the x
 | 
        
           |  |  | 12 |  * and y coordinates based on the device that fired the event.</li>
 | 
        
           |  |  | 13 |  * <li>For Webkit and Gecko on the Mac it enables the use of the Shift + Control + Option + M keyboard
 | 
        
           |  |  | 14 |  * shortcut to fire the "contextmenu" event, which (by default) is only available when VoiceOver
 | 
        
           |  |  | 15 |  * (the screen reader on the Mac) is enabled.</li>
 | 
        
           |  |  | 16 |  * <li>For Opera on the Mac it ensures the "contextmenu" event is fired when the user presses
 | 
        
           |  |  | 17 |  * Shift + Command + M (Opera's context menu keyboard shortcut).</li>
 | 
        
           |  |  | 18 |  * </ul>
 | 
        
           |  |  | 19 |  * @module event-contextmenu
 | 
        
           |  |  | 20 |  * @requires event
 | 
        
           |  |  | 21 |  */
 | 
        
           |  |  | 22 |   | 
        
           |  |  | 23 | var Event = Y.Event,
 | 
        
           |  |  | 24 |     DOM = Y.DOM,
 | 
        
           |  |  | 25 |     UA = Y.UA,
 | 
        
           |  |  | 26 |     OS = Y.UA.os,
 | 
        
           |  |  | 27 |   | 
        
           |  |  | 28 |     ie = UA.ie,
 | 
        
           |  |  | 29 |     gecko = UA.gecko,
 | 
        
           |  |  | 30 |     webkit = UA.webkit,
 | 
        
           |  |  | 31 |     opera = UA.opera,
 | 
        
           |  |  | 32 |   | 
        
           |  |  | 33 |     isWin = (OS === "windows"),
 | 
        
           |  |  | 34 |     isMac = (OS === "macintosh"),
 | 
        
           |  |  | 35 |   | 
        
           |  |  | 36 |     eventData = {},
 | 
        
           |  |  | 37 |   | 
        
           |  |  | 38 |     conf = {
 | 
        
           |  |  | 39 |   | 
        
           |  |  | 40 |         on: function (node, subscription, notifier, filter) {
 | 
        
           |  |  | 41 |   | 
        
           |  |  | 42 |             var handles = [];
 | 
        
           |  |  | 43 |   | 
        
           |  |  | 44 |             handles.push(Event._attach(["contextmenu", function (e) {
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 |                 // Any developer listening for the "contextmenu" event is likely
 | 
        
           |  |  | 47 |                 // going to call preventDefault() to prevent the display of
 | 
        
           |  |  | 48 |                 // the browser's context menu. So, you know, save them a step.
 | 
        
           |  |  | 49 |                 e.preventDefault();
 | 
        
           |  |  | 50 |   | 
        
           |  |  | 51 |                 var id = Y.stamp(node),
 | 
        
           |  |  | 52 |                     data = eventData[id];
 | 
        
           |  |  | 53 |   | 
        
           |  |  | 54 |                 if (data) {
 | 
        
           |  |  | 55 |                     e.clientX = data.clientX;
 | 
        
           |  |  | 56 |                     e.clientY = data.clientY;
 | 
        
           |  |  | 57 |                     e.pageX = data.pageX;
 | 
        
           |  |  | 58 |                     e.pageY = data.pageY;
 | 
        
           |  |  | 59 |                     delete eventData[id];
 | 
        
           |  |  | 60 |                 }
 | 
        
           |  |  | 61 |   | 
        
           |  |  | 62 |                 notifier.fire(e);
 | 
        
           |  |  | 63 |   | 
        
           |  |  | 64 |             }, node]));
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 |   | 
        
           |  |  | 67 |             handles.push(node[filter ? "delegate" : "on"]("keydown", function (e) {
 | 
        
           |  |  | 68 |   | 
        
           |  |  | 69 |                 var target = this.getDOMNode(),
 | 
        
           |  |  | 70 |                     shiftKey = e.shiftKey,
 | 
        
           |  |  | 71 |                     keyCode = e.keyCode,
 | 
        
           |  |  | 72 |                     shiftF10 = (shiftKey && keyCode == 121),
 | 
        
           |  |  | 73 |                     menuKey = (isWin && keyCode == 93),
 | 
        
           |  |  | 74 |                     ctrlKey = e.ctrlKey,
 | 
        
           |  |  | 75 |                     mKey = (keyCode === 77),
 | 
        
           |  |  | 76 |                     macWebkitAndGeckoShortcut = (isMac && (webkit || gecko) && ctrlKey && shiftKey && e.altKey && mKey),
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 |                     // Note: The context menu keyboard shortcut for Opera on the Mac is Shift + Cmd (metaKey) + M,
 | 
        
           |  |  | 79 |                     // but e.metaKey is false for Opera, and Opera sets e.ctrlKey to true instead.
 | 
        
           |  |  | 80 |                     macOperaShortcut = (isMac && opera && ctrlKey && shiftKey && mKey),
 | 
        
           |  |  | 81 |   | 
        
           |  |  | 82 |                     clientX = 0,
 | 
        
           |  |  | 83 |                     clientY = 0,
 | 
        
           |  |  | 84 |                     scrollX,
 | 
        
           |  |  | 85 |                     scrollY,
 | 
        
           |  |  | 86 |                     pageX,
 | 
        
           |  |  | 87 |                     pageY,
 | 
        
           |  |  | 88 |                     xy,
 | 
        
           |  |  | 89 |                     x,
 | 
        
           |  |  | 90 |                     y;
 | 
        
           |  |  | 91 |   | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 |                 if ((isWin && (shiftF10 || menuKey)) ||
 | 
        
           |  |  | 94 |                         (macWebkitAndGeckoShortcut || macOperaShortcut)) {
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 |                     // Need to call preventDefault() here b/c:
 | 
        
           |  |  | 97 |                     // 1) To prevent IE's menubar from gaining focus when the
 | 
        
           |  |  | 98 |                     // user presses Shift + F10
 | 
        
           |  |  | 99 |                     // 2) In Firefox and Opera for Win, Shift + F10 will display a
 | 
        
           |  |  | 100 |                     // context menu, but won't fire the "contextmenu" event. So, need
 | 
        
           |  |  | 101 |                     // to call preventDefault() to prevent the display of the
 | 
        
           |  |  | 102 |                     // browser's context menu
 | 
        
           |  |  | 103 |                     // 3) For Opera on the Mac the context menu keyboard shortcut
 | 
        
           |  |  | 104 |                     // (Shift + Cmd + M) will display a context menu, but like Firefox
 | 
        
           |  |  | 105 |                     // and Opera on windows, Opera doesn't fire a "contextmenu" event,
 | 
        
           |  |  | 106 |                     // so preventDefault() is just used to supress Opera's
 | 
        
           |  |  | 107 |                     // default context menu.
 | 
        
           |  |  | 108 |                     if (((ie || (isWin && (gecko || opera))) && shiftF10) || macOperaShortcut) {
 | 
        
           |  |  | 109 |                         e.preventDefault();
 | 
        
           |  |  | 110 |                     }
 | 
        
           |  |  | 111 |   | 
        
           |  |  | 112 |                     xy = DOM.getXY(target);
 | 
        
           |  |  | 113 |                     x = xy[0];
 | 
        
           |  |  | 114 |                     y = xy[1];
 | 
        
           |  |  | 115 |                     scrollX = DOM.docScrollX();
 | 
        
           |  |  | 116 |                     scrollY = DOM.docScrollY();
 | 
        
           |  |  | 117 |   | 
        
           |  |  | 118 |                     // Protect against instances where xy and might not be returned,
 | 
        
           |  |  | 119 |                     // for example if the target is the document.
 | 
        
           |  |  | 120 |                     if (!Y.Lang.isUndefined(x)) {
 | 
        
           |  |  | 121 |                         clientX = (x + (target.offsetWidth/2)) - scrollX;
 | 
        
           |  |  | 122 |                         clientY = (y + (target.offsetHeight/2)) - scrollY;
 | 
        
           |  |  | 123 |                     }
 | 
        
           |  |  | 124 |   | 
        
           |  |  | 125 |                     pageX = clientX + scrollX;
 | 
        
           |  |  | 126 |                     pageY = clientY + scrollY;
 | 
        
           |  |  | 127 |   | 
        
           |  |  | 128 |                     // When the "contextmenu" event is fired from the keyboard
 | 
        
           |  |  | 129 |                     // clientX, clientY, pageX or pageY aren't set to useful
 | 
        
           |  |  | 130 |                     // values. So, we follow Safari's model here of setting
 | 
        
           |  |  | 131 |                     // the x & x coords to the center of the event target.
 | 
        
           |  |  | 132 |   | 
        
           |  |  | 133 |                     if (menuKey || (isWin && webkit && shiftF10)) {
 | 
        
           |  |  | 134 |                         eventData[Y.stamp(node)] = {
 | 
        
           |  |  | 135 |                             clientX: clientX,
 | 
        
           |  |  | 136 |                             clientY: clientY,
 | 
        
           |  |  | 137 |                             pageX: pageX,
 | 
        
           |  |  | 138 |                             pageY: pageY
 | 
        
           |  |  | 139 |                         };
 | 
        
           |  |  | 140 |                     }
 | 
        
           |  |  | 141 |   | 
        
           |  |  | 142 |                     // Don't need to call notifier.fire(e) when the Menu key
 | 
        
           |  |  | 143 |                     // is pressed as it fires the "contextmenu" event by default.
 | 
        
           |  |  | 144 |                     //
 | 
        
           |  |  | 145 |                     // In IE the call to preventDefault() for Shift + F10
 | 
        
           |  |  | 146 |                     // prevents the "contextmenu" event from firing, so we need
 | 
        
           |  |  | 147 |                     // to call notifier.fire(e)
 | 
        
           |  |  | 148 |                     //
 | 
        
           |  |  | 149 |                     // Need to also call notifier.fire(e) for Gecko and Opera since
 | 
        
           |  |  | 150 |                     // neither Shift + F10 or Shift + Cmd + M fire the "contextmenu" event.
 | 
        
           |  |  | 151 |                     //
 | 
        
           |  |  | 152 |                     // Lastly, also need to call notifier.fire(e) for all Mac browsers
 | 
        
           |  |  | 153 |                     // since neither Shift + Ctrl + Option + M (Webkit and Gecko) or
 | 
        
           |  |  | 154 |                     // Shift + Command + M (Opera) fire the "contextmenu" event.
 | 
        
           |  |  | 155 |   | 
        
           |  |  | 156 |                     if (((ie || (isWin && (gecko || opera))) && shiftF10) || isMac) {
 | 
        
           |  |  | 157 |   | 
        
           |  |  | 158 |                         e.clientX = clientX;
 | 
        
           |  |  | 159 |                         e.clientY = clientY;
 | 
        
           |  |  | 160 |                         e.pageX = pageX;
 | 
        
           |  |  | 161 |                         e.pageY = pageY;
 | 
        
           |  |  | 162 |   | 
        
           |  |  | 163 |                         notifier.fire(e);
 | 
        
           |  |  | 164 |                     }
 | 
        
           |  |  | 165 |   | 
        
           |  |  | 166 |                 }
 | 
        
           |  |  | 167 |   | 
        
           |  |  | 168 |             }, filter));
 | 
        
           |  |  | 169 |   | 
        
           |  |  | 170 |             subscription._handles = handles;
 | 
        
           |  |  | 171 |   | 
        
           |  |  | 172 |         },
 | 
        
           |  |  | 173 |   | 
        
           |  |  | 174 |         detach: function (node, subscription, notifier) {
 | 
        
           |  |  | 175 |   | 
        
           |  |  | 176 |             Y.each(subscription._handles, function (handle) {
 | 
        
           |  |  | 177 |                 handle.detach();
 | 
        
           |  |  | 178 |             });
 | 
        
           |  |  | 179 |   | 
        
           |  |  | 180 |         }
 | 
        
           |  |  | 181 |   | 
        
           |  |  | 182 |     };
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 |   | 
        
           |  |  | 185 | conf.delegate = conf.on;
 | 
        
           |  |  | 186 | conf.detachDelegate = conf.detach;
 | 
        
           |  |  | 187 |   | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 | Event.define("contextmenu", conf, true);
 | 
        
           |  |  | 190 |   | 
        
           |  |  | 191 |   | 
        
           |  |  | 192 | }, '3.18.1', {"requires": ["event-synthetic", "dom-screen"]});
 |