[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

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


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