[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/webroot/rsrc/js/core/ -> KeyboardShortcutManager.js (source)

   1  /**
   2   * @provides phabricator-keyboard-shortcut-manager
   3   * @requires javelin-install
   4   *           javelin-util
   5   *           javelin-stratcom
   6   *           javelin-dom
   7   *           javelin-vector
   8   * @javelin
   9   */
  10  
  11  JX.install('KeyboardShortcutManager', {
  12  
  13    construct : function() {
  14      this._shortcuts = [];
  15  
  16      JX.Stratcom.listen('keypress', null, JX.bind(this, this._onkeypress));
  17      JX.Stratcom.listen('keydown', null, JX.bind(this, this._onkeydown));
  18      JX.Stratcom.listen('keyup', null, JX.bind(this, this._onkeyup));
  19    },
  20  
  21    statics : {
  22      _instance : null,
  23  
  24      /**
  25       * Some keys don't invoke keypress events in some browsers. We handle these
  26       * on keydown instead of keypress.
  27       */
  28      _downkeys : {
  29        left: 1,
  30        right: 1,
  31        up: 1,
  32        down: 1
  33      },
  34  
  35      getInstance : function() {
  36        if (!JX.KeyboardShortcutManager._instance) {
  37          JX.KeyboardShortcutManager._instance = new JX.KeyboardShortcutManager();
  38        }
  39        return JX.KeyboardShortcutManager._instance;
  40      }
  41    },
  42  
  43    members : {
  44      _shortcuts : null,
  45      _focusReticle : null,
  46  
  47      /**
  48       * Instead of calling this directly, you should call
  49       * KeyboardShortcut.register().
  50       */
  51      addKeyboardShortcut : function(s) {
  52        this._shortcuts.push(s);
  53      },
  54      getShortcutDescriptions : function() {
  55        var desc = [];
  56        for (var ii = 0; ii < this._shortcuts.length; ii++) {
  57          desc.push({
  58            keys : this._shortcuts[ii].getKeys(),
  59            description : this._shortcuts[ii].getDescription()
  60          });
  61        }
  62        return desc;
  63      },
  64  
  65      /**
  66       * Scroll an element into view.
  67       */
  68      scrollTo : function(node) {
  69        window.scrollTo(0, JX.$V(node).y - 60);
  70      },
  71  
  72      /**
  73       * Move the keyboard shortcut focus to an element.
  74       *
  75       * @param Node Node to focus, or pass null to clear the focus.
  76       * @param Node To focus multiple nodes (like rows in a table), specify the
  77       *             top-left node as the first parameter and the bottom-right
  78       *             node as the focus extension.
  79       * @return void
  80       */
  81      focusOn : function(node, extended_node) {
  82        this._clearReticle();
  83  
  84        if (!node) {
  85          return;
  86        }
  87  
  88        var r = JX.$N('div', {className : 'keyboard-focus-focus-reticle'});
  89  
  90        extended_node = extended_node || node;
  91  
  92        // Outset the reticle some pixels away from the element, so there's some
  93        // space between the focused element and the outline.
  94        var p  = JX.Vector.getPos(node);
  95        p.add(-4, -4).setPos(r);
  96        // Compute the size we need to extend to the full extent of the focused
  97        // nodes.
  98        JX.Vector.getPos(extended_node)
  99          .add(-p.x, -p.y)
 100          .add(JX.Vector.getDim(extended_node))
 101          .add(8, 8)
 102          .setDim(r);
 103        document.body.appendChild(r);
 104  
 105        this._focusReticle = r;
 106      },
 107  
 108      _clearReticle : function() {
 109        this._focusReticle && JX.DOM.remove(this._focusReticle);
 110        this._focusReticle = null;
 111      },
 112      _onkeypress : function(e) {
 113        if (!(this._getKey(e) in JX.KeyboardShortcutManager._downkeys)) {
 114          this._onkeyhit(e);
 115        }
 116      },
 117      _onkeyhit : function(e) {
 118        var raw = e.getRawEvent();
 119  
 120        if (raw.altKey || raw.ctrlKey || raw.metaKey) {
 121          // Never activate keyboard shortcuts if modifier keys are also
 122          // depressed.
 123          return;
 124        }
 125  
 126        var target = e.getTarget();
 127        var ignore = ['input', 'select', 'textarea', 'object', 'embed'];
 128        if (JX.DOM.isType(target, ignore)) {
 129          // Never activate keyboard shortcuts if the user has some other control
 130          // focused.
 131          return;
 132        }
 133  
 134        var key = this._getKey(e);
 135  
 136        var shortcuts = this._shortcuts;
 137        for (var ii = 0; ii < shortcuts.length; ii++) {
 138          var keys = shortcuts[ii].getKeys();
 139          for (var jj = 0; jj < keys.length; jj++) {
 140            if (keys[jj] == key) {
 141              shortcuts[ii].getHandler()(this);
 142              e.kill(); // Consume the event
 143              return;
 144            }
 145          }
 146        }
 147      },
 148      _onkeydown : function(e) {
 149        this._handleTooltipKeyEvent(e, true);
 150  
 151        if (this._getKey(e) in JX.KeyboardShortcutManager._downkeys) {
 152          this._onkeyhit(e);
 153        }
 154      },
 155      _onkeyup : function(e) {
 156        this._handleTooltipKeyEvent(e, false);
 157      },
 158      _getKey : function(e) {
 159        return e.getSpecialKey() || String.fromCharCode(e.getRawEvent().charCode);
 160      },
 161      _handleTooltipKeyEvent : function(e, is_keydown) {
 162        if (e.getRawEvent().keyCode != 18) {
 163          // If this isn't the alt/option key, don't do anything.
 164          return;
 165        }
 166        // Fire all the shortcut handlers.
 167        var shortcuts = this._shortcuts;
 168        for (var ii = 0; ii < shortcuts.length; ii++) {
 169          var handler = shortcuts[ii].getTooltipHandler();
 170          handler && handler(this, is_keydown);
 171        }
 172      }
 173  
 174    }
 175  });


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1