[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/widget-base/ -> widget-base.js (source)

   1  /*
   2  YUI 3.17.2 (build 9c3c78e)
   3  Copyright 2014 Yahoo! Inc. All rights reserved.
   4  Licensed under the BSD License.
   5  http://yuilibrary.com/license/
   6  */
   7  
   8  YUI.add('widget-base', function (Y, NAME) {
   9  
  10  /**
  11   * Provides the base Widget class, with HTML Parser support
  12   *
  13   * @module widget
  14   * @main widget
  15   */
  16  
  17  /**
  18   * Provides the base Widget class
  19   *
  20   * @module widget
  21   * @submodule widget-base
  22   */
  23  var L = Y.Lang,
  24      Node = Y.Node,
  25  
  26      ClassNameManager = Y.ClassNameManager,
  27  
  28      _getClassName = ClassNameManager.getClassName,
  29      _getWidgetClassName,
  30  
  31      _toInitialCap = Y.cached(function(str) {
  32          return str.substring(0, 1).toUpperCase() + str.substring(1);
  33      }),
  34  
  35      // K-Weight, IE GC optimizations
  36      CONTENT = "content",
  37      VISIBLE = "visible",
  38      HIDDEN = "hidden",
  39      DISABLED = "disabled",
  40      FOCUSED = "focused",
  41      WIDTH = "width",
  42      HEIGHT = "height",
  43      BOUNDING_BOX = "boundingBox",
  44      CONTENT_BOX = "contentBox",
  45      PARENT_NODE = "parentNode",
  46      OWNER_DOCUMENT = "ownerDocument",
  47      AUTO = "auto",
  48      SRC_NODE = "srcNode",
  49      BODY = "body",
  50      TAB_INDEX = "tabIndex",
  51      ID = "id",
  52      RENDER = "render",
  53      RENDERED = "rendered",
  54      DESTROYED = "destroyed",
  55      STRINGS = "strings",
  56      DIV = "<div></div>",
  57      CHANGE = "Change",
  58      LOADING = "loading",
  59  
  60      _UISET = "_uiSet",
  61  
  62      EMPTY_STR = "",
  63      EMPTY_FN = function() {},
  64  
  65      TRUE = true,
  66      FALSE = false,
  67  
  68      UI,
  69      ATTRS = {},
  70      UI_ATTRS = [VISIBLE, DISABLED, HEIGHT, WIDTH, FOCUSED, TAB_INDEX],
  71  
  72      WEBKIT = Y.UA.webkit,
  73  
  74      // Widget nodeid-to-instance map.
  75      _instances = {};
  76  
  77  /**
  78   * A base class for widgets, providing:
  79   * <ul>
  80   *    <li>The render lifecycle method, in addition to the init and destroy
  81   *        lifecycle methods provide by Base</li>
  82   *    <li>Abstract methods to support consistent MVC structure across
  83   *        widgets: renderer, renderUI, bindUI, syncUI</li>
  84   *    <li>Support for common widget attributes, such as boundingBox, contentBox, visible,
  85   *        disabled, focused, strings</li>
  86   * </ul>
  87   *
  88   * @param config {Object} Object literal specifying widget configuration properties.
  89   *
  90   * @class Widget
  91   * @constructor
  92   * @extends Base
  93   */
  94  function Widget(config) {
  95  
  96      // kweight
  97      var widget = this,
  98          parentNode,
  99          render,
 100          constructor = widget.constructor;
 101  
 102      widget._strs = {};
 103      widget._cssPrefix = constructor.CSS_PREFIX || _getClassName(constructor.NAME.toLowerCase());
 104  
 105      // We need a config for HTML_PARSER to work.
 106      config = config || {};
 107  
 108      Widget.superclass.constructor.call(widget, config);
 109  
 110      render = widget.get(RENDER);
 111  
 112      if (render) {
 113          // Render could be a node or boolean
 114          if (render !== TRUE) {
 115              parentNode = render;
 116          }
 117          widget.render(parentNode);
 118      }
 119  }
 120  
 121  /**
 122   * Static property provides a string to identify the class.
 123   * <p>
 124   * Currently used to apply class identifiers to the bounding box
 125   * and to classify events fired by the widget.
 126   * </p>
 127   *
 128   * @property NAME
 129   * @type String
 130   * @static
 131   */
 132  Widget.NAME = "widget";
 133  
 134  /**
 135   * Constant used to identify state changes originating from
 136   * the DOM (as opposed to the JavaScript model).
 137   *
 138   * @property UI_SRC
 139   * @type String
 140   * @static
 141   * @final
 142   */
 143  UI = Widget.UI_SRC = "ui";
 144  
 145  /**
 146   * Static property used to define the default attribute
 147   * configuration for the Widget.
 148   *
 149   * @property ATTRS
 150   * @type Object
 151   * @static
 152   */
 153  Widget.ATTRS = ATTRS;
 154  
 155  // Trying to optimize kweight by setting up attrs this way saves about 0.4K min'd
 156  
 157  /**
 158   * @attribute id
 159   * @writeOnce
 160   * @default Generated using guid()
 161   * @type String
 162   */
 163  
 164  ATTRS[ID] = {
 165      valueFn: "_guid",
 166      writeOnce: TRUE
 167  };
 168  
 169  /**
 170   * Flag indicating whether or not this Widget
 171   * has been through the render lifecycle phase.
 172   *
 173   * @attribute rendered
 174   * @readOnly
 175   * @default false
 176   * @type boolean
 177   */
 178  ATTRS[RENDERED] = {
 179      value:FALSE,
 180      readOnly: TRUE
 181  };
 182  
 183  /**
 184   * @attribute boundingBox
 185   * @description The outermost DOM node for the Widget, used for sizing and positioning
 186   * of a Widget as well as a containing element for any decorator elements used
 187   * for skinning.
 188   * @type String | Node
 189   * @writeOnce
 190   */
 191  ATTRS[BOUNDING_BOX] = {
 192      valueFn:"_defaultBB",
 193      setter: "_setBB",
 194      writeOnce: TRUE
 195  };
 196  
 197  /**
 198   * @attribute contentBox
 199   * @description A DOM node that is a direct descendant of a Widget's bounding box that
 200   * houses its content.
 201   * @type String | Node
 202   * @writeOnce
 203   */
 204  ATTRS[CONTENT_BOX] = {
 205      valueFn:"_defaultCB",
 206      setter: "_setCB",
 207      writeOnce: TRUE
 208  };
 209  
 210  /**
 211   * @attribute tabIndex
 212   * @description Number (between -32767 to 32767) indicating the widget's
 213   * position in the default tab flow.  The value is used to set the
 214   * "tabIndex" attribute on the widget's bounding box.  Negative values allow
 215   * the widget to receive DOM focus programmatically (by calling the focus
 216   * method), while being removed from the default tab flow.  A value of
 217   * null removes the "tabIndex" attribute from the widget's bounding box.
 218   * @type Number
 219   * @default null
 220   */
 221  ATTRS[TAB_INDEX] = {
 222      value: null,
 223      validator: "_validTabIndex"
 224  };
 225  
 226  /**
 227   * @attribute focused
 228   * @description Boolean indicating if the Widget, or one of its descendants,
 229   * has focus.
 230   * @readOnly
 231   * @default false
 232   * @type boolean
 233   */
 234  ATTRS[FOCUSED] = {
 235      value: FALSE,
 236      readOnly:TRUE
 237  };
 238  
 239  /**
 240   * @attribute disabled
 241   * @description Boolean indicating if the Widget should be disabled. The disabled implementation
 242   * is left to the specific classes extending widget.
 243   * @default false
 244   * @type boolean
 245   */
 246  ATTRS[DISABLED] = {
 247      value: FALSE
 248  };
 249  
 250  /**
 251   * @attribute visible
 252   * @description Boolean indicating whether or not the Widget is visible.
 253   * @default TRUE
 254   * @type boolean
 255   */
 256  ATTRS[VISIBLE] = {
 257      value: TRUE
 258  };
 259  
 260  /**
 261   * @attribute height
 262   * @description String with units, or number, representing the height of the Widget. If a number is provided,
 263   * the default unit, defined by the Widgets DEF_UNIT, property is used.
 264   * @default EMPTY_STR
 265   * @type {String | Number}
 266   */
 267  ATTRS[HEIGHT] = {
 268      value: EMPTY_STR
 269  };
 270  
 271  /**
 272   * @attribute width
 273   * @description String with units, or number, representing the width of the Widget. If a number is provided,
 274   * the default unit, defined by the Widgets DEF_UNIT, property is used.
 275   * @default EMPTY_STR
 276   * @type {String | Number}
 277   */
 278  ATTRS[WIDTH] = {
 279      value: EMPTY_STR
 280  };
 281  
 282  /**
 283   * @attribute strings
 284   * @description Collection of strings used to label elements of the Widget's UI.
 285   * @default null
 286   * @type Object
 287   */
 288  ATTRS[STRINGS] = {
 289      value: {},
 290      setter: "_strSetter",
 291      getter: "_strGetter"
 292  };
 293  
 294  /**
 295   * Whether or not to render the widget automatically after init, and optionally, to which parent node.
 296   *
 297   * @attribute render
 298   * @type boolean | Node
 299   * @writeOnce
 300   */
 301  ATTRS[RENDER] = {
 302      value:FALSE,
 303      writeOnce:TRUE
 304  };
 305  
 306  /**
 307   * The css prefix which the static Widget.getClassName method should use when constructing class names
 308   *
 309   * @property CSS_PREFIX
 310   * @type String
 311   * @default Widget.NAME.toLowerCase()
 312   * @private
 313   * @static
 314   */
 315  Widget.CSS_PREFIX = _getClassName(Widget.NAME.toLowerCase());
 316  
 317  /**
 318   * Generate a standard prefixed classname for the Widget, prefixed by the default prefix defined
 319   * by the <code>Y.config.classNamePrefix</code> attribute used by <code>ClassNameManager</code> and
 320   * <code>Widget.NAME.toLowerCase()</code> (e.g. "yui-widget-xxxxx-yyyyy", based on default values for
 321   * the prefix and widget class name).
 322   * <p>
 323   * The instance based version of this method can be used to generate standard prefixed classnames,
 324   * based on the instances NAME, as opposed to Widget.NAME. This method should be used when you
 325   * need to use a constant class name across different types instances.
 326   * </p>
 327   * @method getClassName
 328   * @param {String*} args* 0..n strings which should be concatenated, using the default separator defined by ClassNameManager, to create the class name
 329   */
 330  Widget.getClassName = function() {
 331      // arguments needs to be array'fied to concat
 332      return _getClassName.apply(ClassNameManager, [Widget.CSS_PREFIX].concat(Y.Array(arguments), true));
 333  };
 334  
 335  _getWidgetClassName = Widget.getClassName;
 336  
 337  /**
 338   * Returns the widget instance whose bounding box contains, or is, the given node.
 339   * <p>
 340   * In the case of nested widgets, the nearest bounding box ancestor is used to
 341   * return the widget instance.
 342   * </p>
 343   * @method getByNode
 344   * @static
 345   * @param node {Node | String} The node for which to return a Widget instance. If a selector
 346   * string is passed in, which selects more than one node, the first node found is used.
 347   * @return {Widget} Widget instance, or null if not found.
 348   */
 349  Widget.getByNode = function(node) {
 350      var widget,
 351          widgetMarker = _getWidgetClassName();
 352  
 353      node = Node.one(node);
 354      if (node) {
 355          node = node.ancestor("." + widgetMarker, true);
 356          if (node) {
 357              widget = _instances[Y.stamp(node, true)];
 358          }
 359      }
 360  
 361      return widget || null;
 362  };
 363  
 364  Y.extend(Widget, Y.Base, {
 365  
 366      /**
 367       * Returns a class name prefixed with the the value of the
 368       * <code>YUI.config.classNamePrefix</code> attribute + the instances <code>NAME</code> property.
 369       * Uses <code>YUI.config.classNameDelimiter</code> attribute to delimit the provided strings.
 370       * e.g.
 371       * <code>
 372       * <pre>
 373       *    // returns "yui-slider-foo-bar", for a slider instance
 374       *    var scn = slider.getClassName('foo','bar');
 375       *
 376       *    // returns "yui-overlay-foo-bar", for an overlay instance
 377       *    var ocn = overlay.getClassName('foo','bar');
 378       * </pre>
 379       * </code>
 380       *
 381       * @method getClassName
 382       * @param {String} [classnames*] One or more classname bits to be joined and prefixed
 383       */
 384      getClassName: function () {
 385          return _getClassName.apply(ClassNameManager, [this._cssPrefix].concat(Y.Array(arguments), true));
 386      },
 387  
 388      /**
 389       * Initializer lifecycle implementation for the Widget class. Registers the
 390       * widget instance, and runs through the Widget's HTML_PARSER definition.
 391       *
 392       * @method initializer
 393       * @protected
 394       * @param  config {Object} Configuration object literal for the widget
 395       */
 396      initializer: function(config) {
 397  
 398          var bb = this.get(BOUNDING_BOX);
 399  
 400          if (bb instanceof Node) {
 401              this._mapInstance(Y.stamp(bb));
 402          }
 403  
 404          /**
 405           * Notification event, which widget implementations can fire, when
 406           * they change the content of the widget. This event has no default
 407           * behavior and cannot be prevented, so the "on" or "after"
 408           * moments are effectively equivalent (with on listeners being invoked before
 409           * after listeners).
 410           *
 411           * @event widget:contentUpdate
 412           * @preventable false
 413           * @param {EventFacade} e The Event Facade
 414           */
 415      },
 416  
 417      /**
 418       * Utility method used to add an entry to the boundingBox id to instance map.
 419       *
 420       * This method can be used to populate the instance with lazily created boundingBox Node references.
 421       *
 422       * @method _mapInstance
 423       * @param {String} The boundingBox id
 424       * @protected
 425       */
 426      _mapInstance : function(id) {
 427          _instances[id] = this;
 428      },
 429  
 430      /**
 431       * Destructor lifecycle implementation for the Widget class. Purges events attached
 432       * to the bounding box and content box, removes them from the DOM and removes
 433       * the Widget from the list of registered widgets.
 434       *
 435       * @method destructor
 436       * @protected
 437       */
 438      destructor: function() {
 439  
 440          var boundingBox = this.get(BOUNDING_BOX),
 441              bbGuid;
 442  
 443          if (boundingBox instanceof Node) {
 444              bbGuid = Y.stamp(boundingBox,true);
 445  
 446              if (bbGuid in _instances) {
 447                  delete _instances[bbGuid];
 448              }
 449  
 450              this._destroyBox();
 451          }
 452      },
 453  
 454      /**
 455       * <p>
 456       * Destroy lifecycle method. Fires the destroy
 457       * event, prior to invoking destructors for the
 458       * class hierarchy.
 459       *
 460       * Overrides Base's implementation, to support arguments to destroy
 461       * </p>
 462       * <p>
 463       * Subscribers to the destroy
 464       * event can invoke preventDefault on the event object, to prevent destruction
 465       * from proceeding.
 466       * </p>
 467       * @method destroy
 468       * @param destroyAllNodes {Boolean} If true, all nodes contained within the Widget are
 469       * removed and destroyed. Defaults to false due to potentially high run-time cost.
 470       * @return {Widget} A reference to this object
 471       * @chainable
 472       */
 473      destroy: function(destroyAllNodes) {
 474          this._destroyAllNodes = destroyAllNodes;
 475          return Widget.superclass.destroy.apply(this);
 476      },
 477  
 478      /**
 479       * Removes and destroys the widgets rendered boundingBox, contentBox,
 480       * and detaches bound UI events.
 481       *
 482       * @method _destroyBox
 483       * @protected
 484       */
 485      _destroyBox : function() {
 486  
 487          var boundingBox = this.get(BOUNDING_BOX),
 488              contentBox = this.get(CONTENT_BOX),
 489              deep = this._destroyAllNodes,
 490              same;
 491  
 492          same = boundingBox && boundingBox.compareTo(contentBox);
 493  
 494          if (this.UI_EVENTS) {
 495              this._destroyUIEvents();
 496          }
 497  
 498          this._unbindUI(boundingBox);
 499  
 500          if (contentBox) {
 501              if (deep) {
 502                  contentBox.empty();
 503              }
 504              contentBox.remove(TRUE);
 505          }
 506  
 507          if (!same) {
 508              if (deep) {
 509                  boundingBox.empty();
 510              }
 511              boundingBox.remove(TRUE);
 512          }
 513      },
 514  
 515      /**
 516       * Establishes the initial DOM for the widget. Invoking this
 517       * method will lead to the creating of all DOM elements for
 518       * the widget (or the manipulation of existing DOM elements
 519       * for the progressive enhancement use case).
 520       * <p>
 521       * This method should only be invoked once for an initialized
 522       * widget.
 523       * </p>
 524       * <p>
 525       * It delegates to the widget specific renderer method to do
 526       * the actual work.
 527       * </p>
 528       *
 529       * @method render
 530       * @chainable
 531       * @final
 532       * @param  parentNode {Object | String} Optional. The Node under which the
 533       * Widget is to be rendered. This can be a Node instance or a CSS selector string.
 534       * <p>
 535       * If the selector string returns more than one Node, the first node will be used
 536       * as the parentNode. NOTE: This argument is required if both the boundingBox and contentBox
 537       * are not currently in the document. If it's not provided, the Widget will be rendered
 538       * to the body of the current document in this case.
 539       * </p>
 540       */
 541      render: function(parentNode) {
 542  
 543          if (!this.get(DESTROYED) && !this.get(RENDERED)) {
 544               /**
 545                * Lifecycle event for the render phase, fired prior to rendering the UI
 546                * for the widget (prior to invoking the widget's renderer method).
 547                * <p>
 548                * Subscribers to the "on" moment of this event, will be notified
 549                * before the widget is rendered.
 550                * </p>
 551                * <p>
 552                * Subscribers to the "after" moment of this event, will be notified
 553                * after rendering is complete.
 554                * </p>
 555                *
 556                * @event render
 557                * @preventable _defRenderFn
 558                * @param {EventFacade} e The Event Facade
 559                */
 560              this.publish(RENDER, {
 561                  queuable:FALSE,
 562                  fireOnce:TRUE,
 563                  defaultTargetOnly:TRUE,
 564                  defaultFn: this._defRenderFn
 565              });
 566  
 567              this.fire(RENDER, {parentNode: (parentNode) ? Node.one(parentNode) : null});
 568          }
 569          return this;
 570      },
 571  
 572      /**
 573       * Default render handler
 574       *
 575       * @method _defRenderFn
 576       * @protected
 577       * @param {EventFacade} e The Event object
 578       * @param {Node} parentNode The parent node to render to, if passed in to the <code>render</code> method
 579       */
 580      _defRenderFn : function(e) {
 581          this._parentNode = e.parentNode;
 582  
 583          this.renderer();
 584          this._set(RENDERED, TRUE);
 585  
 586          this._removeLoadingClassNames();
 587      },
 588  
 589      /**
 590       * Creates DOM (or manipulates DOM for progressive enhancement)
 591       * This method is invoked by render() and is not chained
 592       * automatically for the class hierarchy (unlike initializer, destructor)
 593       * so it should be chained manually for subclasses if required.
 594       *
 595       * @method renderer
 596       * @protected
 597       */
 598      renderer: function() {
 599          // kweight
 600          var widget = this;
 601  
 602          widget._renderUI();
 603          widget.renderUI();
 604  
 605          widget._bindUI();
 606          widget.bindUI();
 607  
 608          widget._syncUI();
 609          widget.syncUI();
 610      },
 611  
 612      /**
 613       * Configures/Sets up listeners to bind Widget State to UI/DOM
 614       *
 615       * This method is not called by framework and is not chained
 616       * automatically for the class hierarchy.
 617       *
 618       * @method bindUI
 619       * @protected
 620       */
 621      bindUI: EMPTY_FN,
 622  
 623      /**
 624       * Adds nodes to the DOM
 625       *
 626       * This method is not called by framework and is not chained
 627       * automatically for the class hierarchy.
 628       *
 629       * @method renderUI
 630       * @protected
 631       */
 632      renderUI: EMPTY_FN,
 633  
 634      /**
 635       * Refreshes the rendered UI, based on Widget State
 636       *
 637       * This method is not called by framework and is not chained
 638       * automatically for the class hierarchy.
 639       *
 640       * @method syncUI
 641       * @protected
 642       *
 643       */
 644      syncUI: EMPTY_FN,
 645  
 646      /**
 647       * @method hide
 648       * @description Hides the Widget by setting the "visible" attribute to "false".
 649       * @chainable
 650       */
 651      hide: function() {
 652          return this.set(VISIBLE, FALSE);
 653      },
 654  
 655      /**
 656       * @method show
 657       * @description Shows the Widget by setting the "visible" attribute to "true".
 658       * @chainable
 659       */
 660      show: function() {
 661          return this.set(VISIBLE, TRUE);
 662      },
 663  
 664      /**
 665       * @method focus
 666       * @description Causes the Widget to receive the focus by setting the "focused"
 667       * attribute to "true".
 668       * @chainable
 669       */
 670      focus: function () {
 671          return this._set(FOCUSED, TRUE);
 672      },
 673  
 674      /**
 675       * @method blur
 676       * @description Causes the Widget to lose focus by setting the "focused" attribute
 677       * to "false"
 678       * @chainable
 679       */
 680      blur: function () {
 681          return this._set(FOCUSED, FALSE);
 682      },
 683  
 684      /**
 685       * @method enable
 686       * @description Set the Widget's "disabled" attribute to "false".
 687       * @chainable
 688       */
 689      enable: function() {
 690          return this.set(DISABLED, FALSE);
 691      },
 692  
 693      /**
 694       * @method disable
 695       * @description Set the Widget's "disabled" attribute to "true".
 696       * @chainable
 697       */
 698      disable: function() {
 699          return this.set(DISABLED, TRUE);
 700      },
 701  
 702      /**
 703       * @method _uiSizeCB
 704       * @protected
 705       * @param {boolean} expand
 706       */
 707      _uiSizeCB : function(expand) {
 708          this.get(CONTENT_BOX).toggleClass(_getWidgetClassName(CONTENT, "expanded"), expand);
 709      },
 710  
 711      /**
 712       * Helper method to collect the boundingBox and contentBox and append to the provided parentNode, if not
 713       * already a child. The owner document of the boundingBox, or the owner document of the contentBox will be used
 714       * as the document into which the Widget is rendered if a parentNode is node is not provided. If both the boundingBox and
 715       * the contentBox are not currently in the document, and no parentNode is provided, the widget will be rendered
 716       * to the current document's body.
 717       *
 718       * @method _renderBox
 719       * @private
 720       * @param {Node} parentNode The parentNode to render the widget to. If not provided, and both the boundingBox and
 721       * the contentBox are not currently in the document, the widget will be rendered to the current document's body.
 722       */
 723      _renderBox: function(parentNode) {
 724  
 725          // TODO: Performance Optimization [ More effective algo to reduce Node refs, compares, replaces? ]
 726  
 727          var widget = this, // kweight
 728              contentBox = widget.get(CONTENT_BOX),
 729              boundingBox = widget.get(BOUNDING_BOX),
 730              srcNode = widget.get(SRC_NODE),
 731              defParentNode = widget.DEF_PARENT_NODE,
 732  
 733              doc = (srcNode && srcNode.get(OWNER_DOCUMENT)) || boundingBox.get(OWNER_DOCUMENT) || contentBox.get(OWNER_DOCUMENT);
 734  
 735          // If srcNode (assume it's always in doc), have contentBox take its place (widget render responsible for re-use of srcNode contents)
 736          if (srcNode && !srcNode.compareTo(contentBox) && !contentBox.inDoc(doc)) {
 737              srcNode.replace(contentBox);
 738          }
 739  
 740          if (!boundingBox.compareTo(contentBox.get(PARENT_NODE)) && !boundingBox.compareTo(contentBox)) {
 741              // If contentBox box is already in the document, have boundingBox box take it's place
 742              if (contentBox.inDoc(doc)) {
 743                  contentBox.replace(boundingBox);
 744              }
 745              boundingBox.appendChild(contentBox);
 746          }
 747  
 748          parentNode = parentNode || (defParentNode && Node.one(defParentNode));
 749  
 750          if (parentNode) {
 751              parentNode.appendChild(boundingBox);
 752          } else if (!boundingBox.inDoc(doc)) {
 753              Node.one(BODY).insert(boundingBox, 0);
 754          }
 755      },
 756  
 757      /**
 758       * Setter for the boundingBox attribute
 759       *
 760       * @method _setBB
 761       * @private
 762       * @param {Node|String} node
 763       * @return Node
 764       */
 765      _setBB: function(node) {
 766          return this._setBox(this.get(ID), node, this.BOUNDING_TEMPLATE, true);
 767      },
 768  
 769      /**
 770       * Setter for the contentBox attribute
 771       *
 772       * @method _setCB
 773       * @private
 774       * @param {Node|String} node
 775       * @return Node
 776       */
 777      _setCB: function(node) {
 778          return (this.CONTENT_TEMPLATE === null) ? this.get(BOUNDING_BOX) : this._setBox(null, node, this.CONTENT_TEMPLATE, false);
 779      },
 780  
 781      /**
 782       * Returns the default value for the boundingBox attribute.
 783       *
 784       * For the Widget class, this will most commonly be null (resulting in a new
 785       * boundingBox node instance being created), unless a srcNode was provided
 786       * and CONTENT_TEMPLATE is null, in which case it will be srcNode.
 787       * This behavior was introduced in 3.17.2 to accomodate single-box widgets
 788       * whose BB & CB both point to srcNode (e.g. Y.Button).
 789       *
 790       * @method _defaultBB
 791       * @protected
 792       */
 793      _defaultBB : function() {
 794          var node = this.get(SRC_NODE),
 795              nullCT = (this.CONTENT_TEMPLATE === null);
 796  
 797          return ((node && nullCT) ? node : null);
 798      },
 799  
 800      /**
 801       * Returns the default value for the contentBox attribute.
 802       *
 803       * For the Widget class, this will be the srcNode if provided, otherwise null (resulting in
 804       * a new contentBox node instance being created)
 805       *
 806       * @method _defaultCB
 807       * @protected
 808       */
 809      _defaultCB : function(node) {
 810          return this.get(SRC_NODE) || null;
 811      },
 812  
 813      /**
 814       * Helper method to set the bounding/content box, or create it from
 815       * the provided template if not found.
 816       *
 817       * @method _setBox
 818       * @private
 819       *
 820       * @param {String} id The node's id attribute
 821       * @param {Node|String} node The node reference
 822       * @param {String} template HTML string template for the node
 823       * @param {boolean} isBounding true if this is the boundingBox, false if it's the contentBox
 824       * @return {Node} The node
 825       */
 826      _setBox : function(id, node, template, isBounding) {
 827  
 828          node = Node.one(node);
 829  
 830          if (!node) {
 831              node = Node.create(template);
 832  
 833              if (isBounding) {
 834                  this._bbFromTemplate = true;
 835              } else {
 836                  this._cbFromTemplate = true;
 837              }
 838          }
 839  
 840          if (!node.get(ID)) {
 841              node.set(ID, id || Y.guid());
 842          }
 843  
 844          return node;
 845      },
 846  
 847      /**
 848       * Initializes the UI state for the Widget's bounding/content boxes.
 849       *
 850       * @method _renderUI
 851       * @protected
 852       */
 853      _renderUI: function() {
 854          this._renderBoxClassNames();
 855          this._renderBox(this._parentNode);
 856      },
 857  
 858      /**
 859       * Applies standard class names to the boundingBox and contentBox
 860       *
 861       * @method _renderBoxClassNames
 862       * @protected
 863       */
 864      _renderBoxClassNames : function() {
 865          var classes = this._getClasses(),
 866              cl,
 867              boundingBox = this.get(BOUNDING_BOX),
 868              i;
 869  
 870          boundingBox.addClass(_getWidgetClassName());
 871  
 872          // Start from Widget Sub Class
 873          for (i = classes.length-3; i >= 0; i--) {
 874              cl = classes[i];
 875              boundingBox.addClass(cl.CSS_PREFIX || _getClassName(cl.NAME.toLowerCase()));
 876          }
 877  
 878          // Use instance based name for content box
 879          this.get(CONTENT_BOX).addClass(this.getClassName(CONTENT));
 880      },
 881  
 882      /**
 883       * Removes class names representative of the widget's loading state from
 884       * the boundingBox.
 885       *
 886       * @method _removeLoadingClassNames
 887       * @protected
 888       */
 889      _removeLoadingClassNames: function () {
 890  
 891          var boundingBox = this.get(BOUNDING_BOX),
 892              contentBox = this.get(CONTENT_BOX),
 893              instClass = this.getClassName(LOADING),
 894              widgetClass = _getWidgetClassName(LOADING);
 895  
 896          boundingBox.removeClass(widgetClass)
 897                     .removeClass(instClass);
 898  
 899          contentBox.removeClass(widgetClass)
 900                    .removeClass(instClass);
 901      },
 902  
 903      /**
 904       * Sets up DOM and CustomEvent listeners for the widget.
 905       *
 906       * @method _bindUI
 907       * @protected
 908       */
 909      _bindUI: function() {
 910          this._bindAttrUI(this._UI_ATTRS.BIND);
 911          this._bindDOM();
 912      },
 913  
 914      /**
 915       * @method _unbindUI
 916       * @protected
 917       */
 918      _unbindUI : function(boundingBox) {
 919          this._unbindDOM(boundingBox);
 920      },
 921  
 922      /**
 923       * Sets up DOM listeners, on elements rendered by the widget.
 924       *
 925       * @method _bindDOM
 926       * @protected
 927       */
 928      _bindDOM : function() {
 929          var oDocument = this.get(BOUNDING_BOX).get(OWNER_DOCUMENT),
 930              focusHandle = Widget._hDocFocus;
 931  
 932          // Shared listener across all Widgets.
 933          if (!focusHandle) {
 934              focusHandle = Widget._hDocFocus = oDocument.on("focus", this._onDocFocus, this);
 935              focusHandle.listeners = {
 936                  count: 0
 937              };
 938          }
 939  
 940          focusHandle.listeners[Y.stamp(this, true)] = true;
 941          focusHandle.listeners.count++;
 942  
 943          //    Fix for Webkit:
 944          //    Document doesn't receive focus in Webkit when the user mouses
 945          //    down on it, so the "focused" attribute won't get set to the
 946          //    correct value. Keeping this instance based for now, potential better performance.
 947          //  Otherwise we'll end up looking up widgets from the DOM on every mousedown.
 948          if (WEBKIT){
 949              this._hDocMouseDown = oDocument.on("mousedown", this._onDocMouseDown, this);
 950          }
 951      },
 952  
 953      /**
 954       * @method _unbindDOM
 955       * @protected
 956       */
 957      _unbindDOM : function(boundingBox) {
 958  
 959          var focusHandle = Widget._hDocFocus,
 960              yuid = Y.stamp(this, true),
 961              focusListeners,
 962              mouseHandle = this._hDocMouseDown;
 963  
 964          if (focusHandle) {
 965  
 966              focusListeners = focusHandle.listeners;
 967  
 968              if (focusListeners[yuid]) {
 969                  delete focusListeners[yuid];
 970                  focusListeners.count--;
 971              }
 972  
 973              if (focusListeners.count === 0) {
 974                  focusHandle.detach();
 975                  Widget._hDocFocus = null;
 976              }
 977          }
 978  
 979          if (WEBKIT && mouseHandle) {
 980              mouseHandle.detach();
 981          }
 982      },
 983  
 984      /**
 985       * Updates the widget UI to reflect the attribute state.
 986       *
 987       * @method _syncUI
 988       * @protected
 989       */
 990      _syncUI: function() {
 991          this._syncAttrUI(this._UI_ATTRS.SYNC);
 992      },
 993  
 994      /**
 995       * Sets the height on the widget's bounding box element
 996       *
 997       * @method _uiSetHeight
 998       * @protected
 999       * @param {String | Number} val
1000       */
1001      _uiSetHeight: function(val) {
1002          this._uiSetDim(HEIGHT, val);
1003          this._uiSizeCB((val !== EMPTY_STR && val !== AUTO));
1004      },
1005  
1006      /**
1007       * Sets the width on the widget's bounding box element
1008       *
1009       * @method _uiSetWidth
1010       * @protected
1011       * @param {String | Number} val
1012       */
1013      _uiSetWidth: function(val) {
1014          this._uiSetDim(WIDTH, val);
1015      },
1016  
1017      /**
1018       * @method _uiSetDim
1019       * @private
1020       * @param {String} dim The dimension - "width" or "height"
1021       * @param {Number | String} val The value to set
1022       */
1023      _uiSetDim: function(dimension, val) {
1024          this.get(BOUNDING_BOX).setStyle(dimension, L.isNumber(val) ? val + this.DEF_UNIT : val);
1025      },
1026  
1027      /**
1028       * Sets the visible state for the UI
1029       *
1030       * @method _uiSetVisible
1031       * @protected
1032       * @param {boolean} val
1033       */
1034      _uiSetVisible: function(val) {
1035          this.get(BOUNDING_BOX).toggleClass(this.getClassName(HIDDEN), !val);
1036      },
1037  
1038      /**
1039       * Sets the disabled state for the UI
1040       *
1041       * @method _uiSetDisabled
1042       * @protected
1043       * @param {boolean} val
1044       */
1045      _uiSetDisabled: function(val) {
1046          this.get(BOUNDING_BOX).toggleClass(this.getClassName(DISABLED), val);
1047      },
1048  
1049      /**
1050       * Sets the focused state for the UI
1051       *
1052       * @method _uiSetFocused
1053       * @protected
1054       * @param {boolean} val
1055       * @param {string} src String representing the source that triggered an update to
1056       * the UI.
1057       */
1058      _uiSetFocused: function(val, src) {
1059           var boundingBox = this.get(BOUNDING_BOX);
1060           boundingBox.toggleClass(this.getClassName(FOCUSED), val);
1061  
1062           if (src !== UI) {
1063              if (val) {
1064                  boundingBox.focus();
1065              } else {
1066                  boundingBox.blur();
1067              }
1068           }
1069      },
1070  
1071      /**
1072       * Set the tabIndex on the widget's rendered UI
1073       *
1074       * @method _uiSetTabIndex
1075       * @protected
1076       * @param Number
1077       */
1078      _uiSetTabIndex: function(index) {
1079          var boundingBox = this.get(BOUNDING_BOX);
1080  
1081          if (L.isNumber(index)) {
1082              boundingBox.set(TAB_INDEX, index);
1083          } else {
1084              boundingBox.removeAttribute(TAB_INDEX);
1085          }
1086      },
1087  
1088      /**
1089       * @method _onDocMouseDown
1090       * @description "mousedown" event handler for the owner document of the
1091       * widget's bounding box.
1092       * @protected
1093       * @param {EventFacade} evt The event facade for the DOM focus event
1094       */
1095      _onDocMouseDown: function (evt) {
1096          if (this._domFocus) {
1097              this._onDocFocus(evt);
1098          }
1099      },
1100  
1101      /**
1102       * DOM focus event handler, used to sync the state of the Widget with the DOM
1103       *
1104       * @method _onDocFocus
1105       * @protected
1106       * @param {EventFacade} evt The event facade for the DOM focus event
1107       */
1108      _onDocFocus: function (evt) {
1109          var widget = Widget.getByNode(evt.target),
1110              activeWidget = Widget._active;
1111  
1112          if (activeWidget && (activeWidget !== widget)) {
1113              activeWidget._domFocus = false;
1114              activeWidget._set(FOCUSED, false, {src:UI});
1115  
1116              Widget._active = null;
1117          }
1118  
1119          if (widget) {
1120              widget._domFocus = true;
1121              widget._set(FOCUSED, true, {src:UI});
1122  
1123              Widget._active = widget;
1124          }
1125      },
1126  
1127      /**
1128       * Generic toString implementation for all widgets.
1129       *
1130       * @method toString
1131       * @return {String} The default string value for the widget [ displays the NAME of the instance, and the unique id ]
1132       */
1133      toString: function() {
1134          // Using deprecated name prop for kweight squeeze.
1135          return this.name + "[" + this.get(ID) + "]";
1136      },
1137  
1138      /**
1139       * Default unit to use for dimension values
1140       *
1141       * @property DEF_UNIT
1142       * @type String
1143       */
1144      DEF_UNIT : "px",
1145  
1146      /**
1147       * Default node to render the bounding box to. If not set,
1148       * will default to the current document body.
1149       *
1150       * @property DEF_PARENT_NODE
1151       * @type String | Node
1152       */
1153      DEF_PARENT_NODE : null,
1154  
1155      /**
1156       * Property defining the markup template for content box. If your Widget doesn't
1157       * need the dual boundingBox/contentBox structure, set CONTENT_TEMPLATE to null,
1158       * and contentBox and boundingBox will both point to the same Node.
1159       *
1160       * @property CONTENT_TEMPLATE
1161       * @type String
1162       */
1163      CONTENT_TEMPLATE : DIV,
1164  
1165      /**
1166       * Property defining the markup template for bounding box.
1167       *
1168       * @property BOUNDING_TEMPLATE
1169       * @type String
1170       */
1171      BOUNDING_TEMPLATE : DIV,
1172  
1173      /**
1174       * @method _guid
1175       * @protected
1176       */
1177      _guid : function() {
1178          return Y.guid();
1179      },
1180  
1181      /**
1182       * @method _validTabIndex
1183       * @protected
1184       * @param {Number} tabIndex
1185       */
1186      _validTabIndex : function (tabIndex) {
1187          return (L.isNumber(tabIndex) || L.isNull(tabIndex));
1188      },
1189  
1190      /**
1191       * Binds after listeners for the list of attributes provided
1192       *
1193       * @method _bindAttrUI
1194       * @private
1195       * @param {Array} attrs
1196       */
1197      _bindAttrUI : function(attrs) {
1198          var i,
1199              l = attrs.length;
1200  
1201          for (i = 0; i < l; i++) {
1202              this.after(attrs[i] + CHANGE, this._setAttrUI);
1203          }
1204      },
1205  
1206      /**
1207       * Invokes the _uiSet&#61;ATTR NAME&#62; method for the list of attributes provided
1208       *
1209       * @method _syncAttrUI
1210       * @private
1211       * @param {Array} attrs
1212       */
1213      _syncAttrUI : function(attrs) {
1214          var i, l = attrs.length, attr;
1215          for (i = 0; i < l; i++) {
1216              attr = attrs[i];
1217              this[_UISET + _toInitialCap(attr)](this.get(attr));
1218          }
1219      },
1220  
1221      /**
1222       * @method _setAttrUI
1223       * @private
1224       * @param {EventFacade} e
1225       */
1226      _setAttrUI : function(e) {
1227          if (e.target === this) {
1228              this[_UISET + _toInitialCap(e.attrName)](e.newVal, e.src);
1229          }
1230      },
1231  
1232      /**
1233       * The default setter for the strings attribute. Merges partial sets
1234       * into the full string set, to allow users to partial sets of strings
1235       *
1236       * @method _strSetter
1237       * @protected
1238       * @param {Object} strings
1239       * @return {String} The full set of strings to set
1240       */
1241      _strSetter : function(strings) {
1242          return Y.merge(this.get(STRINGS), strings);
1243      },
1244  
1245      /**
1246       * Helper method to get a specific string value
1247       *
1248       * @deprecated Used by deprecated WidgetLocale implementations.
1249       * @method getString
1250       * @param {String} key
1251       * @return {String} The string
1252       */
1253      getString : function(key) {
1254          return this.get(STRINGS)[key];
1255      },
1256  
1257      /**
1258       * Helper method to get the complete set of strings for the widget
1259       *
1260       * @deprecated  Used by deprecated WidgetLocale implementations.
1261       * @method getStrings
1262       * @param {String} key
1263       * @return {String} The strings
1264       */
1265      getStrings : function() {
1266          return this.get(STRINGS);
1267      },
1268  
1269      /**
1270       * The lists of UI attributes to bind and sync for widget's _bindUI and _syncUI implementations
1271       *
1272       * @property _UI_ATTRS
1273       * @type Object
1274       * @private
1275       */
1276      _UI_ATTRS : {
1277          BIND: UI_ATTRS,
1278          SYNC: UI_ATTRS
1279      }
1280  });
1281  
1282  Y.Widget = Widget;
1283  
1284  
1285  }, '3.17.2', {
1286      "requires": [
1287          "attribute",
1288          "base-base",
1289          "base-pluginhost",
1290          "classnamemanager",
1291          "event-focus",
1292          "node-base",
1293          "node-style"
1294      ],
1295      "skinnable": true
1296  });


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1