src/cm/media/js/lib/yui/yui_3.10.3/build/view/view-debug.js
changeset 525 89ef5ed3c48b
equal deleted inserted replaced
524:322d0feea350 525:89ef5ed3c48b
       
     1 /*
       
     2 YUI 3.10.3 (build 2fb5187)
       
     3 Copyright 2013 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.10.3', {"requires": ["base-build", "node-event-delegate"]});