Version 3.17.2

APIs

  • Begin typing in the search box above to see results.
Show:

File: widget/js/Widget.js

/**
 * Provides the base Widget class, with HTML Parser support
 *
 * @module widget
 * @main widget
 */
/**
 * Provides the base Widget class
 *
 * @module widget
 * @submodule widget-base
 */
var L = Y.Lang,
 Node = Y.Node,
 ClassNameManager = Y.ClassNameManager,
 _getClassName = ClassNameManager.getClassName,
 _getWidgetClassName,
 _toInitialCap = Y.cached(function(str) {
 return str.substring(0, 1).toUpperCase() + str.substring(1);
 }),
 // K-Weight, IE GC optimizations
 CONTENT = "content",
 VISIBLE = "visible",
 HIDDEN = "hidden",
 DISABLED = "disabled",
 FOCUSED = "focused",
 WIDTH = "width",
 HEIGHT = "height",
 BOUNDING_BOX = "boundingBox",
 CONTENT_BOX = "contentBox",
 PARENT_NODE = "parentNode",
 OWNER_DOCUMENT = "ownerDocument",
 AUTO = "auto",
 SRC_NODE = "srcNode",
 BODY = "body",
 TAB_INDEX = "tabIndex",
 ID = "id",
 RENDER = "render",
 RENDERED = "rendered",
 DESTROYED = "destroyed",
 STRINGS = "strings",
 DIV = "<div></div>",
 CHANGE = "Change",
 LOADING = "loading",
 _UISET = "_uiSet",
 EMPTY_STR = "",
 EMPTY_FN = function() {},
 TRUE = true,
 FALSE = false,
 UI,
 ATTRS = {},
 UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX],
 WEBKIT = Y.UA.webkit,
 // Widget nodeid-to-instance map.
 _instances = {};
/**
 * A base class for widgets, providing:
 * <ul>
 * <li>The render lifecycle method, in addition to the init and destroy
 * lifecycle methods provide by Base</li>
 * <li>Abstract methods to support consistent MVC structure across
 * widgets: renderer, renderUI, bindUI, syncUI</li>
 * <li>Support for common widget attributes, such as boundingBox, contentBox, visible,
 * disabled, focused, strings</li>
 * </ul>
 *
 * @param config {Object} Object literal specifying widget configuration properties.
 *
 * @class Widget
 * @constructor
 * @extends Base
 */
function Widget(config) {
 Y.log('constructor called', 'life', 'widget');
 // kweight
 var widget = this,
 parentNode,
 render,
 constructor = widget.constructor;
 widget._strs = {};
 widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase());
 // We need a config for HTML_PARSER to work.
 config = config || {};
 Widget.superclass.constructor.call(widget, config);
 render = widget.get(RENDER);
 if (render) {
 // Render could be a node or boolean
 if (render !== TRUE) {
 parentNode = render;
 }
 widget.render(parentNode);
 }
}
/**
 * Static property provides a string to identify the class.
 * <p>
 * Currently used to apply class identifiers to the bounding box
 * and to classify events fired by the widget.
 * </p>
 *
 * @property NAME
 * @type String
 * @static
 */
Widget.NAME = "widget";
/**
 * Constant used to identify state changes originating from
 * the DOM (as opposed to the JavaScript model).
 *
 * @property UI_SRC
 * @type String
 * @static
 * @final
 */
UI = Widget.UI_SRC = "ui";
/**
 * Static property used to define the default attribute
 * configuration for the Widget.
 *
 * @property ATTRS
 * @type Object
 * @static
 */
Widget.ATTRS = ATTRS;
// Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd
/**
 * @attribute id
 * @writeOnce
 * @default Generated using guid()
 * @type String
 */
ATTRS[ID] = {
 valueFn: "_guid",
 writeOnce: TRUE
};
/**
 * Flag indicating whether or not this Widget
 * has been through the render lifecycle phase.
 *
 * @attribute rendered
 * @readOnly
 * @default false
 * @type boolean
 */
ATTRS[RENDERED] = {
 value:FALSE,
 readOnly: TRUE
};
/**
 * @attribute boundingBox
 * @description The outermost DOM node for the Widget, used for sizing and positioning
 * of a Widget as well as a containing element for any decorator elements used
 * for skinning.
 * @type String | Node
 * @writeOnce
 */
ATTRS[BOUNDING_BOX] = {
 valueFn:"_defaultBB",
 setter: "_setBB",
 writeOnce: TRUE
};
/**
 * @attribute contentBox
 * @description A DOM node that is a direct descendant of a Widget's bounding box that
 * houses its content.
 * @type String | Node
 * @writeOnce
 */
ATTRS[CONTENT_BOX] = {
 valueFn:"_defaultCB",
 setter: "_setCB",
 writeOnce: TRUE
};
/**
 * @attribute tabIndex
 * @description Number (between -32767 to 32767) indicating the widget's
 * position in the default tab flow. The value is used to set the
 * "tabIndex" attribute on the widget's bounding box. Negative values allow
 * the widget to receive DOM focus programmatically (by calling the focus
 * method), while being removed from the default tab flow. A value of
 * null removes the "tabIndex" attribute from the widget's bounding box.
 * @type Number
 * @default null
 */
ATTRS[TAB_INDEX] = {
 value: null,
 validator: "_validTabIndex"
};
/**
 * @attribute focused
 * @description Boolean indicating if the Widget, or one of its descendants,
 * has focus.
 * @readOnly
 * @default false
 * @type boolean
 */
ATTRS[FOCUSED] = {
 value: FALSE,
 readOnly:TRUE
};
/**
 * @attribute disabled
 * @description Boolean indicating if the Widget should be disabled. The disabled implementation
 * is left to the specific classes extending widget.
 * @default false
 * @type boolean
 */
ATTRS[DISABLED] = {
 value: FALSE
};
/**
 * @attribute visible
 * @description Boolean indicating whether or not the Widget is visible.
 * @default TRUE
 * @type boolean
 */
ATTRS[VISIBLE] = {
 value: TRUE
};
/**
 * @attribute height
 * @description String with units, or number, representing the height of the Widget. If a number is provided,
 * the default unit, defined by the Widgets DEF_UNIT, property is used.
 * @default EMPTY_STR
 * @type {String | Number}
 */
ATTRS[HEIGHT] = {
 value: EMPTY_STR
};
/**
 * @attribute width
 * @description String with units, or number, representing the width of the Widget. If a number is provided,
 * the default unit, defined by the Widgets DEF_UNIT, property is used.
 * @default EMPTY_STR
 * @type {String | Number}
 */
ATTRS[WIDTH] = {
 value: EMPTY_STR
};
/**
 * @attribute strings
 * @description Collection of strings used to label elements of the Widget's UI.
 * @default null
 * @type Object
 */
ATTRS[STRINGS] = {
 value: {},
 setter: "_strSetter",
 getter: "_strGetter"
};
/**
 * Whether or not to render the widget automatically after init, and optionally, to which parent node.
 *
 * @attribute render
 * @type boolean | Node
 * @writeOnce
 */
ATTRS[RENDER] = {
 value:FALSE,
 writeOnce:TRUE
};
/**
 * The css prefix which the static Widget.getClassName method should use when constructing class names
 *
 * @property CSS_PREFIX
 * @type String
 * @default Widget.NAME.toLowerCase()
 * @private
 * @static
 */
Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase());
/**
 * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined
 * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and
 * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for
 * the prefix and widget class name).
 * <p>
 * The instance based version of this method can be used to generate standard prefixed classnames,
 * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you
 * need to use a constant class name across different types instances.
 * </p>
 * @method getClassName
 * @param {String*} args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name
 */
Widget.getClassName = function() {
 // arguments needs to be array'fied to concat
 return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true));
};
_getWidgetClassName = Widget.getClassName;
/**
 * Returns the widget instance whose bounding box contains, or is, the given node.
 * <p>
 * In the case of nested widgets, the nearest bounding box ancestor is used to
 * return the widget instance.
 * </p>
 * @method getByNode
 * @static
 * @param node {Node | String} The node for which to return a Widget instance. If a selector
 * string is passed in, which selects more than one node, the first node found is used.
 * @return {Widget} Widget instance, or null if not found.
 */
Widget.getByNode = function(node) {
 var widget,
 widgetMarker = _getWidgetClassName();
 node = Node.one(node);
 if (node) {
 node = node.ancestor("." + widgetMarker, true);
 if (node) {
 widget = _instances[Y.stamp(node, true)];
 }
 }
 return widget || null;
};
Y.extend(Widget, Y.Base, {
 /**
 * Returns a class name prefixed with the the value of the
 * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property.
 * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings.
 * e.g.
 * <code>
 * <pre>
 * // returns "yui-slider-foo-bar", for a slider instance
 * var scn = slider.getClassName('foo','bar');
 *
 * // returns "yui-overlay-foo-bar", for an overlay instance
 * var ocn = overlay.getClassName('foo','bar');
 * </pre>
 * </code>
 *
 * @method getClassName
 * @param {String} [classnames*] One or more classname bits to be joined and prefixed
 */
 getClassName: function () {
 return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true));
 },
 /**
 * Initializer lifecycle implementation for the Widget class. Registers the
 * widget instance, and runs through the Widget's HTML_PARSER definition.
 *
 * @method initializer
 * @protected
 * @param config {Object} Configuration object literal for the widget
 */
 initializer: function(config) {
 Y.log('initializer called', 'life', 'widget');
 var bb = this.get(BOUNDING_BOX);
 if (bb instanceof Node) {
 this._mapInstance(Y.stamp(bb));
 }
 /**
 * Notification event, which widget implementations can fire, when
 * they change the content of the widget. This event has no default
 * behavior and cannot be prevented, so the "on" or "after"
 * moments are effectively equivalent (with on listeners being invoked before
 * after listeners).
 *
 * @event widget:contentUpdate
 * @preventable false
 * @param {EventFacade} e The Event Facade
 */
 },
 /**
 * Utility method used to add an entry to the boundingBox id to instance map.
 *
 * This method can be used to populate the instance with lazily created boundingBox Node references.
 *
 * @method _mapInstance
 * @param {String} The boundingBox id
 * @protected
 */
 _mapInstance : function(id) {
 _instances[id] = this;
 },
 /**
 * Destructor lifecycle implementation for the Widget class. Purges events attached
 * to the bounding box and content box, removes them from the DOM and removes
 * the Widget from the list of registered widgets.
 *
 * @method destructor
 * @protected
 */
 destructor: function() {
 Y.log('destructor called', 'life', 'widget');
 var boundingBox = this.get(BOUNDING_BOX),
 bbGuid;
 if (boundingBox instanceof Node) {
 bbGuid = Y.stamp(boundingBox,true);
 if (bbGuid in _instances) {
 delete _instances[bbGuid];
 }
 this._destroyBox();
 }
 },
 /**
 * <p>
 * Destroy lifecycle method. Fires the destroy
 * event, prior to invoking destructors for the
 * class hierarchy.
 *
 * Overrides Base's implementation, to support arguments to destroy
 * </p>
 * <p>
 * Subscribers to the destroy
 * event can invoke preventDefault on the event object, to prevent destruction
 * from proceeding.
 * </p>
 * @method destroy
 * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are
 * removed and destroyed. Defaults to false due to potentially high run-time cost.
 * @return {Widget} A reference to this object
 * @chainable
 */
 destroy: function(destroyAllNodes) {
 this._destroyAllNodes = destroyAllNodes;
 return Widget.superclass.destroy.apply(this);
 },
 /**
 * Removes and destroys the widgets rendered boundingBox, contentBox,
 * and detaches bound UI events.
 *
 * @method _destroyBox
 * @protected
 */
 _destroyBox : function() {
 var boundingBox = this.get(BOUNDING_BOX),
 contentBox = this.get(CONTENT_BOX),
 deep = this._destroyAllNodes,
 same;
 same = boundingBox && boundingBox.compareTo(contentBox);
 if (this.UI_EVENTS) {
 this._destroyUIEvents();
 }
 this._unbindUI(boundingBox);
 if (contentBox) {
 if (deep) {
 contentBox.empty();
 }
 contentBox.remove(TRUE);
 }
 if (!same) {
 if (deep) {
 boundingBox.empty();
 }
 boundingBox.remove(TRUE);
 }
 },
 /**
 * Establishes the initial DOM for the widget. Invoking this
 * method will lead to the creating of all DOM elements for
 * the widget (or the manipulation of existing DOM elements
 * for the progressive enhancement use case).
 * <p>
 * This method should only be invoked once for an initialized
 * widget.
 * </p>
 * <p>
 * It delegates to the widget specific renderer method to do
 * the actual work.
 * </p>
 *
 * @method render
 * @chainable
 * @final
 * @param parentNode {Object | String} Optional. The Node under which the
 * Widget is to be rendered. This can be a Node instance or a CSS selector string.
 * <p>
 * If the selector string returns more than one Node, the first node will be used
 * as the parentNode. NOTE: This argument is required if both the boundingBox and contentBox
 * are not currently in the document. If it's not provided, the Widget will be rendered
 * to the body of the current document in this case.
 * </p>
 */
 render: function(parentNode) {
 if (this.get(DESTROYED)) { Y.log("Render failed; widget has been destroyed", "error", "widget"); }
 if (!this.get(DESTROYED) && !this.get(RENDERED)) {
 /**
 * Lifecycle event for the render phase, fired prior to rendering the UI
 * for the widget (prior to invoking the widget's renderer method).
 * <p>
 * Subscribers to the "on" moment of this event, will be notified
 * before the widget is rendered.
 * </p>
 * <p>
 * Subscribers to the "after" moment of this event, will be notified
 * after rendering is complete.
 * </p>
 *
 * @event render
 * @preventable _defRenderFn
 * @param {EventFacade} e The Event Facade
 */
 this.publish(RENDER, {
 queuable:FALSE,
 fireOnce:TRUE,
 defaultTargetOnly:TRUE,
 defaultFn: this._defRenderFn
 });
 this.fire(RENDER, {parentNode: (parentNode) ? Node.one(parentNode) : null});
 }
 return this;
 },
 /**
 * Default render handler
 *
 * @method _defRenderFn
 * @protected
 * @param {EventFacade} e The Event object
 * @param {Node} parentNode The parent node to render to, if passed in to the <code>render</code> method
 */
 _defRenderFn : function(e) {
 this._parentNode = e.parentNode;
 this.renderer();
 this._set(RENDERED, TRUE);
 this._removeLoadingClassNames();
 },
 /**
 * Creates DOM (or manipulates DOM for progressive enhancement)
 * This method is invoked by render() and is not chained
 * automatically for the class hierarchy (unlike initializer, destructor)
 * so it should be chained manually for subclasses if required.
 *
 * @method renderer
 * @protected
 */
 renderer: function() {
 // kweight
 var widget = this;
 widget._renderUI();
 widget.renderUI();
 widget._bindUI();
 widget.bindUI();
 widget._syncUI();
 widget.syncUI();
 },
 /**
 * Configures/Sets up listeners to bind Widget State to UI/DOM
 *
 * This method is not called by framework and is not chained
 * automatically for the class hierarchy.
 *
 * @method bindUI
 * @protected
 */
 bindUI: EMPTY_FN,
 /**
 * Adds nodes to the DOM
 *
 * This method is not called by framework and is not chained
 * automatically for the class hierarchy.
 *
 * @method renderUI
 * @protected
 */
 renderUI: EMPTY_FN,
 /**
 * Refreshes the rendered UI, based on Widget State
 *
 * This method is not called by framework and is not chained
 * automatically for the class hierarchy.
 *
 * @method syncUI
 * @protected
 *
 */
 syncUI: EMPTY_FN,
 /**
 * @method hide
 * @description Hides the Widget by setting the "visible" attribute to "false".
 * @chainable
 */
 hide: function() {
 return this.set(VISIBLE, FALSE);
 },
 /**
 * @method show
 * @description Shows the Widget by setting the "visible" attribute to "true".
 * @chainable
 */
 show: function() {
 return this.set(VISIBLE, TRUE);
 },
 /**
 * @method focus
 * @description Causes the Widget to receive the focus by setting the "focused"
 * attribute to "true".
 * @chainable
 */
 focus: function () {
 return this._set(FOCUSED, TRUE);
 },
 /**
 * @method blur
 * @description Causes the Widget to lose focus by setting the "focused" attribute
 * to "false"
 * @chainable
 */
 blur: function () {
 return this._set(FOCUSED, FALSE);
 },
 /**
 * @method enable
 * @description Set the Widget's "disabled" attribute to "false".
 * @chainable
 */
 enable: function() {
 return this.set(DISABLED, FALSE);
 },
 /**
 * @method disable
 * @description Set the Widget's "disabled" attribute to "true".
 * @chainable
 */
 disable: function() {
 return this.set(DISABLED, TRUE);
 },
 /**
 * @method _uiSizeCB
 * @protected
 * @param {boolean} expand
 */
 _uiSizeCB : function(expand) {
 this.get(CONTENT_BOX).toggleClass(_getWidgetClassName(CONTENT, "expanded"), expand);
 },
 /**
 * Helper method to collect the boundingBox and contentBox and append to the provided parentNode, if not
 * already a child. The owner document of the boundingBox, or the owner document of the contentBox will be used
 * as the document into which the Widget is rendered if a parentNode is node is not provided. If both the boundingBox and
 * the contentBox are not currently in the document, and no parentNode is provided, the widget will be rendered
 * to the current document's body.
 *
 * @method _renderBox
 * @private
 * @param {Node} parentNode The parentNode to render the widget to. If not provided, and both the boundingBox and
 * the contentBox are not currently in the document, the widget will be rendered to the current document's body.
 */
 _renderBox: function(parentNode) {
 // TODO: Performance Optimization [ More effective algo to reduce Node refs, compares, replaces? ]
 var widget = this, // kweight
 contentBox = widget.get(CONTENT_BOX),
 boundingBox = widget.get(BOUNDING_BOX),
 srcNode = widget.get(SRC_NODE),
 defParentNode = widget.DEF_PARENT_NODE,
 doc = (srcNode && srcNode.get(OWNER_DOCUMENT)) || boundingBox.get(OWNER_DOCUMENT) || contentBox.get(OWNER_DOCUMENT);
 // If srcNode (assume it's always in doc), have contentBox take its place (widget render responsible for re-use of srcNode contents)
 if (srcNode && !srcNode.compareTo(contentBox) && !contentBox.inDoc(doc)) {
 srcNode.replace(contentBox);
 }
 if (!boundingBox.compareTo(contentBox.get(PARENT_NODE)) && !boundingBox.compareTo(contentBox)) {
 // If contentBox box is already in the document, have boundingBox box take it's place
 if (contentBox.inDoc(doc)) {
 contentBox.replace(boundingBox);
 }
 boundingBox.appendChild(contentBox);
 }
 parentNode = parentNode || (defParentNode && Node.one(defParentNode));
 if (parentNode) {
 parentNode.appendChild(boundingBox);
 } else if (!boundingBox.inDoc(doc)) {
 Node.one(BODY).insert(boundingBox, 0);
 }
 },
 /**
 * Setter for the boundingBox attribute
 *
 * @method _setBB
 * @private
 * @param {Node|String} node
 * @return Node
 */
 _setBB: function(node) {
 return this._setBox(this.get(ID), node, this.BOUNDING_TEMPLATE, true);
 },
 /**
 * Setter for the contentBox attribute
 *
 * @method _setCB
 * @private
 * @param {Node|String} node
 * @return Node
 */
 _setCB: function(node) {
 return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE, false);
 },
 /**
 * Returns the default value for the boundingBox attribute.
 *
 * For the Widget class, this will most commonly be null (resulting in a new
 * boundingBox node instance being created), unless a srcNode was provided
 * and CONTENT_TEMPLATE is null, in which case it will be srcNode.
 * This behavior was introduced in @VERSION@ to accomodate single-box widgets
 * whose BB & CB both point to srcNode (e.g. Y.Button).
 *
 * @method _defaultBB
 * @protected
 */
 _defaultBB : function() {
 var node = this.get(SRC_NODE),
 nullCT = (this.CONTENT_TEMPLATE === null);
 return ((node && nullCT) ? node : null);
 },
 /**
 * Returns the default value for the contentBox attribute.
 *
 * For the Widget class, this will be the srcNode if provided, otherwise null (resulting in
 * a new contentBox node instance being created)
 *
 * @method _defaultCB
 * @protected
 */
 _defaultCB : function(node) {
 return this.get(SRC_NODE) || null;
 },
 /**
 * Helper method to set the bounding/content box, or create it from
 * the provided template if not found.
 *
 * @method _setBox
 * @private
 *
 * @param {String} id The node's id attribute
 * @param {Node|String} node The node reference
 * @param {String} template HTML string template for the node
 * @param {boolean} isBounding true if this is the boundingBox, false if it's the contentBox
 * @return {Node} The node
 */
 _setBox : function(id, node, template, isBounding) {
 node = Node.one(node);
 if (!node) {
 node = Node.create(template);
 if (isBounding) {
 this._bbFromTemplate = true;
 } else {
 this._cbFromTemplate = true;
 }
 }
 if (!node.get(ID)) {
 node.set(ID, id || Y.guid());
 }
 return node;
 },
 /**
 * Initializes the UI state for the Widget's bounding/content boxes.
 *
 * @method _renderUI
 * @protected
 */
 _renderUI: function() {
 this._renderBoxClassNames();
 this._renderBox(this._parentNode);
 },
 /**
 * Applies standard class names to the boundingBox and contentBox
 *
 * @method _renderBoxClassNames
 * @protected
 */
 _renderBoxClassNames : function() {
 var classes = this._getClasses(),
 cl,
 boundingBox = this.get(BOUNDING_BOX),
 i;
 boundingBox.addClass(_getWidgetClassName());
 // Start from Widget Sub Class
 for (i = classes.length-3; i >= 0; i--) {
 cl = classes[i];
 boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase()));
 }
 // Use instance based name for content box
 this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT));
 },
 /**
 * Removes class names representative of the widget's loading state from
 * the boundingBox.
 *
 * @method _removeLoadingClassNames
 * @protected
 */
 _removeLoadingClassNames: function () {
 var boundingBox = this.get(BOUNDING_BOX),
 contentBox = this.get(CONTENT_BOX),
 instClass = this.getClassName(LOADING),
 widgetClass = _getWidgetClassName(LOADING);
 boundingBox.removeClass(widgetClass)
 .removeClass(instClass);
 contentBox.removeClass(widgetClass)
 .removeClass(instClass);
 },
 /**
 * Sets up DOM and CustomEvent listeners for the widget.
 *
 * @method _bindUI
 * @protected
 */
 _bindUI: function() {
 this._bindAttrUI(this._UI_ATTRS.BIND);
 this._bindDOM();
 },
 /**
 * @method _unbindUI
 * @protected
 */
 _unbindUI : function(boundingBox) {
 this._unbindDOM(boundingBox);
 },
 /**
 * Sets up DOM listeners, on elements rendered by the widget.
 *
 * @method _bindDOM
 * @protected
 */
 _bindDOM : function() {
 var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT),
 focusHandle = Widget._hDocFocus;
 // Shared listener across all Widgets.
 if (!focusHandle) {
 focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this);
 focusHandle.listeners = {
 count: 0
 };
 }
 focusHandle.listeners[Y.stamp(this, true)] = true;
 focusHandle.listeners.count++;
 //	Fix for Webkit:
 //	Document doesn't receive focus in Webkit when the user mouses
 //	down on it, so the "focused" attribute won't get set to the
 //	correct value. Keeping this instance based for now, potential better performance.
 // Otherwise we'll end up looking up widgets from the DOM on every mousedown.
 if (WEBKIT){
 this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this);
 }
 },
 /**
 * @method _unbindDOM
 * @protected
 */
 _unbindDOM : function(boundingBox) {
 var focusHandle = Widget._hDocFocus,
 yuid = Y.stamp(this, true),
 focusListeners,
 mouseHandle = this._hDocMouseDown;
 if (focusHandle) {
 focusListeners = focusHandle.listeners;
 if (focusListeners[yuid]) {
 delete focusListeners[yuid];
 focusListeners.count--;
 }
 if (focusListeners.count === 0) {
 focusHandle.detach();
 Widget._hDocFocus = null;
 }
 }
 if (WEBKIT && mouseHandle) {
 mouseHandle.detach();
 }
 },
 /**
 * Updates the widget UI to reflect the attribute state.
 *
 * @method _syncUI
 * @protected
 */
 _syncUI: function() {
 this._syncAttrUI(this._UI_ATTRS.SYNC);
 },
 /**
 * Sets the height on the widget's bounding box element
 *
 * @method _uiSetHeight
 * @protected
 * @param {String | Number} val
 */
 _uiSetHeight: function(val) {
 this._uiSetDim(HEIGHT, val);
 this._uiSizeCB((val !== EMPTY_STR && val !== AUTO));
 },
 /**
 * Sets the width on the widget's bounding box element
 *
 * @method _uiSetWidth
 * @protected
 * @param {String | Number} val
 */
 _uiSetWidth: function(val) {
 this._uiSetDim(WIDTH, val);
 },
 /**
 * @method _uiSetDim
 * @private
 * @param {String} dim The dimension - "width" or "height"
 * @param {Number | String} val The value to set
 */
 _uiSetDim: function(dimension, val) {
 this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val);
 },
 /**
 * Sets the visible state for the UI
 *
 * @method _uiSetVisible
 * @protected
 * @param {boolean} val
 */
 _uiSetVisible: function(val) {
 this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val);
 },
 /**
 * Sets the disabled state for the UI
 *
 * @method _uiSetDisabled
 * @protected
 * @param {boolean} val
 */
 _uiSetDisabled: function(val) {
 this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val);
 },
 /**
 * Sets the focused state for the UI
 *
 * @method _uiSetFocused
 * @protected
 * @param {boolean} val
 * @param {string} src String representing the source that triggered an update to
 * the UI.
 */
 _uiSetFocused: function(val, src) {
 var boundingBox = this.get(BOUNDING_BOX);
 boundingBox.toggleClass(this.getClassName(FOCUSED), val);
 if (src !== UI) {
 if (val) {
 boundingBox.focus();
 } else {
 boundingBox.blur();
 }
 }
 },
 /**
 * Set the tabIndex on the widget's rendered UI
 *
 * @method _uiSetTabIndex
 * @protected
 * @param Number
 */
 _uiSetTabIndex: function(index) {
 var boundingBox = this.get(BOUNDING_BOX);
 if (L.isNumber(index)) {
 boundingBox.set(TAB_INDEX, index);
 } else {
 boundingBox.removeAttribute(TAB_INDEX);
 }
 },
 /**
 * @method _onDocMouseDown
 * @description "mousedown" event handler for the owner document of the
 * widget's bounding box.
 * @protected
 * @param {EventFacade} evt The event facade for the DOM focus event
 */
 _onDocMouseDown: function (evt) {
 if (this._domFocus) {
 this._onDocFocus(evt);
 }
 },
 /**
 * DOM focus event handler, used to sync the state of the Widget with the DOM
 *
 * @method _onDocFocus
 * @protected
 * @param {EventFacade} evt The event facade for the DOM focus event
 */
 _onDocFocus: function (evt) {
 var widget = Widget.getByNode(evt.target),
 activeWidget = Widget._active;
 if (activeWidget && (activeWidget !== widget)) {
 activeWidget._domFocus = false;
 activeWidget._set(FOCUSED, false, {src:UI});
 Widget._active = null;
 }
 if (widget) {
 widget._domFocus = true;
 widget._set(FOCUSED, true, {src:UI});
 Widget._active = widget;
 }
 },
 /**
 * Generic toString implementation for all widgets.
 *
 * @method toString
 * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ]
 */
 toString: function() {
 // Using deprecated name prop for kweight squeeze.
 return this.name + "[" + this.get(ID) + "]";
 },
 /**
 * Default unit to use for dimension values
 *
 * @property DEF_UNIT
 * @type String
 */
 DEF_UNIT : "px",
 /**
 * Default node to render the bounding box to. If not set,
 * will default to the current document body.
 *
 * @property DEF_PARENT_NODE
 * @type String | Node
 */
 DEF_PARENT_NODE : null,
 /**
 * Property defining the markup template for content box. If your Widget doesn't
 * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null,
 * and contentBox and boundingBox will both point to the same Node.
 *
 * @property CONTENT_TEMPLATE
 * @type String
 */
 CONTENT_TEMPLATE : DIV,
 /**
 * Property defining the markup template for bounding box.
 *
 * @property BOUNDING_TEMPLATE
 * @type String
 */
 BOUNDING_TEMPLATE : DIV,
 /**
 * @method _guid
 * @protected
 */
 _guid : function() {
 return Y.guid();
 },
 /**
 * @method _validTabIndex
 * @protected
 * @param {Number} tabIndex
 */
 _validTabIndex : function (tabIndex) {
 return (L.isNumber(tabIndex) || L.isNull(tabIndex));
 },
 /**
 * Binds after listeners for the list of attributes provided
 *
 * @method _bindAttrUI
 * @private
 * @param {Array} attrs
 */
 _bindAttrUI : function(attrs) {
 var i,
 l = attrs.length;
 for (i = 0; i < l; i++) {
 this.after(attrs[i] + CHANGE, this._setAttrUI);
 }
 },
 /**
 * Invokes the _uiSet&#61;ATTR NAME&#62; method for the list of attributes provided
 *
 * @method _syncAttrUI
 * @private
 * @param {Array} attrs
 */
 _syncAttrUI : function(attrs) {
 var i, l = attrs.length, attr;
 for (i = 0; i < l; i++) {
 attr = attrs[i];
 this[_UISET + _toInitialCap(attr)](this.get(attr));
 }
 },
 /**
 * @method _setAttrUI
 * @private
 * @param {EventFacade} e
 */
 _setAttrUI : function(e) {
 if (e.target === this) {
 this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src);
 }
 },
 /**
 * The default setter for the strings attribute. Merges partial sets
 * into the full string set, to allow users to partial sets of strings
 *
 * @method _strSetter
 * @protected
 * @param {Object} strings
 * @return {String} The full set of strings to set
 */
 _strSetter : function(strings) {
 return Y.merge(this.get(STRINGS), strings);
 },
 /**
 * Helper method to get a specific string value
 *
 * @deprecated Used by deprecated WidgetLocale implementations.
 * @method getString
 * @param {String} key
 * @return {String} The string
 */
 getString : function(key) {
 return this.get(STRINGS)[key];
 },
 /**
 * Helper method to get the complete set of strings for the widget
 *
 * @deprecated Used by deprecated WidgetLocale implementations.
 * @method getStrings
 * @param {String} key
 * @return {String} The strings
 */
 getStrings : function() {
 return this.get(STRINGS);
 },
 /**
 * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations
 *
 * @property _UI_ATTRS
 * @type Object
 * @private
 */
 _UI_ATTRS : {
 BIND: UI_ATTRS,
 SYNC: UI_ATTRS
 }
});
Y.Widget = Widget;
 

AltStyle によって変換されたページ (->オリジナル) /