Path: blob/trunk/third_party/closure/goog/ui/submenurenderer.js
4116 views
/**1* @license2* Copyright The Closure Library Authors.3* SPDX-License-Identifier: Apache-2.04*/56/**7* @fileoverview Renderer for {@link goog.ui.SubMenu}s.8*/910goog.provide('goog.ui.SubMenuRenderer');1112goog.require('goog.a11y.aria');13goog.require('goog.a11y.aria.State');14goog.require('goog.asserts');15goog.require('goog.dom');16goog.require('goog.dom.TagName');17goog.require('goog.dom.classlist');18goog.require('goog.style');19goog.require('goog.ui.Menu');20goog.require('goog.ui.MenuItemRenderer');21goog.requireType('goog.ui.Control');22goog.requireType('goog.ui.ControlContent');23goog.requireType('goog.ui.SubMenu');24252627/**28* Default renderer for {@link goog.ui.SubMenu}s. Each item has the following29* structure:30*31* <div class="goog-submenu">32* ...(menuitem content)...33* <div class="goog-menu">34* ... (submenu content) ...35* </div>36* </div>37*38* @constructor39* @extends {goog.ui.MenuItemRenderer}40*/41goog.ui.SubMenuRenderer = function() {42'use strict';43goog.ui.MenuItemRenderer.call(this);44};45goog.inherits(goog.ui.SubMenuRenderer, goog.ui.MenuItemRenderer);46goog.addSingletonGetter(goog.ui.SubMenuRenderer);474849/**50* Default CSS class to be applied to the root element of components rendered51* by this renderer.52* @type {string}53*/54goog.ui.SubMenuRenderer.CSS_CLASS = goog.getCssName('goog-submenu');555657/**58* The CSS class for submenus that displays the submenu arrow.59* @type {string}60* @private61*/62goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_ =63goog.getCssName('goog-submenu-arrow');646566/**67* Overrides {@link goog.ui.MenuItemRenderer#createDom} by adding68* the additional class 'goog-submenu' to the created element,69* and passes the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}70* to add an child element that can be styled to show an arrow.71* @param {goog.ui.Control} control goog.ui.SubMenu to render.72* @return {!Element} Root element for the item.73* @override74*/75goog.ui.SubMenuRenderer.prototype.createDom = function(control) {76'use strict';77var subMenu = /** @type {goog.ui.SubMenu} */ (control);78var element =79goog.ui.SubMenuRenderer.superClass_.createDom.call(this, subMenu);80goog.asserts.assert(element);81goog.dom.classlist.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);82this.addArrow_(subMenu, element);83return element;84};858687/**88* Overrides {@link goog.ui.MenuItemRenderer#decorate} by adding89* the additional class 'goog-submenu' to the decorated element,90* and passing the element to {@link goog.ui.SubMenuItemRenderer#addArrow_}91* to add a child element that can be styled to show an arrow.92* Also searches the element for a child with the class goog-menu. If a93* matching child element is found, creates a goog.ui.Menu, uses it to94* decorate the child element, and passes that menu to subMenu.setMenu.95* @param {goog.ui.Control} control goog.ui.SubMenu to render.96* @param {Element} element Element to decorate.97* @return {!Element} Root element for the item.98* @override99*/100goog.ui.SubMenuRenderer.prototype.decorate = function(control, element) {101'use strict';102var subMenu = /** @type {goog.ui.SubMenu} */ (control);103element =104goog.ui.SubMenuRenderer.superClass_.decorate.call(this, subMenu, element);105goog.asserts.assert(element);106goog.dom.classlist.add(element, goog.ui.SubMenuRenderer.CSS_CLASS);107this.addArrow_(subMenu, element);108109// Search for a child menu and decorate it.110var childMenuEls = goog.dom.getElementsByTagNameAndClass(111goog.dom.TagName.DIV, goog.getCssName('goog-menu'), element);112if (childMenuEls.length) {113var childMenu = new goog.ui.Menu(subMenu.getDomHelper());114var childMenuEl = childMenuEls[0];115// Hide the menu element before attaching it to the document body; see116// bug 1089244.117goog.style.setElementShown(childMenuEl, false);118subMenu.getDomHelper().getDocument().body.appendChild(childMenuEl);119childMenu.decorate(childMenuEl);120subMenu.setMenu(childMenu, true);121}122return element;123};124125126/**127* Takes a menu item's root element, and sets its content to the given text128* caption or DOM structure. Overrides the superclass immplementation by129* making sure that the submenu arrow structure is preserved.130* @param {Element} element The item's root element.131* @param {goog.ui.ControlContent} content Text caption or DOM structure to be132* set as the item's content.133* @override134*/135goog.ui.SubMenuRenderer.prototype.setContent = function(element, content) {136'use strict';137// Save the submenu arrow element, if present.138var contentElement = this.getContentElement(element);139var arrowElement = contentElement && contentElement.lastChild;140goog.ui.SubMenuRenderer.superClass_.setContent.call(this, element, content);141// If the arrowElement was there, is no longer there, and really was an arrow,142// reappend it.143if (arrowElement && contentElement.lastChild != arrowElement &&144goog.dom.classlist.contains(145/** @type {!Element} */ (arrowElement),146goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_)) {147contentElement.appendChild(arrowElement);148}149};150151152/**153* Overrides {@link goog.ui.MenuItemRenderer#initializeDom} to tweak154* the DOM structure for the span.goog-submenu-arrow element155* depending on the text direction (LTR or RTL). When the SubMenu is RTL156* the arrow will be given the additional class of goog-submenu-arrow-rtl,157* and the arrow will be moved up to be the first child in the SubMenu's158* element. Otherwise the arrow will have the class goog-submenu-arrow-ltr,159* and be kept as the last child of the SubMenu's element.160* @param {goog.ui.Control} control goog.ui.SubMenu whose DOM is to be161* initialized as it enters the document.162* @override163*/164goog.ui.SubMenuRenderer.prototype.initializeDom = function(control) {165'use strict';166var subMenu = /** @type {goog.ui.SubMenu} */ (control);167goog.ui.SubMenuRenderer.superClass_.initializeDom.call(this, subMenu);168var element = subMenu.getContentElement();169var arrow = subMenu.getDomHelper().getElementsByTagNameAndClass(170goog.dom.TagName.SPAN, goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_,171element)[0];172goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);173if (arrow != element.lastChild) {174element.appendChild(arrow);175}176var subMenuElement = subMenu.getElement();177goog.asserts.assert(178subMenuElement, 'The sub menu DOM element cannot be null.');179goog.a11y.aria.setState(180subMenuElement, goog.a11y.aria.State.HASPOPUP, 'true');181};182183184/**185* Appends a child node with the class goog.getCssName('goog-submenu-arrow') or186* 'goog-submenu-arrow-rtl' which can be styled to show an arrow.187* @param {goog.ui.SubMenu} subMenu SubMenu to render.188* @param {Element} element Element to decorate.189* @private190*/191goog.ui.SubMenuRenderer.prototype.addArrow_ = function(subMenu, element) {192'use strict';193var arrow = subMenu.getDomHelper().createDom(goog.dom.TagName.SPAN);194arrow.className = goog.ui.SubMenuRenderer.CSS_CLASS_SUBMENU_;195goog.ui.SubMenuRenderer.setArrowTextContent_(subMenu, arrow);196this.getContentElement(element).appendChild(arrow);197};198199200/**201* The unicode char for a left arrow.202* @type {string}203* @private204*/205goog.ui.SubMenuRenderer.LEFT_ARROW_ = '\u25C4';206207208/**209* The unicode char for a right arrow.210* @type {string}211* @private212*/213goog.ui.SubMenuRenderer.RIGHT_ARROW_ = '\u25BA';214215216/**217* Set the text content of an arrow.218* @param {goog.ui.SubMenu} subMenu The sub menu that owns the arrow.219* @param {Element} arrow The arrow element.220* @private221*/222goog.ui.SubMenuRenderer.setArrowTextContent_ = function(subMenu, arrow) {223'use strict';224// Fix arrow rtl225var leftArrow = goog.ui.SubMenuRenderer.LEFT_ARROW_;226var rightArrow = goog.ui.SubMenuRenderer.RIGHT_ARROW_;227228goog.asserts.assert(arrow);229230if (subMenu.isRightToLeft()) {231goog.dom.classlist.add(arrow, goog.getCssName('goog-submenu-arrow-rtl'));232// Unicode character - Black left-pointing pointer iff aligned to end.233goog.dom.setTextContent(234arrow, subMenu.isAlignedToEnd() ? leftArrow : rightArrow);235} else {236goog.dom.classlist.remove(arrow, goog.getCssName('goog-submenu-arrow-rtl'));237// Unicode character - Black right-pointing pointer iff aligned to end.238goog.dom.setTextContent(239arrow, subMenu.isAlignedToEnd() ? rightArrow : leftArrow);240}241};242243244