@module {constructor} can-control can-control
@parent can-dom-utilities
@collection can-legacy
@download can-route
@test can/route/test.html
@test can/control/test.html
@inherits can-construct
@description widget factory with declarative event binding.
@group can-control.static static
@group can-control.prototype prototype
@link ../docco/control/control.html docco
@package ../package.json

@description Create organized, memory-leak free, rapidly performing,
stateful controls with declarative event binding. Use `Control` to create UI
controls like tabs, grids, and context menus,
and organize them into higher-order business rules with
[can.route]. It can serve as both a traditional view and a traditional controller.

@signature `Control( [staticProperties,] instanceProperties )`

Create a new, extended, control constructor
function. This functionality is inherited from [can-construct] and is deprecated in favor of using
[can-control.extend].

@param {Object} [staticProperties] An object of properties and methods that are added the control constructor
function directly. The most common property to add is [can-control.defaults].

@param {Object} instanceProperties An object of properties and methods that belong to
instances of the `Control` constructor function. These properties are added to the
control's `prototype` object. Properties that
look like event handlers (ex: `"{element} click"` or `"{element} li mouseenter"`) are setup
as event handlers (see [Listening to events](#section_Listeningtoevents)).

@return {function(new:can.Construct,element,options)} A control constructor function that has been
extended with the provided `staticProperties` and `instanceProperties`.


@signature `new Control( element, options )`

Create an instance of a control. [can.Control.prototype.setup] processes
the arguments and sets up event binding. Write your initialization
code in `can.Control.prototype.init`. Note, you never call `new Control()` directly,
instead, you call it on constructor functions extended from `Control`.

@param {HTMLElement|can-view-nodelist|CSSSelectorString} element Specifies the element the control will be created on.

@param {Object|can-map|can-define/map/map} [options] Option values merged with [can-control.defaults Control.defaults]
and set as [can-control::options this.options]. If options is an observable ([can-map CanMap] / [can-define/map/map DefineMap]), any values from [can-control.defaults defaults] that do not exist on the observable will be set. The observable will then be set as [can-control::options this.options].


@return {can-control} A new instance of the constructor function extending Control.

@body

## The Control Lifecycle

The following walks through a control's lifecycle
with an example todo list widget.  It's broken up into the following
lifecycle events:

 - Extending a control
 - Creating a control instance
 - Listening to events
 - Destroying a control

## Extending a control

The following example builds up a basic todos widget for listing
and completing todo items. Start by creating a control constructor
function of your own by extending [can-control] and defining an instance init method.

    var Todos = Control.extend({
      init: function( element, options ) { ... }
    });

## Creating a control instance

Create an instance of the Todos control on the `todos` element with:

    var todosControl = new Todos( '#todos', {} );

The control's associated [can.ejs EJS] template looks like:

    <% todos.each(function( todo ) { %>
      <li <%= (el) -> el.data( 'todo', todo ) %> >
        <%= todo.attr( 'name' ) %>
        <a href="javascript://" class="destroy">
      </li>
    <% }) %>

### `init(element, options)`

[can-control.prototype.init] is called with the below arguments when new instances of [can-control] are created:

- __element__ - The wrapped element passed to the
                control. Control accepts a
                raw HTMLElement, a CSS selector, or a NodeList. This is
                set as `this.element` on the control instance.
- __options__ - The second argument passed to new Control, extended with
                the can.Control's static __defaults__. This is set as
                `this.options` on the control instance. Note that static is used
                formally to indicate that _default values are shared across control instances_.

Any additional arguments provided to the constructor will be passed as normal. Use [can.view] to produce a document fragment
from your template and inject it in the passed element. Note that the `todos` parameter passed to [can.view] below
is an instance of [can-list]:

    var Todos = Control.extend({

      //defaults are merged into the options arg provided to the constructor
      defaults : { view: 'todos.ejs' }

    }, {
      init: function( element , options ) {

        //create a pointer to the control's scope
        var self = this;

        //run the Todo model's .findAll() method to produce a can.List
        Todo.findAll( {}, function( todos ) {

            //create a document fragment with can.view
            //and inject it into the provided element's body
    		self.element.html( can.view(self.options.view, todos) );
        });
      }
    });

    // create a Todos Control with default options
    new Todos( document.body.firstElementChild );

    // overwrite the template default
    new Todos( '#todos', { view: 'specialTodos.ejs' } );

### `this.element`

[can-control::element] is the
NodeList consisting of the element the control is created on.

    var todosControl = new Todos( document.body.firstElementChild );
    todosControl.element[0] //-> document.body.firstElementChild

Each library wraps elements differently. If you are using jQuery, for example,
the element is wrapped with `jQuery( element )`.

### `this.options`

[can-control::options] is the second argument passed to
`new Control()`, merged with the control's static __defaults__ property.

## Listening to events

Control automatically binds prototype methods that look
like event handlers. Listen to __click__'s on `<li>` elements within [can-control::element this.element] like:

    var Todos = Control.extend({
      init: function( element , options ) {...},

      '{element} li click': function( li, event ) {
        console.log( 'You clicked', li.text() );

        // let other controls know what happened
        li.trigger( 'selected' );
      }
    });

When an `<li>` is clicked, `"{element} li click"` is called with:

- The library-wrapped __element__ that was clicked
- The __event__ data

Control uses event delegation, so you can add `<li>`s without needing to rebind
event handlers.

To destroy a todo when its `<a href="javascript://" class="destroy">` link
is clicked:

    var Todos = can.Control.extend({
      init: function( element, options ) {...},

      '{element} li click': function( li ) {...},

      '{element} li .destroy click': function( el, ev ) {
        // get the li element that has todo data
        var li = el.closest( 'li' );

        // get the model
        var todo = li.data( 'todo' );

        //destroy it
        todo.destroy();
      }
    });

When the todo is destroyed, EJS's live binding will remove its LI automatically.

### Templated Event Handlers Part 1 `"{eventName}"`

Customize event handler behavior with `"{NAME}"` in
the event handler name.  The following allows customization
of the event that destroys a todo:

    var Todos = Control.extend({
      init: function( element , options ) { ... },

      '{element} li click': function( li ) { ... },

      '{element} li .destroy {destroyEvent}': function( el, ev ) {
        // previous destroy code here
      }
    });

    // create Todos with this.options.destroyEvent
    new Todos( '#todos', { destroyEvent: 'mouseenter' } );

Values inside `{NAME}` are looked up on the control's `this.options` first,
and then the `window`. For example, we could customize it instead like:

    var Todos = Control.extend({
      init: function( element , options ) { ... },

      '{element} li click': function( li ) { ... },

      '{element} li .destroy {Events.destroy}': function( el, ev ) {
        // previous destroy code here
      }
    });

    // Events config
    Events = { destroy: 'click' };

    // Events.destroy is looked up on the window.
    new Todos( '#todos' );

The selector can also be templated.

    var Todos = Control.extend({
      init: function( element , options ) { ... },

      '{element} {listElement} click': function( li ) { ... },

      '{element} {listElement} .destroy {destroyEvent}': function( el, ev ) {
        // previous destroy code here
      }
    });

    // create Todos with this.options.destroyEvent
    new Todos( '#todos',  {
      destroyEvent: 'mouseenter',
      listElement: 'li'
    } );

### Templated Event Handlers Part 2 `"{objectName}"`

Control can also bind to objects other than `this.element` with
templated event handlers.  This is _critical_
for avoiding memory leaks that are so common among MVC applications.

If the value inside `{NAME}` is an object, Control will bind to that
object to listen for events. For example, the following tooltip listens to
clicks on the window:

    var Tooltip = Control.extend({
      '{window} click': function( el, ev ) {
        // hide only if we clicked outside the tooltip
        if ( !this.element.has( ev.target ) ) {
          this.element.remove();
        }
      }
    });

    // create a Tooltip
    new Tooltip( $( '<div>INFO</div>' ).appendTo( el ) );

This is convenient when listening for model changes. If EJS were not
taking care of removing `<li>`s after their associated models were destroyed,
we could implement it in `Todos` like:

    var Todos = Control.extend({
      init: function( element, options ) {...},

      '{element} li click': function( li ) {...},

      '{element} li .destroy click': function( el, ev ) {
        // get the li element that has todo data
        var li = el.closest( 'li' );

        // get the model
        var todo = li.data( 'todo' );

        //destroy it
        todo.destroy();
      },

      '{Todo} destroyed': function( Todo, ev, todoDestroyed ) {
        // find where the element
        var index = this.todosList.indexOf( todoDestroyed );
        this.element.children( ':nth-child(' + ( index + 1 ) + ')' )
                    .remove();
      }
    });

    new Todos( '#todos' );

### `on()`

[can-control::on] rebinds a control's event handlers. This is useful when you want
to listen to a specific model and change it:

    var Editor = Control.extend({
      todo: function( todo ) {
        this.options.todo = todo;
        this.on();
        this.setName();
      },

      // a helper that sets the value of the input
      // to the todo's name
      setName: function() {
        this.element.val( this.options.todo.name );
      },

      // listen for changes in the todo
      // and update the input
      '{todo} updated': function() {
        this.setName();
      },

      // when the input changes
      // update the todo instance
      '{element} change': function() {
        var todo = this.options.todo;
        todo.attr( 'name', this.element.val() );
        todo.save();
      }
    });

    var todo1 = new Todo({ id: 6, name: 'trash' }),
        todo2 = new Todo({ id: 6, name: 'dishes' });

    // create the editor;
    var editor = new Editor( '#editor' );

    // show the first todo
    editor.todo( todo1 );

    // switch it to the second todo
    editor.todo( todo2 );


## Destroying a control

[can-control::destroy] unbinds a control's
event handlers and releases its element, but does not remove
the element from the page.

    var todo = new Todos( '#todos' );
    todo.destroy();

When a control's element is removed from the page
__destroy__ is called automatically.

    new Todos( '#todos' );
    $( '#todos' ).remove();

All event handlers bound with Control are unbound when the control
is destroyed (or its element is removed).

_Brief aside on destroy and templated event binding. Taken
together, templated event binding, and control's automatic
clean-up make it almost impossible
to write leaking applications. An application that uses
only templated event handlers on controls within the body
could free up all
data by calling `$(document.body).empty()`._

## Tabs Example

Here is an example of how to build a simple tab widget using Control:

<p data-height="265" data-theme-id="0" data-slug-hash="eLExWm" data-default-tab="result" data-user="danieltian" data-pen-title="CanJS 5.0 Hello World" class="codepen">See the Pen <a href="https://codepen.io/danieltian/pen/eLExWm/">CanJS 5.0 Hello World</a> by Daniel Tian (<a href="https://codepen.io/danieltian">@danieltian</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
