| Index: third_party/google_input_tools/third_party/closure_library/closure/goog/ui/control.js
|
| diff --git a/third_party/google_input_tools/third_party/closure_library/closure/goog/ui/control.js b/third_party/google_input_tools/third_party/closure_library/closure/goog/ui/control.js
|
| index a258c26dda56e4e4b44340c03cefd456548823b6..c9382f3d871415bbbdc0355bbee57b3d47428873 100644
|
| --- a/third_party/google_input_tools/third_party/closure_library/closure/goog/ui/control.js
|
| +++ b/third_party/google_input_tools/third_party/closure_library/closure/goog/ui/control.js
|
| @@ -25,9 +25,12 @@
|
|
|
| goog.provide('goog.ui.Control');
|
|
|
| +goog.require('goog.Disposable');
|
| goog.require('goog.array');
|
| goog.require('goog.dom');
|
| +goog.require('goog.events.BrowserEvent');
|
| goog.require('goog.events.Event');
|
| +goog.require('goog.events.EventHandler');
|
| goog.require('goog.events.EventType');
|
| goog.require('goog.events.KeyCodes');
|
| goog.require('goog.events.KeyHandler');
|
| @@ -77,6 +80,12 @@ goog.ui.Control = function(opt_content, opt_renderer, opt_domHelper) {
|
| this.renderer_ = opt_renderer ||
|
| goog.ui.registry.getDefaultRenderer(this.constructor);
|
| this.setContentInternal(goog.isDef(opt_content) ? opt_content : null);
|
| +
|
| + /** @private {?string} The control's aria-label. */
|
| + this.ariaLabel_ = null;
|
| +
|
| + /** @private {goog.ui.Control.IeMouseEventSequenceSimulator_} */
|
| + this.ieMouseEventSequenceSimulator_;
|
| };
|
| goog.inherits(goog.ui.Control, goog.ui.Component);
|
| goog.tagUnsealableClass(goog.ui.Control);
|
| @@ -212,7 +221,7 @@ goog.ui.Control.prototype.keyHandler_;
|
|
|
| /**
|
| * Additional class name(s) to apply to the control's root element, if any.
|
| - * @type {Array.<string>?}
|
| + * @type {Array<string>?}
|
| * @private
|
| */
|
| goog.ui.Control.prototype.extraClassNames_ = null;
|
| @@ -339,7 +348,7 @@ goog.ui.Control.prototype.setRenderer = function(renderer) {
|
| /**
|
| * Returns any additional class name(s) to be applied to the component's
|
| * root element, or null if no extra class names are needed.
|
| - * @return {Array.<string>?} Additional class names to be applied to
|
| + * @return {Array<string>?} Additional class names to be applied to
|
| * the component's root element (null if none).
|
| */
|
| goog.ui.Control.prototype.getExtraClassNames = function() {
|
| @@ -458,6 +467,30 @@ goog.ui.Control.prototype.setPreferredAriaRole = function(role) {
|
|
|
|
|
| /**
|
| + * Gets the control's aria label.
|
| + * @return {?string} This control's aria label.
|
| + */
|
| +goog.ui.Control.prototype.getAriaLabel = function() {
|
| + return this.ariaLabel_;
|
| +};
|
| +
|
| +
|
| +/**
|
| + * Sets the control's aria label. This can be used to assign aria label to the
|
| + * element after it is rendered.
|
| + * @param {string} label The string to set as the aria label for this control.
|
| + * No escaping is done on this value.
|
| + */
|
| +goog.ui.Control.prototype.setAriaLabel = function(label) {
|
| + this.ariaLabel_ = label;
|
| + var element = this.getElement();
|
| + if (element) {
|
| + this.renderer_.setAriaLabel(element, label);
|
| + }
|
| +};
|
| +
|
| +
|
| +/**
|
| * Returns the DOM element into which child components are to be rendered,
|
| * or null if the control itself hasn't been rendered yet. Overrides
|
| * {@link goog.ui.Component#getContentElement} by delegating to the renderer.
|
| @@ -518,6 +551,9 @@ goog.ui.Control.prototype.decorateInternal = function(element) {
|
| goog.ui.Control.prototype.enterDocument = function() {
|
| goog.ui.Control.superClass_.enterDocument.call(this);
|
|
|
| + // Call the renderer's setAriaStates method to set element's aria attributes.
|
| + this.renderer_.setAriaStates(this, this.getElementStrict());
|
| +
|
| // Call the renderer's initializeDom method to configure properties of the
|
| // control's DOM that can only be done once it's in the document.
|
| this.renderer_.initializeDom(this);
|
| @@ -574,6 +610,11 @@ goog.ui.Control.prototype.enableMouseEventHandling_ = function(enable) {
|
| if (goog.userAgent.IE) {
|
| handler.listen(element, goog.events.EventType.DBLCLICK,
|
| this.handleDblClick);
|
| + if (!this.ieMouseEventSequenceSimulator_) {
|
| + this.ieMouseEventSequenceSimulator_ =
|
| + new goog.ui.Control.IeMouseEventSequenceSimulator_(this);
|
| + this.registerDisposable(this.ieMouseEventSequenceSimulator_);
|
| + }
|
| }
|
| } else {
|
| handler.
|
| @@ -590,6 +631,8 @@ goog.ui.Control.prototype.enableMouseEventHandling_ = function(enable) {
|
| if (goog.userAgent.IE) {
|
| handler.unlisten(element, goog.events.EventType.DBLCLICK,
|
| this.handleDblClick);
|
| + goog.dispose(this.ieMouseEventSequenceSimulator_);
|
| + this.ieMouseEventSequenceSimulator_ = null;
|
| }
|
| }
|
| };
|
| @@ -623,6 +666,7 @@ goog.ui.Control.prototype.disposeInternal = function() {
|
| delete this.renderer_;
|
| this.content_ = null;
|
| this.extraClassNames_ = null;
|
| + this.ieMouseEventSequenceSimulator_ = null;
|
| };
|
|
|
|
|
| @@ -824,7 +868,7 @@ goog.ui.Control.prototype.setEnabled = function(enable) {
|
| if (this.isVisible()) {
|
| this.renderer_.setFocusable(this, enable);
|
| }
|
| - this.setState(goog.ui.Component.State.DISABLED, !enable);
|
| + this.setState(goog.ui.Component.State.DISABLED, !enable, true);
|
| }
|
| };
|
|
|
| @@ -996,8 +1040,13 @@ goog.ui.Control.prototype.hasState = function(state) {
|
| * transition events; use advisedly.
|
| * @param {goog.ui.Component.State} state State to set or clear.
|
| * @param {boolean} enable Whether to set or clear the state (if supported).
|
| + * @param {boolean=} opt_calledFrom Prevents looping with setEnabled.
|
| */
|
| -goog.ui.Control.prototype.setState = function(state, enable) {
|
| +goog.ui.Control.prototype.setState = function(state, enable, opt_calledFrom) {
|
| + if (!opt_calledFrom && state == goog.ui.Component.State.DISABLED) {
|
| + this.setEnabled(!enable);
|
| + return;
|
| + }
|
| if (this.isSupportedState(state) && enable != this.hasState(state)) {
|
| // Delegate actual styling to the renderer, since it is DOM-specific.
|
| this.renderer_.setState(this, state, enable);
|
| @@ -1224,7 +1273,7 @@ goog.ui.Control.prototype.handleMouseDown = function(e) {
|
| if (this.isAutoState(goog.ui.Component.State.ACTIVE)) {
|
| this.setActive(true);
|
| }
|
| - if (this.renderer_.isFocusable(this)) {
|
| + if (this.renderer_ && this.renderer_.isFocusable(this)) {
|
| this.getKeyEventTarget().focus();
|
| }
|
| }
|
| @@ -1386,3 +1435,110 @@ goog.ui.registry.setDecoratorByClassName(goog.ui.ControlRenderer.CSS_CLASS,
|
| function() {
|
| return new goog.ui.Control(null);
|
| });
|
| +
|
| +
|
| +
|
| +/**
|
| + * A singleton that helps goog.ui.Control instances play well with screen
|
| + * readers. It necessitated by shortcomings in IE, and need not be
|
| + * instantiated in any other browser.
|
| + *
|
| + * In most cases, a click on a goog.ui.Control results in a sequence of events:
|
| + * MOUSEDOWN, MOUSEUP and CLICK. UI controls rely on this sequence since most
|
| + * behavior is trigged by MOUSEDOWN and MOUSEUP. But when IE is used with some
|
| + * traditional screen readers (JAWS, NVDA and perhaps others), IE only sends
|
| + * the CLICK event, resulting in the control being unresponsive. This class
|
| + * monitors the sequence of these events, and if it detects a CLICK event not
|
| + * not preceded by a MOUSEUP event, directly calls the control's event handlers
|
| + * for MOUSEDOWN, then MOUSEUP. While the resulting sequence is different from
|
| + * the norm (the CLICK comes first instead of last), testing thus far shows
|
| + * the resulting behavior to be correct.
|
| + *
|
| + * See http://goo.gl/qvQR4C for more details.
|
| + *
|
| + * @param {!goog.ui.Control} control
|
| + * @constructor
|
| + * @extends {goog.Disposable}
|
| + * @private
|
| + */
|
| +goog.ui.Control.IeMouseEventSequenceSimulator_ = function(control) {
|
| + goog.ui.Control.IeMouseEventSequenceSimulator_.base(this, 'constructor');
|
| +
|
| + /** @private {goog.ui.Control}*/
|
| + this.control_ = control;
|
| +
|
| + /** @private {boolean} */
|
| + this.clickExpected_ = false;
|
| +
|
| + /** @private @const */
|
| + this.handler_ = new goog.events.EventHandler(this);
|
| + this.registerDisposable(this.handler_);
|
| +
|
| + var element = this.control_.getElementStrict();
|
| + this.handler_.
|
| + listen(element, goog.events.EventType.MOUSEDOWN, this.handleMouseDown_).
|
| + listen(element, goog.events.EventType.MOUSEUP, this.handleMouseUp_).
|
| + listen(element, goog.events.EventType.CLICK, this.handleClick_);
|
| +};
|
| +goog.inherits(goog.ui.Control.IeMouseEventSequenceSimulator_, goog.Disposable);
|
| +
|
| +
|
| +/** @private */
|
| +goog.ui.Control.IeMouseEventSequenceSimulator_.prototype.handleMouseDown_ =
|
| + function() {
|
| + this.clickExpected_ = false;
|
| +};
|
| +
|
| +
|
| +/** @private */
|
| +goog.ui.Control.IeMouseEventSequenceSimulator_.prototype.handleMouseUp_ =
|
| + function() {
|
| + this.clickExpected_ = true;
|
| +};
|
| +
|
| +
|
| +/**
|
| + * @param {!goog.events.Event} e
|
| + * @private
|
| + */
|
| +goog.ui.Control.IeMouseEventSequenceSimulator_.prototype.handleClick_ =
|
| + function(e) {
|
| + if (this.clickExpected_) {
|
| + // This is the end of a normal click sequence: mouse-down, mouse-up, click.
|
| + // Assume appropriate actions have already been performed.
|
| + this.clickExpected_ = false;
|
| + return;
|
| + }
|
| +
|
| + // For click events not part of a normal sequence, similate the mouse-down and
|
| + // mouse-up events by creating synthetic events for each and directly invoke
|
| + // the corresponding event listeners in order.
|
| +
|
| + var browserEvent = /** @type {goog.events.BrowserEvent} */ (e);
|
| +
|
| + var event = browserEvent.getBrowserEvent();
|
| + var origEventButton = event.button;
|
| + var origEventType = event.type;
|
| +
|
| + event.button = goog.events.BrowserEvent.MouseButton.LEFT;
|
| +
|
| + event.type = goog.events.EventType.MOUSEDOWN;
|
| + this.control_.handleMouseDown(
|
| + new goog.events.BrowserEvent(event, browserEvent.currentTarget));
|
| +
|
| + event.type = goog.events.EventType.MOUSEUP;
|
| + this.control_.handleMouseUp(
|
| + new goog.events.BrowserEvent(event, browserEvent.currentTarget));
|
| +
|
| + // Restore original values for click handlers that have not yet been invoked.
|
| + event.button = origEventButton;
|
| + event.type = origEventType;
|
| +};
|
| +
|
| +
|
| +/** @override */
|
| +goog.ui.Control.IeMouseEventSequenceSimulator_.prototype.disposeInternal =
|
| + function() {
|
| + this.control_ = null;
|
| + goog.ui.Control.IeMouseEventSequenceSimulator_.base(this, 'disposeInternal');
|
| +};
|
|
|