234 lines
8.3 KiB
JavaScript
234 lines
8.3 KiB
JavaScript
// Copyright 2008 The Closure Library Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS-IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
/**
|
|
* @fileoverview Renderer for {@link goog.ui.SubMenu}s.
|
|
*
|
|
*/
|
|
|
|
goog.provide('goog.ui.SubMenuRenderer');
|
|
|
|
goog.require('goog.a11y.aria');
|
|
goog.require('goog.a11y.aria.State');
|
|
goog.require('goog.asserts');
|
|
goog.require('goog.dom');
|
|
goog.require('goog.dom.classes');
|
|
goog.require('goog.style');
|
|
goog.require('goog.ui.Menu');
|
|
goog.require('goog.ui.MenuItemRenderer');
|
|
|
|
|
|
|
|
/**
|
|
* Default renderer for {@link goog.ui.SubMenu}s. Each item has the following
|
|
* structure:
|
|
* <div class="goog-submenu">
|
|
* ...(menuitem content)...
|
|
* <div class="goog-menu">
|
|
* ... (submenu content) ...
|
|
* </div>
|
|
* </div>
|
|
* @constructor
|
|
* @extends {goog.ui.MenuItemRenderer}
|
|
*/
|
|
goog.ui.SubMenuRenderer = function() {
|
|
goog.ui.MenuItemRenderer.call(this);
|
|
};
|
|
goog.inherits(goog.ui.SubMenuRenderer, goog.ui.MenuItemRenderer);
|
|
goog.addSingletonGetter(goog.ui.SubMenuRenderer);
|
|
|
|
|
|
/**
|
|
* Default CSS class to be applied to the root element of components rendered
|
|
* by this renderer.
|
|
* @type {string}
|
|
*/
|
|
goog.ui.SubMenuRenderer.CSS_CLASS = goog.getCssName('goog-submenu');
|
|
|
|
|
|
/**
|
|
* The CSS class for submenus that displays the submenu arrow.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_ =
|
|
goog.getCssName('goog-submenu-arrow');
|
|
|
|
|
|
/**
|
|
* Overrides {@link goog.ui.MenuItemRenderer#createDom} by adding
|
|
* the additional class 'goog-submenu' to the created element,
|
|
* and passes the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}
|
|
* to add an child element that can be styled to show an arrow.
|
|
* @param {goog.ui.Control} control goog.ui.SubMenu to render.
|
|
* @return {Element} Root element for the item.
|
|
* @override
|
|
*/
|
|
goog.ui.SubMenuRenderer.prototype.createDom = function(control) {
|
|
var subMenu = /** @type {goog.ui.SubMenu} */ (control);
|
|
var element = goog.ui.SubMenuRenderer.superClass_.createDom.call(this,
|
|
subMenu);
|
|
goog.dom.classes.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);
|
|
this.addArrow_(subMenu, element);
|
|
return element;
|
|
};
|
|
|
|
|
|
/**
|
|
* Overrides {@link goog.ui.MenuItemRenderer#decorate} by adding
|
|
* the additional class 'goog-submenu' to the decorated element,
|
|
* and passing the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}
|
|
* to add a child element that can be styled to show an arrow.
|
|
* Also searches the element for a child with the class goog-menu. If a
|
|
* matching child element is found, creates a goog.ui.Menu, uses it to
|
|
* decorate the child element, and passes that menu to subMenu.setMenu.
|
|
* @param {goog.ui.Control} control goog.ui.SubMenu to render.
|
|
* @param {Element} element Element to decorate.
|
|
* @return {Element} Root element for the item.
|
|
* @override
|
|
*/
|
|
goog.ui.SubMenuRenderer.prototype.decorate = function(control, element) {
|
|
var subMenu = /** @type {goog.ui.SubMenu} */ (control);
|
|
element = goog.ui.SubMenuRenderer.superClass_.decorate.call(
|
|
this, subMenu, element);
|
|
goog.dom.classes.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);
|
|
this.addArrow_(subMenu, element);
|
|
|
|
// Search for a child menu and decorate it.
|
|
var childMenuEls = goog.dom.getElementsByTagNameAndClass(
|
|
'div', goog.getCssName('goog-menu'), element);
|
|
if (childMenuEls.length) {
|
|
var childMenu = new goog.ui.Menu(subMenu.getDomHelper());
|
|
var childMenuEl = childMenuEls[0];
|
|
// Hide the menu element before attaching it to the document body; see
|
|
// bug 1089244.
|
|
goog.style.setElementShown(childMenuEl, false);
|
|
subMenu.getDomHelper().getDocument().body.appendChild(childMenuEl);
|
|
childMenu.decorate(childMenuEl);
|
|
subMenu.setMenu(childMenu, true);
|
|
}
|
|
return element;
|
|
};
|
|
|
|
|
|
/**
|
|
* Takes a menu item's root element, and sets its content to the given text
|
|
* caption or DOM structure. Overrides the superclass immplementation by
|
|
* making sure that the submenu arrow structure is preserved.
|
|
* @param {Element} element The item's root element.
|
|
* @param {goog.ui.ControlContent} content Text caption or DOM structure to be
|
|
* set as the item's content.
|
|
* @override
|
|
*/
|
|
goog.ui.SubMenuRenderer.prototype.setContent = function(element, content) {
|
|
// Save the submenu arrow element, if present.
|
|
var contentElement = this.getContentElement(element);
|
|
var arrowElement = contentElement && contentElement.lastChild;
|
|
goog.ui.SubMenuRenderer.superClass_.setContent.call(this, element, content);
|
|
// If the arrowElement was there, is no longer there, and really was an arrow,
|
|
// reappend it.
|
|
if (arrowElement &&
|
|
contentElement.lastChild != arrowElement &&
|
|
goog.dom.classes.has(arrowElement,
|
|
goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_)) {
|
|
contentElement.appendChild(arrowElement);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Overrides {@link goog.ui.MenuItemRenderer#initializeDom} to tweak
|
|
* the DOM structure for the span.goog-submenu-arrow element
|
|
* depending on the text direction (LTR or RTL). When the SubMenu is RTL
|
|
* the arrow will be given the additional class of goog-submenu-arrow-rtl,
|
|
* and the arrow will be moved up to be the first child in the SubMenu's
|
|
* element. Otherwise the arrow will have the class goog-submenu-arrow-ltr,
|
|
* and be kept as the last child of the SubMenu's element.
|
|
* @param {goog.ui.Control} control goog.ui.SubMenu whose DOM is to be
|
|
* initialized as it enters the document.
|
|
* @override
|
|
*/
|
|
goog.ui.SubMenuRenderer.prototype.initializeDom = function(control) {
|
|
var subMenu = /** @type {goog.ui.SubMenu} */ (control);
|
|
goog.ui.SubMenuRenderer.superClass_.initializeDom.call(this, subMenu);
|
|
var element = subMenu.getContentElement();
|
|
var arrow = subMenu.getDomHelper().getElementsByTagNameAndClass(
|
|
'span', goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_, element)[0];
|
|
goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);
|
|
if (arrow != element.lastChild) {
|
|
element.appendChild(arrow);
|
|
}
|
|
var subMenuElement = subMenu.getElement();
|
|
goog.asserts.assert(subMenuElement,
|
|
'The sub menu DOM element cannot be null.');
|
|
goog.a11y.aria.setState(subMenuElement,
|
|
goog.a11y.aria.State.HASPOPUP,
|
|
'true');
|
|
};
|
|
|
|
|
|
/**
|
|
* Appends a child node with the class goog.getCssName('goog-submenu-arrow') or
|
|
* 'goog-submenu-arrow-rtl' which can be styled to show an arrow.
|
|
* @param {goog.ui.SubMenu} subMenu SubMenu to render.
|
|
* @param {Element} element Element to decorate.
|
|
* @private
|
|
*/
|
|
goog.ui.SubMenuRenderer.prototype.addArrow_ = function(subMenu, element) {
|
|
var arrow = subMenu.getDomHelper().createDom('span');
|
|
arrow.className = goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_;
|
|
goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);
|
|
this.getContentElement(element).appendChild(arrow);
|
|
};
|
|
|
|
|
|
/**
|
|
* The unicode char for a left arrow.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.SubMenuRenderer.LEFT_ARROW_ = '\u25C4';
|
|
|
|
|
|
/**
|
|
* The unicode char for a right arrow.
|
|
* @type {string}
|
|
* @private
|
|
*/
|
|
goog.ui.SubMenuRenderer.RIGHT_ARROW_ = '\u25BA';
|
|
|
|
|
|
/**
|
|
* Set the text content of an arrow.
|
|
* @param {goog.ui.SubMenu} subMenu The sub menu that owns the arrow.
|
|
* @param {Element} arrow The arrow element.
|
|
* @private
|
|
*/
|
|
goog.ui.SubMenuRenderer.setArrowTextContent_ = function(subMenu, arrow) {
|
|
// Fix arrow rtl
|
|
var leftArrow = goog.ui.SubMenuRenderer.LEFT_ARROW_;
|
|
var rightArrow = goog.ui.SubMenuRenderer.RIGHT_ARROW_;
|
|
if (subMenu.isRightToLeft()) {
|
|
goog.dom.classes.add(arrow, goog.getCssName('goog-submenu-arrow-rtl'));
|
|
// Unicode character - Black left-pointing pointer iff aligned to end.
|
|
goog.dom.setTextContent(arrow, subMenu.isAlignedToEnd() ?
|
|
leftArrow : rightArrow);
|
|
} else {
|
|
goog.dom.classes.remove(arrow, goog.getCssName('goog-submenu-arrow-rtl'));
|
|
// Unicode character - Black right-pointing pointer iff aligned to end.
|
|
goog.dom.setTextContent(arrow, subMenu.isAlignedToEnd() ?
|
|
rightArrow : leftArrow);
|
|
}
|
|
};
|