// 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 Default renderer for {@link goog.ui.Button}s. * * @author attila@google.com (Attila Bodis) */ goog.provide('goog.ui.ButtonRenderer'); goog.require('goog.a11y.aria'); goog.require('goog.a11y.aria.Role'); goog.require('goog.a11y.aria.State'); goog.require('goog.asserts'); goog.require('goog.ui.ButtonSide'); goog.require('goog.ui.Component'); goog.require('goog.ui.ControlRenderer'); goog.forwardDeclare('goog.ui.Button'); // circular /** * Default renderer for {@link goog.ui.Button}s. Extends the superclass with * the following button-specific API methods: * * For alternate renderers, see {@link goog.ui.NativeButtonRenderer}, * {@link goog.ui.CustomButtonRenderer}, and {@link goog.ui.FlatButtonRenderer}. * @constructor * @extends {goog.ui.ControlRenderer} */ goog.ui.ButtonRenderer = function() { goog.ui.ControlRenderer.call(this); }; goog.inherits(goog.ui.ButtonRenderer, goog.ui.ControlRenderer); goog.addSingletonGetter(goog.ui.ButtonRenderer); /** * Default CSS class to be applied to the root element of components rendered * by this renderer. * @type {string} */ goog.ui.ButtonRenderer.CSS_CLASS = goog.getCssName('goog-button'); /** * Returns the ARIA role to be applied to buttons. * @return {goog.a11y.aria.Role|undefined} ARIA role. * @override */ goog.ui.ButtonRenderer.prototype.getAriaRole = function() { return goog.a11y.aria.Role.BUTTON; }; /** * Updates the button's ARIA (accessibility) state if the button is being * treated as a checkbox. Also makes sure that attributes which aren't * supported by buttons aren't being added. * @param {Element} element Element whose ARIA state is to be updated. * @param {goog.ui.Component.State} state Component state being enabled or * disabled. * @param {boolean} enable Whether the state is being enabled or disabled. * @protected * @override */ goog.ui.ButtonRenderer.prototype.updateAriaState = function( element, state, enable) { switch (state) { // If button has CHECKED or SELECTED state, assign aria-pressed case goog.ui.Component.State.SELECTED: case goog.ui.Component.State.CHECKED: goog.asserts.assert(element, 'The button DOM element cannot be null.'); goog.a11y.aria.setState(element, goog.a11y.aria.State.PRESSED, enable); break; default: case goog.ui.Component.State.OPENED: case goog.ui.Component.State.DISABLED: goog.ui.ButtonRenderer.base( this, 'updateAriaState', element, state, enable); break; } }; /** @override */ goog.ui.ButtonRenderer.prototype.createDom = function(button) { var element = goog.ui.ButtonRenderer.base(this, 'createDom', button); this.setTooltip(element, button.getTooltip()); var value = button.getValue(); if (value) { this.setValue(element, value); } // If this is a toggle button, set ARIA state if (button.isSupportedState(goog.ui.Component.State.CHECKED)) { this.updateAriaState( element, goog.ui.Component.State.CHECKED, button.isChecked()); } return element; }; /** @override */ goog.ui.ButtonRenderer.prototype.decorate = function(button, element) { // The superclass implementation takes care of common attributes; we only // need to set the value and the tooltip. element = goog.ui.ButtonRenderer.superClass_.decorate.call(this, button, element); button.setValueInternal(this.getValue(element)); button.setTooltipInternal(this.getTooltip(element)); // If this is a toggle button, set ARIA state if (button.isSupportedState(goog.ui.Component.State.CHECKED)) { this.updateAriaState( element, goog.ui.Component.State.CHECKED, button.isChecked()); } return element; }; /** * Takes a button's root element, and returns the value associated with it. * No-op in the base class. * @param {Element} element The button's root element. * @return {string|undefined} The button's value (undefined if none). */ goog.ui.ButtonRenderer.prototype.getValue = goog.nullFunction; /** * Takes a button's root element and a value, and updates the element to reflect * the new value. No-op in the base class. * @param {Element} element The button's root element. * @param {string} value New value. */ goog.ui.ButtonRenderer.prototype.setValue = goog.nullFunction; /** * Takes a button's root element, and returns its tooltip text. * @param {Element} element The button's root element. * @return {string|undefined} The tooltip text. */ goog.ui.ButtonRenderer.prototype.getTooltip = function(element) { return element.title; }; /** * Takes a button's root element and a tooltip string, and updates the element * with the new tooltip. * @param {Element} element The button's root element. * @param {string} tooltip New tooltip text. * @protected */ goog.ui.ButtonRenderer.prototype.setTooltip = function(element, tooltip) { if (element) { // Don't set a title attribute if there isn't a tooltip. Blank title // attributes can be interpreted incorrectly by screen readers. if (tooltip) { element.title = tooltip; } else { element.removeAttribute('title'); } } }; /** * Collapses the border on one or both sides of the button, allowing it to be * combined with the adjacent button(s), forming a single UI componenet with * multiple targets. * @param {goog.ui.Button} button Button to update. * @param {number} sides Bitmap of one or more {@link goog.ui.ButtonSide}s for * which borders should be collapsed. * @protected */ goog.ui.ButtonRenderer.prototype.setCollapsed = function(button, sides) { var isRtl = button.isRightToLeft(); var collapseLeftClassName = goog.getCssName(this.getStructuralCssClass(), 'collapse-left'); var collapseRightClassName = goog.getCssName(this.getStructuralCssClass(), 'collapse-right'); button.enableClassName( isRtl ? collapseRightClassName : collapseLeftClassName, !!(sides & goog.ui.ButtonSide.START)); button.enableClassName( isRtl ? collapseLeftClassName : collapseRightClassName, !!(sides & goog.ui.ButtonSide.END)); }; /** @override */ goog.ui.ButtonRenderer.prototype.getCssClass = function() { return goog.ui.ButtonRenderer.CSS_CLASS; };