123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- goog.provide('goog.ui.AttachableMenu');
- goog.require('goog.a11y.aria');
- goog.require('goog.a11y.aria.State');
- goog.require('goog.array');
- goog.require('goog.asserts');
- goog.require('goog.dom');
- goog.require('goog.dom.classlist');
- goog.require('goog.events.Event');
- goog.require('goog.events.KeyCodes');
- goog.require('goog.string');
- goog.require('goog.style');
- goog.require('goog.ui.ItemEvent');
- goog.require('goog.ui.MenuBase');
- goog.require('goog.ui.PopupBase');
- goog.require('goog.userAgent');
- goog.ui.AttachableMenu = function(opt_element) {
- goog.ui.MenuBase.call(this, opt_element);
- };
- goog.inherits(goog.ui.AttachableMenu, goog.ui.MenuBase);
- goog.tagUnsealableClass(goog.ui.AttachableMenu);
- goog.ui.AttachableMenu.prototype.selectedElement_ = null;
- goog.ui.AttachableMenu.prototype.itemClassName_ = 'menu-item';
- goog.ui.AttachableMenu.prototype.selectedItemClassName_ = 'menu-item-selected';
- goog.ui.AttachableMenu.prototype.lastKeyDown_ = goog.now();
- goog.ui.AttachableMenu.prototype.disposeInternal = function() {
- goog.ui.AttachableMenu.superClass_.disposeInternal.call(this);
- this.selectedElement_ = null;
- };
- goog.ui.AttachableMenu.prototype.getItemClassName = function() {
- return this.itemClassName_;
- };
- goog.ui.AttachableMenu.prototype.setItemClassName = function(name) {
- this.itemClassName_ = name;
- };
- goog.ui.AttachableMenu.prototype.getSelectedItemClassName = function() {
- return this.selectedItemClassName_;
- };
- goog.ui.AttachableMenu.prototype.setSelectedItemClassName = function(name) {
- this.selectedItemClassName_ = name;
- };
- goog.ui.AttachableMenu.prototype.getSelectedItem = function() {
- return this.selectedElement_;
- };
- goog.ui.AttachableMenu.prototype.setSelectedItem = function(obj) {
- var elt = (obj);
- if (this.selectedElement_) {
- goog.dom.classlist.remove(
- this.selectedElement_, this.selectedItemClassName_);
- }
- this.selectedElement_ = elt;
- var el = (this.getElement());
- goog.asserts.assert(el, 'The attachable menu DOM element cannot be null.');
- if (this.selectedElement_) {
- goog.dom.classlist.add(this.selectedElement_, this.selectedItemClassName_);
- if (elt.id) {
-
-
-
- goog.a11y.aria.setState(
- el, goog.a11y.aria.State.ACTIVEDESCENDANT, elt.id);
- }
- var top = this.selectedElement_.offsetTop;
- var height = this.selectedElement_.offsetHeight;
- var scrollTop = el.scrollTop;
- var scrollHeight = el.offsetHeight;
-
-
- if (top < scrollTop) {
- el.scrollTop = top;
- } else if (top + height > scrollTop + scrollHeight) {
- el.scrollTop = top + height - scrollHeight;
- }
- } else {
-
- goog.a11y.aria.setState(el, goog.a11y.aria.State.ACTIVEDESCENDANT, '');
- }
- };
- goog.ui.AttachableMenu.prototype.showPopupElement = function() {
-
-
- var el = (this.getElement());
- goog.style.setElementShown(el, true);
- el.scrollTop = 0;
- el.style.visibility = 'visible';
- };
- goog.ui.AttachableMenu.prototype.onShow = function() {
- goog.ui.AttachableMenu.superClass_.onShow.call(this);
-
-
-
-
- var el = this.getElement();
- goog.userAgent.IE ? el.firstChild.focus() : el.focus();
- };
- goog.ui.AttachableMenu.prototype.getNextPrevItem = function(prev) {
-
- var elements = this.getElement().getElementsByTagName('*');
- var elementCount = elements.length;
- var index;
-
- if (this.selectedElement_) {
- for (var i = 0; i < elementCount; i++) {
- if (elements[i] == this.selectedElement_) {
- index = prev ? i - 1 : i + 1;
- break;
- }
- }
- }
-
- if (!goog.isDef(index)) {
- index = prev ? elementCount - 1 : 0;
- }
-
-
- for (var i = 0; i < elementCount; i++) {
- var multiplier = prev ? -1 : 1;
- var nextIndex = index + (multiplier * i) % elementCount;
-
- if (nextIndex < 0) {
- nextIndex += elementCount;
- } else if (nextIndex >= elementCount) {
- nextIndex -= elementCount;
- }
- if (this.isMenuItem_(elements[nextIndex])) {
- return elements[nextIndex];
- }
- }
- return null;
- };
- goog.ui.AttachableMenu.prototype.onMouseOver = function(e) {
- var eltItem = this.getAncestorMenuItem_( (e.target));
- if (eltItem == null) {
- return;
- }
-
- if (goog.now() - this.lastKeyDown_ > goog.ui.PopupBase.DEBOUNCE_DELAY_MS) {
- this.setSelectedItem(eltItem);
- }
- };
- goog.ui.AttachableMenu.prototype.onMouseOut = function(e) {
- var eltItem = this.getAncestorMenuItem_( (e.target));
- if (eltItem == null) {
- return;
- }
-
- if (goog.now() - this.lastKeyDown_ > goog.ui.PopupBase.DEBOUNCE_DELAY_MS) {
- this.setSelectedItem(null);
- }
- };
- goog.ui.AttachableMenu.prototype.onMouseDown = goog.events.Event.preventDefault;
- goog.ui.AttachableMenu.prototype.onMouseUp = function(e) {
- var eltItem = this.getAncestorMenuItem_( (e.target));
- if (eltItem == null) {
- return;
- }
- this.setVisible(false);
- this.onItemSelected_(eltItem);
- };
- goog.ui.AttachableMenu.prototype.onKeyDown = function(e) {
- switch (e.keyCode) {
- case goog.events.KeyCodes.DOWN:
- this.setSelectedItem(this.getNextPrevItem(false));
- this.lastKeyDown_ = goog.now();
- break;
- case goog.events.KeyCodes.UP:
- this.setSelectedItem(this.getNextPrevItem(true));
- this.lastKeyDown_ = goog.now();
- break;
- case goog.events.KeyCodes.ENTER:
- if (this.selectedElement_) {
- this.onItemSelected_();
- this.setVisible(false);
- }
- break;
- case goog.events.KeyCodes.ESC:
- this.setVisible(false);
- break;
- default:
- if (e.charCode) {
- var charStr = String.fromCharCode(e.charCode);
- this.selectByName_(charStr, 1, true);
- }
- break;
- }
-
-
- e.preventDefault();
-
-
- e.stopPropagation();
- this.dispatchEvent(e);
- };
- goog.ui.AttachableMenu.prototype.selectByName_ = function(
- prefix, opt_direction, opt_skip) {
- var elements = this.getElement().getElementsByTagName('*');
- var elementCount = elements.length;
- var index;
- if (elementCount == 0) {
- return;
- }
- if (!this.selectedElement_ ||
- (index = goog.array.indexOf(elements, this.selectedElement_)) == -1) {
-
- index = 0;
- }
- var start = index;
- var re = new RegExp('^' + goog.string.regExpEscape(prefix), 'i');
- var skip = opt_skip && this.selectedElement_;
- var dir = opt_direction || 1;
- do {
- if (elements[index] != skip && this.isMenuItem_(elements[index])) {
- var name = goog.dom.getTextContent(elements[index]);
- if (name.match(re)) {
- break;
- }
- }
- index += dir;
- if (index == elementCount) {
- index = 0;
- } else if (index < 0) {
- index = elementCount - 1;
- }
- } while (index != start);
- if (this.selectedElement_ != elements[index]) {
- this.setSelectedItem(elements[index]);
- }
- };
- goog.ui.AttachableMenu.prototype.onItemSelected_ = function(opt_item) {
- this.dispatchEvent(
- new goog.ui.ItemEvent(
- goog.ui.MenuBase.Events.ITEM_ACTION, this,
- opt_item || this.selectedElement_));
- };
- goog.ui.AttachableMenu.prototype.isMenuItem_ = function(elt) {
- return !!elt && goog.dom.classlist.contains(elt, this.itemClassName_);
- };
- goog.ui.AttachableMenu.prototype.getAncestorMenuItem_ = function(elt) {
- if (elt) {
- var ownerDocumentBody = goog.dom.getOwnerDocument(elt).body;
- while (elt != null && elt != ownerDocumentBody) {
- if (this.isMenuItem_(elt)) {
- return elt;
- }
- elt = (elt.parentNode);
- }
- }
- return null;
- };
|