[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/webroot/rsrc/js/phuix/ -> PHUIXDropdownMenu.js (source)

   1  /**
   2   * @provides phuix-dropdown-menu
   3   * @requires javelin-install
   4   *           javelin-util
   5   *           javelin-dom
   6   *           javelin-vector
   7   *           javelin-stratcom
   8   * @javelin
   9   */
  10  
  11  
  12  /**
  13   * Basic interaction for a dropdown menu.
  14   *
  15   * The menu is unaware of the content inside it, so it can not close itself
  16   * when an item is selected. Callers must make a call to @{method:close} after
  17   * an item is chosen in order to close the menu.
  18   */
  19  JX.install('PHUIXDropdownMenu', {
  20  
  21    construct : function(node) {
  22      this._node = node;
  23  
  24      JX.DOM.listen(
  25        this._node,
  26        'click',
  27        null,
  28        JX.bind(this, this._onclick));
  29  
  30      JX.Stratcom.listen(
  31        'mousedown',
  32        null,
  33        JX.bind(this, this._onanyclick));
  34  
  35      JX.Stratcom.listen(
  36        'resize',
  37        null,
  38        JX.bind(this, this._adjustposition));
  39  
  40      JX.Stratcom.listen('phuix.dropdown.open', null, JX.bind(this, this.close));
  41  
  42      JX.Stratcom.listen('keydown', null, JX.bind(this, this._onkey));
  43    },
  44  
  45    events: ['open'],
  46  
  47    properties: {
  48      width: null,
  49      align: 'right',
  50      offsetX: 0,
  51      offsetY: 0
  52    },
  53  
  54    members: {
  55      _node: null,
  56      _menu: null,
  57      _open: false,
  58      _content: null,
  59  
  60      setContent: function(content) {
  61        JX.DOM.setContent(this._getMenuNode(), content);
  62        return this;
  63      },
  64  
  65      open: function() {
  66        if (this._open) {
  67          return;
  68        }
  69  
  70        this.invoke('open');
  71        JX.Stratcom.invoke('phuix.dropdown.open');
  72  
  73        this._open = true;
  74        this._show();
  75  
  76        return this;
  77      },
  78  
  79      close: function() {
  80        if (!this._open) {
  81          return;
  82        }
  83        this._open = false;
  84        this._hide();
  85  
  86        return this;
  87      },
  88  
  89      _getMenuNode: function() {
  90        if (!this._menu) {
  91          var attrs = {
  92            className: 'phuix-dropdown-menu',
  93            role: 'button'
  94          };
  95  
  96          var menu = JX.$N('div', attrs);
  97  
  98          this._menu = menu;
  99        }
 100  
 101        return this._menu;
 102      },
 103  
 104      _onclick : function(e) {
 105        if (this._open) {
 106          this.close();
 107        } else {
 108          this.open();
 109        }
 110        e.prevent();
 111      },
 112  
 113      _onanyclick : function(e) {
 114        if (!this._open) {
 115          return;
 116        }
 117  
 118        if (JX.Stratcom.pass(e)) {
 119          return;
 120        }
 121  
 122        var t = e.getTarget();
 123        while (t) {
 124          if (t == this._menu || t == this._node) {
 125            return;
 126          }
 127          t = t.parentNode;
 128        }
 129  
 130        this.close();
 131      },
 132  
 133      _show : function() {
 134        document.body.appendChild(this._menu);
 135  
 136        if (this.getWidth()) {
 137          new JX.Vector(this.getWidth(), null).setDim(this._menu);
 138        }
 139  
 140        this._adjustposition();
 141  
 142        JX.DOM.alterClass(this._node, 'phuix-dropdown-open', true);
 143  
 144        this._node.setAttribute('aria-expanded', 'true');
 145  
 146        // Try to highlight the first link in the menu for assistive technologies.
 147        var links = JX.DOM.scry(this._menu, 'a');
 148        if (links[0]) {
 149          JX.DOM.focus(links[0]);
 150        }
 151      },
 152  
 153      _hide : function() {
 154        JX.DOM.remove(this._menu);
 155  
 156        JX.DOM.alterClass(this._node, 'phuix-dropdown-open', false);
 157  
 158        this._node.setAttribute('aria-expanded', 'false');
 159      },
 160  
 161      _adjustposition : function() {
 162        if (!this._open) {
 163          return;
 164        }
 165  
 166        var m = JX.Vector.getDim(this._menu);
 167  
 168        var v = JX.$V(this._node);
 169        var d = JX.Vector.getDim(this._node);
 170  
 171        switch (this.getAlign()) {
 172          case 'right':
 173            v = v.add(d)
 174                 .add(JX.$V(-m.x, 0));
 175            break;
 176          default:
 177            v = v.add(0, d.y);
 178            break;
 179        }
 180  
 181        v = v.add(this.getOffsetX(), this.getOffsetY());
 182  
 183        v.setPos(this._menu);
 184      },
 185  
 186      _onkey: function(e) {
 187        // When the user presses escape with a menu open, close the menu and
 188        // refocus the button which activates the menu. In particular, this makes
 189        // popups more usable with assistive technologies.
 190  
 191        if (!this._open) {
 192          return;
 193        }
 194  
 195        if (e.getSpecialKey() != 'esc') {
 196          return;
 197        }
 198  
 199        this.close();
 200        JX.DOM.focus(this._node);
 201  
 202        e.prevent();
 203      }
 204  
 205    }
 206  });


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