| 1 | 
           efrain | 
           1 | 
           YUI.add('event-key', function (Y, NAME) {
  | 
        
        
            | 
            | 
           2 | 
              | 
        
        
            | 
            | 
           3 | 
           /**
  | 
        
        
            | 
            | 
           4 | 
            * Functionality to listen for one or more specific key combinations.
  | 
        
        
            | 
            | 
           5 | 
            * @module event
  | 
        
        
            | 
            | 
           6 | 
            * @submodule event-key
  | 
        
        
            | 
            | 
           7 | 
            */
  | 
        
        
            | 
            | 
           8 | 
              | 
        
        
            | 
            | 
           9 | 
           var ALT      = "+alt",
  | 
        
        
            | 
            | 
           10 | 
               CTRL     = "+ctrl",
  | 
        
        
            | 
            | 
           11 | 
               META     = "+meta",
  | 
        
        
            | 
            | 
           12 | 
               SHIFT    = "+shift",
  | 
        
        
            | 
            | 
           13 | 
              | 
        
        
            | 
            | 
           14 | 
               trim     = Y.Lang.trim,
  | 
        
        
            | 
            | 
           15 | 
              | 
        
        
            | 
            | 
           16 | 
               eventDef = {
  | 
        
        
            | 
            | 
           17 | 
                   KEY_MAP: {
  | 
        
        
            | 
            | 
           18 | 
                       enter    : 13,
  | 
        
        
            | 
            | 
           19 | 
                       space    : 32,
  | 
        
        
            | 
            | 
           20 | 
                       esc      : 27,
  | 
        
        
            | 
            | 
           21 | 
                       backspace: 8,
  | 
        
        
            | 
            | 
           22 | 
                       tab      : 9,
  | 
        
        
            | 
            | 
           23 | 
                       pageup   : 33,
  | 
        
        
            | 
            | 
           24 | 
                       pagedown : 34
  | 
        
        
            | 
            | 
           25 | 
                   },
  | 
        
        
            | 
            | 
           26 | 
              | 
        
        
            | 
            | 
           27 | 
                   _typeRE: /^(up|down|press):/,
  | 
        
        
            | 
            | 
           28 | 
                   _keysRE: /^(?:up|down|press):|\+(alt|ctrl|meta|shift)/g,
  | 
        
        
            | 
            | 
           29 | 
              | 
        
        
            | 
            | 
           30 | 
                   processArgs: function (args) {
  | 
        
        
            | 
            | 
           31 | 
                       var spec = args.splice(3,1)[0],
  | 
        
        
            | 
            | 
           32 | 
                           mods = Y.Array.hash(spec.match(/\+(?:alt|ctrl|meta|shift)\b/g) || []),
  | 
        
        
            | 
            | 
           33 | 
                           config = {
  | 
        
        
            | 
            | 
           34 | 
                               type: this._typeRE.test(spec) ? RegExp.$1 : null,
  | 
        
        
            | 
            | 
           35 | 
                               mods: mods,
  | 
        
        
            | 
            | 
           36 | 
                               keys: null
  | 
        
        
            | 
            | 
           37 | 
                           },
  | 
        
        
            | 
            | 
           38 | 
                           // strip type and modifiers from spec, leaving only keyCodes
  | 
        
        
            | 
            | 
           39 | 
                           bits = spec.replace(this._keysRE, ''),
  | 
        
        
            | 
            | 
           40 | 
                           chr, uc, lc, i;
  | 
        
        
            | 
            | 
           41 | 
              | 
        
        
            | 
            | 
           42 | 
                       if (bits) {
  | 
        
        
            | 
            | 
           43 | 
                           bits = bits.split(',');
  | 
        
        
            | 
            | 
           44 | 
              | 
        
        
            | 
            | 
           45 | 
                           config.keys = {};
  | 
        
        
            | 
            | 
           46 | 
              | 
        
        
            | 
            | 
           47 | 
                           // FIXME: need to support '65,esc' => keypress, keydown
  | 
        
        
            | 
            | 
           48 | 
                           for (i = bits.length - 1; i >= 0; --i) {
  | 
        
        
            | 
            | 
           49 | 
                               chr = trim(bits[i]);
  | 
        
        
            | 
            | 
           50 | 
              | 
        
        
            | 
            | 
           51 | 
                               // catch sloppy filters, trailing commas, etc 'a,,'
  | 
        
        
            | 
            | 
           52 | 
                               if (!chr) {
  | 
        
        
            | 
            | 
           53 | 
                                   continue;
  | 
        
        
            | 
            | 
           54 | 
                               }
  | 
        
        
            | 
            | 
           55 | 
              | 
        
        
            | 
            | 
           56 | 
                               // non-numerics are single characters or key names
  | 
        
        
            | 
            | 
           57 | 
                               if (+chr == chr) {
  | 
        
        
            | 
            | 
           58 | 
                                   config.keys[chr] = mods;
  | 
        
        
            | 
            | 
           59 | 
                               } else {
  | 
        
        
            | 
            | 
           60 | 
                                   lc = chr.toLowerCase();
  | 
        
        
            | 
            | 
           61 | 
              | 
        
        
            | 
            | 
           62 | 
                                   if (this.KEY_MAP[lc]) {
  | 
        
        
            | 
            | 
           63 | 
                                       config.keys[this.KEY_MAP[lc]] = mods;
  | 
        
        
            | 
            | 
           64 | 
                                       // FIXME: '65,enter' defaults keydown for both
  | 
        
        
            | 
            | 
           65 | 
                                       if (!config.type) {
  | 
        
        
            | 
            | 
           66 | 
                                           config.type = "down"; // safest
  | 
        
        
            | 
            | 
           67 | 
                                       }
  | 
        
        
            | 
            | 
           68 | 
                                   } else {
  | 
        
        
            | 
            | 
           69 | 
                                       // FIXME: Character mapping only works for keypress
  | 
        
        
            | 
            | 
           70 | 
                                       // events. Otherwise, it uses String.fromCharCode()
  | 
        
        
            | 
            | 
           71 | 
                                       // from the keyCode, which is wrong.
  | 
        
        
            | 
            | 
           72 | 
                                       chr = chr.charAt(0);
  | 
        
        
            | 
            | 
           73 | 
                                       uc  = chr.toUpperCase();
  | 
        
        
            | 
            | 
           74 | 
              | 
        
        
            | 
            | 
           75 | 
                                       if (mods["+shift"]) {
  | 
        
        
            | 
            | 
           76 | 
                                           chr = uc;
  | 
        
        
            | 
            | 
           77 | 
                                       }
  | 
        
        
            | 
            | 
           78 | 
              | 
        
        
            | 
            | 
           79 | 
                                       // FIXME: stupid assumption that
  | 
        
        
            | 
            | 
           80 | 
                                       // the keycode of the lower case == the
  | 
        
        
            | 
            | 
           81 | 
                                       // charCode of the upper case
  | 
        
        
            | 
            | 
           82 | 
                                       // a (key:65,char:97), A (key:65,char:65)
  | 
        
        
            | 
            | 
           83 | 
                                       config.keys[chr.charCodeAt(0)] =
  | 
        
        
            | 
            | 
           84 | 
                                           (chr === uc) ?
  | 
        
        
            | 
            | 
           85 | 
                                               // upper case chars get +shift free
  | 
        
        
            | 
            | 
           86 | 
                                               Y.merge(mods, { "+shift": true }) :
  | 
        
        
            | 
            | 
           87 | 
                                               mods;
  | 
        
        
            | 
            | 
           88 | 
                                   }
  | 
        
        
            | 
            | 
           89 | 
                               }
  | 
        
        
            | 
            | 
           90 | 
                           }
  | 
        
        
            | 
            | 
           91 | 
                       }
  | 
        
        
            | 
            | 
           92 | 
              | 
        
        
            | 
            | 
           93 | 
                       if (!config.type) {
  | 
        
        
            | 
            | 
           94 | 
                           config.type = "press";
  | 
        
        
            | 
            | 
           95 | 
                       }
  | 
        
        
            | 
            | 
           96 | 
              | 
        
        
            | 
            | 
           97 | 
                       return config;
  | 
        
        
            | 
            | 
           98 | 
                   },
  | 
        
        
            | 
            | 
           99 | 
              | 
        
        
            | 
            | 
           100 | 
                   on: function (node, sub, notifier, filter) {
  | 
        
        
            | 
            | 
           101 | 
                       var spec   = sub._extra,
  | 
        
        
            | 
            | 
           102 | 
                           type   = "key" + spec.type,
  | 
        
        
            | 
            | 
           103 | 
                           keys   = spec.keys,
  | 
        
        
            | 
            | 
           104 | 
                           method = (filter) ? "delegate" : "on";
  | 
        
        
            | 
            | 
           105 | 
              | 
        
        
            | 
            | 
           106 | 
                       // Note: without specifying any keyCodes, this becomes a
  | 
        
        
            | 
            | 
           107 | 
                       // horribly inefficient alias for 'keydown' (et al), but I
  | 
        
        
            | 
            | 
           108 | 
                       // can't abort this subscription for a simple
  | 
        
        
            | 
            | 
           109 | 
                       // Y.on('keypress', ...);
  | 
        
        
            | 
            | 
           110 | 
                       // Please use keyCodes or just subscribe directly to keydown,
  | 
        
        
            | 
            | 
           111 | 
                       // keyup, or keypress
  | 
        
        
            | 
            | 
           112 | 
                       sub._detach = node[method](type, function (e) {
  | 
        
        
            | 
            | 
           113 | 
                           var key = keys ? keys[e.which] : spec.mods;
  | 
        
        
            | 
            | 
           114 | 
              | 
        
        
            | 
            | 
           115 | 
                           if (key &&
  | 
        
        
            | 
            | 
           116 | 
                               (!key[ALT]   || (key[ALT]   && e.altKey)) &&
  | 
        
        
            | 
            | 
           117 | 
                               (!key[CTRL]  || (key[CTRL]  && e.ctrlKey)) &&
  | 
        
        
            | 
            | 
           118 | 
                               (!key[META]  || (key[META]  && e.metaKey)) &&
  | 
        
        
            | 
            | 
           119 | 
                               (!key[SHIFT] || (key[SHIFT] && e.shiftKey)))
  | 
        
        
            | 
            | 
           120 | 
                           {
  | 
        
        
            | 
            | 
           121 | 
                               notifier.fire(e);
  | 
        
        
            | 
            | 
           122 | 
                           }
  | 
        
        
            | 
            | 
           123 | 
                       }, filter);
  | 
        
        
            | 
            | 
           124 | 
                   },
  | 
        
        
            | 
            | 
           125 | 
              | 
        
        
            | 
            | 
           126 | 
                   detach: function (node, sub, notifier) {
  | 
        
        
            | 
            | 
           127 | 
                       sub._detach.detach();
  | 
        
        
            | 
            | 
           128 | 
                   }
  | 
        
        
            | 
            | 
           129 | 
               };
  | 
        
        
            | 
            | 
           130 | 
              | 
        
        
            | 
            | 
           131 | 
           eventDef.delegate = eventDef.on;
  | 
        
        
            | 
            | 
           132 | 
           eventDef.detachDelegate = eventDef.detach;
  | 
        
        
            | 
            | 
           133 | 
              | 
        
        
            | 
            | 
           134 | 
           /**
  | 
        
        
            | 
            | 
           135 | 
            * <p>Add a key listener.  The listener will only be notified if the
  | 
        
        
            | 
            | 
           136 | 
            * keystroke detected meets the supplied specification.  The
  | 
        
        
            | 
            | 
           137 | 
            * specification is a string that is defined as:</p>
  | 
        
        
            | 
            | 
           138 | 
            *
  | 
        
        
            | 
            | 
           139 | 
            * <dl>
  | 
        
        
            | 
            | 
           140 | 
            *   <dt>spec</dt>
  | 
        
        
            | 
            | 
           141 | 
            *   <dd><code>[{type}:]{code}[,{code}]*</code></dd>
  | 
        
        
            | 
            | 
           142 | 
            *   <dt>type</dt>
  | 
        
        
            | 
            | 
           143 | 
            *   <dd><code>"down", "up", or "press"</code></dd>
  | 
        
        
            | 
            | 
           144 | 
            *   <dt>code</dt>
  | 
        
        
            | 
            | 
           145 | 
            *   <dd><code>{keyCode|character|keyName}[+{modifier}]*</code></dd>
  | 
        
        
            | 
            | 
           146 | 
            *   <dt>modifier</dt>
  | 
        
        
            | 
            | 
           147 | 
            *   <dd><code>"shift", "ctrl", "alt", or "meta"</code></dd>
  | 
        
        
            | 
            | 
           148 | 
            *   <dt>keyName</dt>
  | 
        
        
            | 
            | 
           149 | 
            *   <dd><code>"enter", "space", "backspace", "esc", "tab", "pageup", or "pagedown"</code></dd>
  | 
        
        
            | 
            | 
           150 | 
            * </dl>
  | 
        
        
            | 
            | 
           151 | 
            *
  | 
        
        
            | 
            | 
           152 | 
            * <p>Examples:</p>
  | 
        
        
            | 
            | 
           153 | 
            * <ul>
  | 
        
        
            | 
            | 
           154 | 
            *   <li><code>Y.on("key", callback, "press:12,65+shift+ctrl", "#my-input");</code></li>
  | 
        
        
            | 
            | 
           155 | 
            *   <li><code>Y.delegate("key", preventSubmit, "#forms", "enter", "input[type=text]");</code></li>
  | 
        
        
            | 
            | 
           156 | 
            *   <li><code>Y.one("doc").on("key", viNav, "j,k,l,;");</code></li>
  | 
        
        
            | 
            | 
           157 | 
            * </ul>
  | 
        
        
            | 
            | 
           158 | 
            *
  | 
        
        
            | 
            | 
           159 | 
            * @event key
  | 
        
        
            | 
            | 
           160 | 
            * @for YUI
  | 
        
        
            | 
            | 
           161 | 
            * @param type {string} 'key'
  | 
        
        
            | 
            | 
           162 | 
            * @param fn {function} the function to execute
  | 
        
        
            | 
            | 
           163 | 
            * @param id {string|HTMLElement|collection} the element(s) to bind
  | 
        
        
            | 
            | 
           164 | 
            * @param spec {string} the keyCode and modifier specification
  | 
        
        
            | 
            | 
           165 | 
            * @param o optional context object
  | 
        
        
            | 
            | 
           166 | 
            * @param args 0..n additional arguments to provide to the listener.
  | 
        
        
            | 
            | 
           167 | 
            * @return {Event.Handle} the detach handle
  | 
        
        
            | 
            | 
           168 | 
            */
  | 
        
        
            | 
            | 
           169 | 
           Y.Event.define('key', eventDef, true);
  | 
        
        
            | 
            | 
           170 | 
              | 
        
        
            | 
            | 
           171 | 
              | 
        
        
            | 
            | 
           172 | 
           }, '3.18.1', {"requires": ["event-synthetic"]});
  |