UNPKG

accessibility-developer-tools

Version:

This is a library of accessibility-related testing and utility code.

336 lines (289 loc) 9.4 kB
// Copyright 2010 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 Behavior for combining two controls. * * @see ../demos/split.html */ goog.provide('goog.ui.SplitBehavior'); goog.provide('goog.ui.SplitBehavior.DefaultHandlers'); goog.require('goog.Disposable'); goog.require('goog.asserts'); goog.require('goog.dispose'); goog.require('goog.dom.NodeType'); goog.require('goog.dom.classlist'); goog.require('goog.events.EventHandler'); goog.require('goog.ui.ButtonSide'); goog.require('goog.ui.Component'); goog.require('goog.ui.decorate'); goog.require('goog.ui.registry'); /** * Creates a behavior for combining two controls. The behavior is triggered * by a given event type which applies the behavior handler. * Can be used to also render or decorate the controls. * For a usage example see {@link goog.ui.ColorSplitBehavior} * * @param {goog.ui.Control} first A ui control. * @param {goog.ui.Control} second A ui control. * @param {function(!goog.ui.Control, !Event)=} opt_behaviorHandler A handler * to apply for the behavior. * @param {string=} opt_eventType The event type triggering the * handler. * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper, used for * document interaction. * @constructor * @extends {goog.Disposable} */ goog.ui.SplitBehavior = function( first, second, opt_behaviorHandler, opt_eventType, opt_domHelper) { goog.Disposable.call(this); /** * @type {goog.ui.Control} * @private */ this.first_ = first; /** * @type {goog.ui.Control} * @private */ this.second_ = second; /** * Handler for this behavior. * @type {function(!goog.ui.Control, !Event)} * @private */ this.behaviorHandler_ = opt_behaviorHandler || goog.ui.SplitBehavior.DefaultHandlers.CAPTION; /** * Event type triggering the behavior. * @type {string} * @private */ this.eventType_ = opt_eventType || goog.ui.Component.EventType.ACTION; /** * True iff the behavior is active. * @type {boolean} * @private */ this.isActive_ = false; /** * Event handler. * @type {goog.events.EventHandler} * @private */ this.eventHandler_ = new goog.events.EventHandler(); /** * Whether to dispose the first control when dispose is called. * @type {boolean} * @private */ this.disposeFirst_ = true; /** * Whether to dispose the second control when dispose is called. * @type {boolean} * @private */ this.disposeSecond_ = true; }; goog.inherits(goog.ui.SplitBehavior, goog.Disposable); goog.tagUnsealableClass(goog.ui.SplitBehavior); /** * Css class for elements rendered by this behavior. * @type {string} */ goog.ui.SplitBehavior.CSS_CLASS = goog.getCssName('goog-split-behavior'); /** * An emum of split behavior handlers. * @enum {function(!goog.ui.Control, !Event)} */ goog.ui.SplitBehavior.DefaultHandlers = { NONE: goog.nullFunction, CAPTION: function(targetControl, e) { var item = /** @type {goog.ui.MenuItem} */ (e.target); var value = (/** @type {string} */ ((item && item.getValue()) || '')); var button = /** @type {goog.ui.Button} */ (targetControl); button.setCaption && button.setCaption(value); button.setValue && button.setValue(value); }, VALUE: function(targetControl, e) { var item = /** @type {goog.ui.MenuItem} */ (e.target); var value = (/** @type {string} */ (item && item.getValue()) || ''); var button = /** @type {goog.ui.Button} */ (targetControl); button.setValue && button.setValue(value); } }; /** * The element containing the controls. * @type {Element} * @private */ goog.ui.SplitBehavior.prototype.element_ = null; /** * @return {Element} The element containing the controls. */ goog.ui.SplitBehavior.prototype.getElement = function() { return this.element_; }; /** * @return {function(!goog.ui.Control,!Event)} The behavior handler. */ goog.ui.SplitBehavior.prototype.getBehaviorHandler = function() { return this.behaviorHandler_; }; /** * @return {string} The behavior event type. */ goog.ui.SplitBehavior.prototype.getEventType = function() { return this.eventType_; }; /** * Sets the disposeControls flags. * @param {boolean} disposeFirst Whether to dispose the first control * when dispose is called. * @param {boolean} disposeSecond Whether to dispose the second control * when dispose is called. */ goog.ui.SplitBehavior.prototype.setDisposeControls = function( disposeFirst, disposeSecond) { this.disposeFirst_ = !!disposeFirst; this.disposeSecond_ = !!disposeSecond; }; /** * Sets the behavior handler. * @param {function(goog.ui.Control,Event)} behaviorHandler The behavior * handler. */ goog.ui.SplitBehavior.prototype.setHandler = function(behaviorHandler) { this.behaviorHandler_ = behaviorHandler; if (this.isActive_) { this.setActive(false); this.setActive(true); } }; /** * Sets the behavior event type. * @param {string} eventType The behavior event type. */ goog.ui.SplitBehavior.prototype.setEventType = function(eventType) { this.eventType_ = eventType; if (this.isActive_) { this.setActive(false); this.setActive(true); } }; /** * Decorates an element and returns the behavior. * @param {Element} element An element to decorate. * @param {boolean=} opt_activate Whether to activate the behavior * (default=true). * @return {!goog.ui.SplitBehavior} A split behavior. */ goog.ui.SplitBehavior.prototype.decorate = function(element, opt_activate) { if (this.first_ || this.second_) { throw Error('Cannot decorate controls are already set'); } this.decorateChildren_(element); var activate = goog.isDefAndNotNull(opt_activate) ? !!opt_activate : true; this.element_ = element; this.setActive(activate); return this; }; /** * Renders an element and returns the behavior. * @param {Element} element An element to decorate. * @param {boolean=} opt_activate Whether to activate the behavior * (default=true). * @return {!goog.ui.SplitBehavior} A split behavior. */ goog.ui.SplitBehavior.prototype.render = function(element, opt_activate) { goog.asserts.assert(element); goog.dom.classlist.add(element, goog.ui.SplitBehavior.CSS_CLASS); this.first_.render(element); this.second_.render(element); this.collapseSides_(this.first_, this.second_); var activate = goog.isDefAndNotNull(opt_activate) ? !!opt_activate : true; this.element_ = element; this.setActive(activate); return this; }; /** * Activate or deactivate the behavior. * @param {boolean} activate Whether to activate or deactivate the behavior. */ goog.ui.SplitBehavior.prototype.setActive = function(activate) { if (this.isActive_ == activate) { return; } this.isActive_ = activate; if (activate) { this.eventHandler_.listen( this.second_, this.eventType_, goog.bind(this.behaviorHandler_, this, this.first_)); // TODO(user): should we call the handler here to sync between // first_ and second_. } else { this.eventHandler_.removeAll(); } }; /** @override */ goog.ui.SplitBehavior.prototype.disposeInternal = function() { this.setActive(false); goog.dispose(this.eventHandler_); if (this.disposeFirst_) { goog.dispose(this.first_); } if (this.disposeSecond_) { goog.dispose(this.second_); } goog.ui.SplitBehavior.superClass_.disposeInternal.call(this); }; /** * Decorates two child nodes of the given element. * @param {Element} element An element to render two of it's child nodes. * @private */ goog.ui.SplitBehavior.prototype.decorateChildren_ = function(element) { var childNodes = element.childNodes; var len = childNodes.length; var finished = false; for (var i = 0; i < len && !finished; i++) { var child = childNodes[i]; if (child.nodeType == goog.dom.NodeType.ELEMENT) { var el = /** @type {!Element} */ (child); if (!this.first_) { this.first_ = /** @type {goog.ui.Control} */ (goog.ui.decorate(el)); } else if (!this.second_) { this.second_ = /** @type {goog.ui.Control} */ (goog.ui.decorate(el)); finished = true; } } } }; /** * Collapse the the controls together. * @param {goog.ui.Control} first The first element. * @param {goog.ui.Control} second The second element. * @private */ goog.ui.SplitBehavior.prototype.collapseSides_ = function(first, second) { if (goog.isFunction(first.setCollapsed) && goog.isFunction(second.setCollapsed)) { first.setCollapsed(goog.ui.ButtonSide.END); second.setCollapsed(goog.ui.ButtonSide.START); } }; // Register a decorator factory function for goog.ui.Buttons. goog.ui.registry.setDecoratorByClassName( goog.ui.SplitBehavior.CSS_CLASS, function() { return new goog.ui.SplitBehavior(null, null); });