Changeset View
Changeset View
Standalone View
Standalone View
webroot/rsrc/js/phuix/PHUIXDropdownMenu.js
Show All 15 Lines | |||||
* when an item is selected. Callers must make a call to @{method:close} after | * when an item is selected. Callers must make a call to @{method:close} after | ||||
* an item is chosen in order to close the menu. | * an item is chosen in order to close the menu. | ||||
*/ | */ | ||||
JX.install('PHUIXDropdownMenu', { | JX.install('PHUIXDropdownMenu', { | ||||
construct : function(node) { | construct : function(node) { | ||||
this._node = node; | this._node = node; | ||||
if (node) { | |||||
JX.DOM.listen( | JX.DOM.listen( | ||||
this._node, | this._node, | ||||
'click', | 'click', | ||||
null, | null, | ||||
JX.bind(this, this._onclick)); | JX.bind(this, this._onclick)); | ||||
} | |||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
'mousedown', | 'mousedown', | ||||
null, | null, | ||||
JX.bind(this, this._onanyclick)); | JX.bind(this, this._onanyclick)); | ||||
JX.Stratcom.listen( | JX.Stratcom.listen( | ||||
'resize', | 'resize', | ||||
Show All 12 Lines | JX.install('PHUIXDropdownMenu', { | ||||
}, | }, | ||||
events: ['open', 'close'], | events: ['open', 'close'], | ||||
properties: { | properties: { | ||||
width: null, | width: null, | ||||
align: 'right', | align: 'right', | ||||
offsetX: 0, | offsetX: 0, | ||||
offsetY: 0 | offsetY: 0, | ||||
disableAutofocus: false | |||||
}, | }, | ||||
members: { | members: { | ||||
_node: null, | _node: null, | ||||
_menu: null, | _menu: null, | ||||
_open: false, | _open: false, | ||||
_content: null, | _content: null, | ||||
_position: null, | |||||
_visible: false, | |||||
setContent: function(content) { | setContent: function(content) { | ||||
JX.DOM.setContent(this._getMenuNode(), content); | JX.DOM.setContent(this._getMenuNode(), content); | ||||
return this; | return this; | ||||
}, | }, | ||||
open: function() { | open: function() { | ||||
if (this._open) { | if (this._open) { | ||||
Show All 16 Lines | close: function() { | ||||
this._open = false; | this._open = false; | ||||
this._hide(); | this._hide(); | ||||
this.invoke('close'); | this.invoke('close'); | ||||
return this; | return this; | ||||
}, | }, | ||||
setPosition: function(pos) { | |||||
this._position = pos; | |||||
this._setMenuNodePosition(pos); | |||||
return this; | |||||
}, | |||||
_getMenuNode: function() { | _getMenuNode: function() { | ||||
if (!this._menu) { | if (!this._menu) { | ||||
var attrs = { | var attrs = { | ||||
className: 'phuix-dropdown-menu', | className: 'phuix-dropdown-menu', | ||||
role: 'button' | role: 'button' | ||||
}; | }; | ||||
var menu = JX.$N('div', attrs); | var menu = JX.$N('div', attrs); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | _onanyclick : function(e) { | ||||
} | } | ||||
t = t.parentNode; | t = t.parentNode; | ||||
} | } | ||||
this.close(); | this.close(); | ||||
}, | }, | ||||
_show : function() { | _show : function() { | ||||
if (!this._visible) { | |||||
this._visible = true; | |||||
document.body.appendChild(this._menu); | document.body.appendChild(this._menu); | ||||
} | |||||
if (this.getWidth()) { | if (this.getWidth()) { | ||||
new JX.Vector(this.getWidth(), null).setDim(this._menu); | new JX.Vector(this.getWidth(), null).setDim(this._menu); | ||||
} | } | ||||
this._adjustposition(); | this._adjustposition(); | ||||
if (this._node) { | |||||
JX.DOM.alterClass(this._node, 'phuix-dropdown-open', true); | JX.DOM.alterClass(this._node, 'phuix-dropdown-open', true); | ||||
this._node.setAttribute('aria-expanded', 'true'); | this._node.setAttribute('aria-expanded', 'true'); | ||||
} | |||||
// Try to highlight the first link in the menu for assistive technologies. | // Try to highlight the first link in the menu for assistive technologies. | ||||
if (!this.getDisableAutofocus()) { | |||||
var links = JX.DOM.scry(this._menu, 'a'); | var links = JX.DOM.scry(this._menu, 'a'); | ||||
if (links[0]) { | if (links[0]) { | ||||
JX.DOM.focus(links[0]); | JX.DOM.focus(links[0]); | ||||
} | } | ||||
} | |||||
}, | }, | ||||
_hide : function() { | _hide : function() { | ||||
this._visible = false; | |||||
JX.DOM.remove(this._menu); | JX.DOM.remove(this._menu); | ||||
if (this._node) { | |||||
JX.DOM.alterClass(this._node, 'phuix-dropdown-open', false); | JX.DOM.alterClass(this._node, 'phuix-dropdown-open', false); | ||||
this._node.setAttribute('aria-expanded', 'false'); | this._node.setAttribute('aria-expanded', 'false'); | ||||
} | |||||
}, | }, | ||||
_adjustposition : function() { | _adjustposition : function() { | ||||
if (!this._open) { | if (!this._open) { | ||||
return; | return; | ||||
} | } | ||||
if (this._position) { | |||||
this._setMenuNodePosition(this._position); | |||||
return; | |||||
} | |||||
if (!this._node) { | |||||
return; | |||||
} | |||||
var m = JX.Vector.getDim(this._menu); | var m = JX.Vector.getDim(this._menu); | ||||
var v = JX.$V(this._node); | var v = JX.$V(this._node); | ||||
var d = JX.Vector.getDim(this._node); | var d = JX.Vector.getDim(this._node); | ||||
var alignments = ['right', 'left']; | var alignments = ['right', 'left']; | ||||
var disallow = {}; | var disallow = {}; | ||||
var margin = 8; | var margin = 8; | ||||
Show All 27 Lines | _adjustposition : function() { | ||||
v = v.add(d) | v = v.add(d) | ||||
.add(JX.$V(-m.x, 0)); | .add(JX.$V(-m.x, 0)); | ||||
break; | break; | ||||
default: | default: | ||||
v = v.add(0, d.y); | v = v.add(0, d.y); | ||||
break; | break; | ||||
} | } | ||||
v = v.add(this.getOffsetX(), this.getOffsetY()); | this._setMenuNodePosition(v); | ||||
}, | |||||
_setMenuNodePosition: function(v) { | |||||
v = v.add(this.getOffsetX(), this.getOffsetY()); | |||||
v.setPos(this._menu); | v.setPos(this._menu); | ||||
}, | }, | ||||
getMenuNodeDimensions: function() { | |||||
if (!this._visible) { | |||||
document.body.appendChild(this._menu); | |||||
} | |||||
var dim = JX.Vector.getDim(this._menu); | |||||
if (!this._visible) { | |||||
JX.DOM.remove(this._menu); | |||||
} | |||||
return dim; | |||||
}, | |||||
_onkey: function(e) { | _onkey: function(e) { | ||||
// When the user presses escape with a menu open, close the menu and | // When the user presses escape with a menu open, close the menu and | ||||
// refocus the button which activates the menu. In particular, this makes | // refocus the button which activates the menu. In particular, this makes | ||||
// popups more usable with assistive technologies. | // popups more usable with assistive technologies. | ||||
if (!this._open) { | if (!this._open) { | ||||
return; | return; | ||||
} | } | ||||
if (e.getSpecialKey() != 'esc') { | if (e.getSpecialKey() != 'esc') { | ||||
return; | return; | ||||
} | } | ||||
this.close(); | this.close(); | ||||
if (this._node) { | |||||
JX.DOM.focus(this._node); | JX.DOM.focus(this._node); | ||||
} | |||||
e.prevent(); | e.prevent(); | ||||
} | } | ||||
} | } | ||||
}); | }); |