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