view.js revision db664634abff07e378add55f2ef12fcd2f37f62d
a4544a5a0e622ef69e38641f87ab1b5685e05911Phill CunningtonYUI.add('view', function(Y) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterY.Base._buildCfg.custom._NON_ATTRS_CFG = function(prop, r, s) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (s._NON_ATTRS_CFG) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster r._NON_ATTRS_CFG = (r._NON_ATTRS_CFG || []).concat(s._NON_ATTRS_CFG);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/**
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRepresents a logical piece of an application's user interface, and provides a
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterlightweight, overridable API for rendering content and handling delegated DOM
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterevents on a container element.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster@submodule view
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster@since 3.4.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster**/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster/**
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterRepresents a logical piece of an application's user interface, and provides a
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterlightweight, overridable API for rendering content and handling delegated DOM
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterevents on a container element.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterThe View class imposes little structure and provides only minimal functionality
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterof its own: it's basically just an overridable API interface that helps you
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterimplement custom views.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
1c3134bddb7b413373d1668cbc4b7d95c2477667Mark de ReeperAs of YUI 3.5.0, View allows ad-hoc attributes to be specified at instantiation
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fostertime, so you don't need to subclass `Y.View` to add custom attributes. Just pass
8af80418ba1ec431c8027fa9668e5678658d3611Allan Fosterthem to the constructor:
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster var view = new Y.View({foo: 'bar'});
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell view.get('foo'); // => "bar"
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell@class View
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell@constructor
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell@extends Base
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell@since 3.4.0
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell**/
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnellfunction View() {
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell View.superclass.constructor.apply(this, arguments);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan FosterY.View = Y.extend(View, Y.Base, {
c184142912cff04e5442d8bf70febe477285fb1cCraig McDonnell // -- Public Properties ----------------------------------------------------
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Template for this view's container.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @property containerTemplate
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @type String
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @default "<div/>"
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @since 3.5.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford containerTemplate: '<div/>',
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Hash of CSS selectors mapped to events to delegate to elements matching
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster those selectors.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster CSS selectors are relative to the `container` element. Events are attached
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster to the container, and delegation is used so that subscribers are only
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster notified of events that occur on elements inside the container that match
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott the specified selectors. This allows the container's contents to be re-
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott rendered as needed without losing event subscriptions.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Event handlers can be specified either as functions or as strings that map
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster to function names on this view instance or its prototype.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster The `this` object in event handlers will refer to this view instance. If
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford you'd prefer `this` to be something else, use `Y.bind()` to bind a custom
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `this` object.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @example
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster var view = new Y.View({
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster events: {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Call `this.toggle()` whenever the element with the id
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott // "toggle-button" is clicked.
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott '#toggle-button': {click: 'toggle'},
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Call `this.hoverOn()` when the mouse moves over any element
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // with the "hoverable" class, and `this.hoverOff()` when the
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott // mouse moves out of any element with the "hoverable" class.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster '.hoverable': {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster mouseover: 'hoverOn',
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster mouseout : 'hoverOff'
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott }
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster });
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @property events
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @type Object
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @default {}
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford events: {},
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Template for this view's contents.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster This is a convenience property that has no default behavior of its own.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster It's only provided as a convention to allow you to store whatever you
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster consider to be a template, whether that's an HTML string, a `Y.Node`
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster instance, a Mustache template, or anything else your little heart
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster desires.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster How this template gets used is entirely up to you and your custom
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `render()` method.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @property template
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @type mixed
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @default ''
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster template: '',
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // -- Protected Properties -------------------------------------------------
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster This tells `Y.Base` that it should create ad-hoc attributes for config
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott properties passed to View's constructor. This makes it possible to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster instantiate a view and set a bunch of attributes without having to subclass
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott `Y.View` and declare all those attributes first.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @property _allowAdHocAttrs
1c3134bddb7b413373d1668cbc4b7d95c2477667Mark de Reeper @type Boolean
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @default true
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @protected
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @since 3.5.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _allowAdHocAttrs: true,
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott // -- Lifecycle Methods ----------------------------------------------------
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster initializer: function (config) {
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott config || (config = {});
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Set instance properties specified in the config.
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott config.containerTemplate &&
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott (this.containerTemplate = config.containerTemplate);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster config.template && (this.template = config.template);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Merge events from the config into events in `this.events`.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.events = config.events ? Y.merge(this.events, config.events) :
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford this.events;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // When the container node changes (or when it's set for the first
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // time), we'll attach events to it, but not until then. This allows the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // container to be created lazily the first time it's accessed rather
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // than always on init.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.after('containerChange', this._afterContainerChange);
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott Destroys this View, detaching any DOM events and optionally also destroying
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster its container node.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster By default, the container node will not be destroyed. Pass an _options_
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster object with a truthy `remove` property to destroy the container as well.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method destroy
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @param {Object} [options] Options.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @param {Boolean} [options.remove=false] If `true`, this View's container
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster will be removed from the DOM and destroyed as well.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @chainable
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford */
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster destroy: function (options) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // We also accept `delete` as a synonym for `remove`.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (options && (options.remove || options['delete'])) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Attaching an event handler here because the `destroy` event is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // preventable. If we destroyed the container before calling the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // superclass's `destroy()` method and the event was prevented, the
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott // class would end up in a broken state.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.onceAfter('destroy', function () {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this._destroyContainer();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster });
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return View.superclass.destroy.call(this);
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster destructor: function () {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.detachEvents();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster delete this._container;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // -- Public Methods -------------------------------------------------------
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Attaches delegated event handlers to this view's container element. This
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster method is called internally to subscribe to events configured in the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `events` attribute when the view is initialized.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster You may override this method to customize the event attaching logic.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @method attachEvents
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @param {Object} [events] Hash of events to attach. See the docs for the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `events` attribute for details on the format. If not specified, this
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster view's `events` property will be used.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @chainable
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @see detachEvents
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster attachEvents: function (events) {
4dc32d1e92477080fa1652a865cadc3f63ae04edBrian Bailey var container = this.get('container'),
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott owns = Y.Object.owns,
3e9693aa1fe0454cabcfcf9020cf1db11258946eBrian Bailey handler, handlers, name, selector;
4dc32d1e92477080fa1652a865cadc3f63ae04edBrian Bailey
3e9693aa1fe0454cabcfcf9020cf1db11258946eBrian Bailey this.detachEvents();
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster events || (events = this.events);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster for (selector in events) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!owns(events, selector)) { continue; }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster handlers = events[selector];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford for (name in handlers) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (!owns(handlers, name)) { continue; }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster handler = handlers[name];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (typeof handler === 'string') {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster handler = this[handler];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this._attachedViewEvents.push(
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott container.delegate(name, handler, selector, this));
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return this;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Creates and returns a container node for this view.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster By default, the container is created from the HTML template specified in the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `containerTemplate` property, and is _not_ added to the DOM automatically.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster You may override this method to customize how the container node is created
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford (such as by rendering it from a custom template format). Your method must
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return a `Y.Node` instance.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method create
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @param {HTMLElement|Node|String} [container] Selector string, `Y.Node`
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster instance, or DOM element to use at the container node.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @return {Node} Node instance of the created container node.
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster create: function (container) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return container ? Y.one(container) :
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott Y.Node.create(this.containerTemplate);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Detaches DOM events that have previously been attached to the container by
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `attachEvents()`.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method detachEvents
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @chainable
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @see attachEvents
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster detachEvents: function () {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Y.Array.each(this._attachedViewEvents, function (handle) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster handle.detach();
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford });
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford this._attachedViewEvents = [];
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return this;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott Removes this view's container element from the DOM (if it's in the DOM),
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster but doesn't destroy it or any event listeners attached to it.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method remove
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @chainable
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster remove: function () {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster var container = this.get('container');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster container && container.remove();
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford return this;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Renders this view.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster This method is a noop by default. Override it to provide a custom
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster implementation that renders this view's content and appends it to the
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott container element. Ideally your `render` method should also return `this` as
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster the end to allow chaining, but that's up to you.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Since there's no default renderer, you're free to render your view however
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster you see fit, whether that means manipulating the DOM directly, dumping
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster strings into `innerHTML`, or using a template language of some kind.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster For basic templating needs, `Y.Node.create()` and `Y.Lang.sub()` may
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster suffice, but there are no restrictions on what tools or techniques you can
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford use to render your view. All you need to do is append something to the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster container element at some point, and optionally append the container
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster to the DOM if it's not there already.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method render
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @chainable
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster render: function () {
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott return this;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // -- Protected Methods ----------------------------------------------------
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Removes the `container` from the DOM and purges all its event listeners.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method _destroyContainer
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @protected
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _destroyContainer: function () {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster var container = this.get('container');
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster container && container.remove(true);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott Getter for the `container` attribute.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method _getContainer
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @param {Node|null} value Current attribute value.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @return {Node} Container node.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @protected
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @since 3.5.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _getContainer: function (value) {
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford // This wackiness is necessary to enable fully lazy creation of the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // container node both when no container is specified and when one is
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // specified via a valueFn.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott if (!this._container) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster if (value) {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Attach events to the container when it's specified via a
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // valueFn, which won't fire the containerChange event.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this._container = value;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster this.attachEvents();
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott } else {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // Create a default container and set that as the new attribute
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // value. The `this._container` property prevents infinite
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // recursion.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster value = this._container = this.create();
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford this._set('container', value);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster return value;
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster // -- Protected Event Handlers ---------------------------------------------
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Handles `containerChange` events. Detaches event handlers from the old
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster container (if any) and attaches them to the new container.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Right now the `container` attr is initOnly so this event should only ever
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott fire the first time the container is created, but in the future (once Y.App
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster can handle it) we may allow runtime container changes.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @method _afterContainerChange
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @protected
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @since 3.5.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _afterContainerChange: function () {
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott this.attachEvents(this.events);
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}, {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster NAME: 'view',
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ATTRS: {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Container node into which this view's content will be rendered.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster The container node serves as the host for all DOM events attached by the
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster view. Delegation is used to handle events on children of the container,
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott allowing the container's contents to be re-rendered at any time without
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster losing event subscriptions.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford The default container is a `<div>` Node, but you can override this in
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster a subclass, or by passing in a custom `container` config value at
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster instantiation time.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster When `container` is overridden by a subclass or passed as a config
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster option at instantiation time, it may be provided as a selector string, a
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster DOM element, or a `Y.Node` instance. The value will be converted into a
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster `Y.Node` instance if it isn't one already.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster The container is not added to the page automatically. This allows you to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster have full control over how and when your view is actually rendered to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster the page.
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @attribute container
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @type HTMLElement|Node|String
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @default Y.Node.create(this.containerTemplate)
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @writeOnce
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster container: {
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster getter : '_getContainer',
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster setter : Y.one,
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster writeOnce: true
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster }
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott },
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford /**
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster Properties that shouldn't be turned into ad-hoc attributes when passed to
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster View's constructor.
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @property _NON_ATTRS_CFG
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @type Array
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @static
0c893a059f84246bf91e2f0fbf63e4c92f8e5165Tony Bamford @protected
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster @since 3.5.0
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster **/
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster _NON_ATTRS_CFG: [
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster 'containerTemplate',
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster 'events',
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott 'template'
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster ]
35ab1c5bca11317474fe12bdd8d22c17cdaf2697Robert Wapshott});
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster}, '@VERSION@' ,{requires:['base-build', 'node-event-delegate']});
8af80418ba1ec431c8027fa9668e5678658d3611Allan Foster