[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/view/ -> view-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('view', function (Y, NAME) {
   9  
  10  /**
  11  Represents a logical piece of an application's user interface, and provides a
  12  lightweight, overridable API for rendering content and handling delegated DOM
  13  events on a container element.
  14  
  15  @module app
  16  @submodule view
  17  @since 3.4.0
  18  **/
  19  
  20  /**
  21  Represents a logical piece of an application's user interface, and provides a
  22  lightweight, overridable API for rendering content and handling delegated DOM
  23  events on a container element.
  24  
  25  The View class imposes little structure and provides only minimal functionality
  26  of its own: it's basically just an overridable API interface that helps you
  27  implement custom views.
  28  
  29  As of YUI 3.5.0, View allows ad-hoc attributes to be specified at instantiation
  30  time, so you don't need to subclass `Y.View` to add custom attributes. Just pass
  31  them to the constructor:
  32  
  33      var view = new Y.View({foo: 'bar'});
  34      view.get('foo'); // => "bar"
  35  
  36  @class View
  37  @constructor
  38  @extends Base
  39  @since 3.4.0
  40  **/
  41  
  42  function View() {
  43      View.superclass.constructor.apply(this, arguments);
  44  }
  45  
  46  Y.View = Y.extend(View, Y.Base, {
  47      // -- Public Properties ----------------------------------------------------
  48  
  49      /**
  50      Template for this view's container.
  51  
  52      @property containerTemplate
  53      @type String
  54      @default "<div/>"
  55      @since 3.5.0
  56      **/
  57      containerTemplate: '<div/>',
  58  
  59      /**
  60      Hash of CSS selectors mapped to events to delegate to elements matching
  61      those selectors.
  62  
  63      CSS selectors are relative to the `container` element. Events are attached
  64      to the container, and delegation is used so that subscribers are only
  65      notified of events that occur on elements inside the container that match
  66      the specified selectors. This allows the container's contents to be re-
  67      rendered as needed without losing event subscriptions.
  68  
  69      Event handlers can be specified either as functions or as strings that map
  70      to function names on this view instance or its prototype.
  71  
  72      The `this` object in event handlers will refer to this view instance. If
  73      you'd prefer `this` to be something else, use `Y.bind()` to bind a custom
  74      `this` object.
  75  
  76      @example
  77  
  78          var view = new Y.View({
  79              events: {
  80                  // Call `this.toggle()` whenever the element with the id
  81                  // "toggle-button" is clicked.
  82                  '#toggle-button': {click: 'toggle'},
  83  
  84                  // Call `this.hoverOn()` when the mouse moves over any element
  85                  // with the "hoverable" class, and `this.hoverOff()` when the
  86                  // mouse moves out of any element with the "hoverable" class.
  87                  '.hoverable': {
  88                      mouseover: 'hoverOn',
  89                      mouseout : 'hoverOff'
  90                  }
  91              }
  92          });
  93  
  94      @property events
  95      @type Object
  96      @default {}
  97      **/
  98      events: {},
  99  
 100      /**
 101      Template for this view's contents.
 102  
 103      This is a convenience property that has no default behavior of its own.
 104      It's only provided as a convention to allow you to store whatever you
 105      consider to be a template, whether that's an HTML string, a `Y.Node`
 106      instance, a Mustache template, or anything else your little heart
 107      desires.
 108  
 109      How this template gets used is entirely up to you and your custom
 110      `render()` method.
 111  
 112      @property template
 113      @type mixed
 114      @default ''
 115      **/
 116      template: '',
 117  
 118      // -- Protected Properties -------------------------------------------------
 119  
 120      /**
 121      This tells `Y.Base` that it should create ad-hoc attributes for config
 122      properties passed to View's constructor. This makes it possible to
 123      instantiate a view and set a bunch of attributes without having to subclass
 124      `Y.View` and declare all those attributes first.
 125  
 126      @property _allowAdHocAttrs
 127      @type Boolean
 128      @default true
 129      @protected
 130      @since 3.5.0
 131      **/
 132      _allowAdHocAttrs: true,
 133  
 134      // -- Lifecycle Methods ----------------------------------------------------
 135      initializer: function (config) {
 136          config || (config = {});
 137  
 138          // Set instance properties specified in the config.
 139          config.containerTemplate &&
 140              (this.containerTemplate = config.containerTemplate);
 141  
 142          config.template && (this.template = config.template);
 143  
 144          // Merge events from the config into events in `this.events`.
 145          this.events = config.events ? Y.merge(this.events, config.events) :
 146              this.events;
 147  
 148          // When the container node changes (or when it's set for the first
 149          // time), we'll attach events to it, but not until then. This allows the
 150          // container to be created lazily the first time it's accessed rather
 151          // than always on init.
 152          this.after('containerChange', this._afterContainerChange);
 153      },
 154  
 155      /**
 156      Destroys this View, detaching any DOM events and optionally also destroying
 157      its container node.
 158  
 159      By default, the container node will not be destroyed. Pass an _options_
 160      object with a truthy `remove` property to destroy the container as well.
 161  
 162      @method destroy
 163      @param {Object} [options] Options.
 164          @param {Boolean} [options.remove=false] If `true`, this View's container
 165              will be removed from the DOM and destroyed as well.
 166      @chainable
 167      */
 168      destroy: function (options) {
 169          // We also accept `delete` as a synonym for `remove`.
 170          if (options && (options.remove || options['delete'])) {
 171              // Attaching an event handler here because the `destroy` event is
 172              // preventable. If we destroyed the container before calling the
 173              // superclass's `destroy()` method and the event was prevented, the
 174              // class would end up in a broken state.
 175              this.onceAfter('destroy', function () {
 176                  this._destroyContainer();
 177              });
 178          }
 179  
 180          return View.superclass.destroy.call(this);
 181      },
 182  
 183      destructor: function () {
 184          this.detachEvents();
 185          delete this._container;
 186      },
 187  
 188      // -- Public Methods -------------------------------------------------------
 189  
 190      /**
 191      Attaches delegated event handlers to this view's container element. This
 192      method is called internally to subscribe to events configured in the
 193      `events` attribute when the view is initialized.
 194  
 195      You may override this method to customize the event attaching logic.
 196  
 197      @method attachEvents
 198      @param {Object} [events] Hash of events to attach. See the docs for the
 199          `events` attribute for details on the format. If not specified, this
 200          view's `events` property will be used.
 201      @chainable
 202      @see detachEvents
 203      **/
 204      attachEvents: function (events) {
 205          var container = this.get('container'),
 206              owns      = Y.Object.owns,
 207              handler, handlers, name, selector;
 208  
 209          this.detachEvents();
 210  
 211          events || (events = this.events);
 212  
 213          for (selector in events) {
 214              if (!owns(events, selector)) { continue; }
 215  
 216              handlers = events[selector];
 217  
 218              for (name in handlers) {
 219                  if (!owns(handlers, name)) { continue; }
 220  
 221                  handler = handlers[name];
 222  
 223                  // TODO: Make this more robust by using lazy-binding:
 224                  // `handler = Y.bind(handler, this);`
 225                  if (typeof handler === 'string') {
 226                      handler = this[handler];
 227                  }
 228  
 229                  if (!handler) {
 230                      Y.log('Missing handler for ' + selector + ' ' + name + ' event.', 'warn', 'View');
 231                      continue;
 232                  }
 233  
 234                  this._attachedViewEvents.push(
 235                      container.delegate(name, handler, selector, this));
 236              }
 237          }
 238  
 239          return this;
 240      },
 241  
 242      /**
 243      Creates and returns a container node for this view.
 244  
 245      By default, the container is created from the HTML template specified in the
 246      `containerTemplate` property, and is _not_ added to the DOM automatically.
 247  
 248      You may override this method to customize how the container node is created
 249      (such as by rendering it from a custom template format). Your method must
 250      return a `Y.Node` instance.
 251  
 252      @method create
 253      @param {HTMLElement|Node|String} [container] Selector string, `Y.Node`
 254          instance, or DOM element to use at the container node.
 255      @return {Node} Node instance of the created container node.
 256      **/
 257      create: function (container) {
 258          return container ? Y.one(container) :
 259                  Y.Node.create(this.containerTemplate);
 260      },
 261  
 262      /**
 263      Detaches DOM events that have previously been attached to the container by
 264      `attachEvents()`.
 265  
 266      @method detachEvents
 267      @chainable
 268      @see attachEvents
 269      **/
 270      detachEvents: function () {
 271          Y.Array.each(this._attachedViewEvents, function (handle) {
 272              if (handle) {
 273                  handle.detach();
 274              }
 275          });
 276  
 277          this._attachedViewEvents = [];
 278          return this;
 279      },
 280  
 281      /**
 282      Removes this view's container element from the DOM (if it's in the DOM),
 283      but doesn't destroy it or any event listeners attached to it.
 284  
 285      @method remove
 286      @chainable
 287      **/
 288      remove: function () {
 289          var container = this.get('container');
 290          container && container.remove();
 291          return this;
 292      },
 293  
 294      /**
 295      Renders this view.
 296  
 297      This method is a noop by default. Override it to provide a custom
 298      implementation that renders this view's content and appends it to the
 299      container element. Ideally your `render` method should also return `this` as
 300      the end to allow chaining, but that's up to you.
 301  
 302      Since there's no default renderer, you're free to render your view however
 303      you see fit, whether that means manipulating the DOM directly, dumping
 304      strings into `innerHTML`, or using a template language of some kind.
 305  
 306      For basic templating needs, `Y.Node.create()` and `Y.Lang.sub()` may
 307      suffice, but there are no restrictions on what tools or techniques you can
 308      use to render your view. All you need to do is append something to the
 309      container element at some point, and optionally append the container
 310      to the DOM if it's not there already.
 311  
 312      @method render
 313      @chainable
 314      **/
 315      render: function () {
 316          return this;
 317      },
 318  
 319      // -- Protected Methods ----------------------------------------------------
 320  
 321      /**
 322      Removes the `container` from the DOM and purges all its event listeners.
 323  
 324      @method _destroyContainer
 325      @protected
 326      **/
 327      _destroyContainer: function () {
 328          var container = this.get('container');
 329          container && container.remove(true);
 330      },
 331  
 332      /**
 333      Getter for the `container` attribute.
 334  
 335      @method _getContainer
 336      @param {Node|null} value Current attribute value.
 337      @return {Node} Container node.
 338      @protected
 339      @since 3.5.0
 340      **/
 341      _getContainer: function (value) {
 342          // This wackiness is necessary to enable fully lazy creation of the
 343          // container node both when no container is specified and when one is
 344          // specified via a valueFn.
 345  
 346          if (!this._container) {
 347              if (value) {
 348                  // Attach events to the container when it's specified via a
 349                  // valueFn, which won't fire the containerChange event.
 350                  this._container = value;
 351                  this.attachEvents();
 352              } else {
 353                  // Create a default container and set that as the new attribute
 354                  // value. The `this._container` property prevents infinite
 355                  // recursion.
 356                  value = this._container = this.create();
 357                  this._set('container', value);
 358              }
 359          }
 360  
 361          return value;
 362      },
 363  
 364      // -- Protected Event Handlers ---------------------------------------------
 365  
 366      /**
 367      Handles `containerChange` events. Detaches event handlers from the old
 368      container (if any) and attaches them to the new container.
 369  
 370      Right now the `container` attr is initOnly so this event should only ever
 371      fire the first time the container is created, but in the future (once Y.App
 372      can handle it) we may allow runtime container changes.
 373  
 374      @method _afterContainerChange
 375      @protected
 376      @since 3.5.0
 377      **/
 378      _afterContainerChange: function () {
 379          this.attachEvents(this.events);
 380      }
 381  }, {
 382      NAME: 'view',
 383  
 384      ATTRS: {
 385          /**
 386          Container node into which this view's content will be rendered.
 387  
 388          The container node serves as the host for all DOM events attached by the
 389          view. Delegation is used to handle events on children of the container,
 390          allowing the container's contents to be re-rendered at any time without
 391          losing event subscriptions.
 392  
 393          The default container is a `<div>` Node, but you can override this in
 394          a subclass, or by passing in a custom `container` config value at
 395          instantiation time. If you override the default container in a subclass
 396          using `ATTRS`, you must use the `valueFn` property. The view's constructor
 397          will ignore any assignments using `value`.
 398  
 399          When `container` is overridden by a subclass or passed as a config
 400          option at instantiation time, you can provide it as a selector string, a
 401          DOM element, a `Y.Node` instance, or (if you are subclassing and modifying
 402          the attribute), a `valueFn` function that returns a `Y.Node` instance.
 403          The value will be converted into a `Y.Node` instance if it isn't one
 404          already.
 405  
 406          The container is not added to the page automatically. This allows you to
 407          have full control over how and when your view is actually rendered to
 408          the page.
 409  
 410          @attribute container
 411          @type HTMLElement|Node|String
 412          @default Y.Node.create(this.containerTemplate)
 413          @writeOnce
 414          **/
 415          container: {
 416              getter   : '_getContainer',
 417              setter   : Y.one,
 418              writeOnce: true
 419          }
 420      },
 421  
 422      /**
 423      Properties that shouldn't be turned into ad-hoc attributes when passed to
 424      View's constructor.
 425  
 426      @property _NON_ATTRS_CFG
 427      @type Array
 428      @static
 429      @protected
 430      @since 3.5.0
 431      **/
 432      _NON_ATTRS_CFG: [
 433          'containerTemplate',
 434          'events',
 435          'template'
 436      ]
 437  });
 438  
 439  
 440  
 441  }, '3.17.2', {"requires": ["base-build", "node-event-delegate"]});


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