(function(can, window, undefined){
//used to determine if a control instance is one of controllers
//controllers can be strings or classes
var i,
isAControllerOf = function( instance, controllers ) {
for ( i = 0; i < controllers.length; i++ ) {
if ( typeof controllers[i] == 'string' ? instance.constructor._shortName == controllers[i] : instance instanceof controllers[i] ) {
return true;
}
}
return false;
},
data = function(el, data){
return $el.data('controls');
},
makeArray = can.makeArray,
old = can.Control.setup;
/*
* static
*/
can.Control.setup = function() {
// if you didn't provide a name, or are control, don't do anything
if ( this !== can.Control ) {
/**
* @attribute can.Control.plugin.static.pluginName
* @parent can.Control.plugin
*
* Setting the static `pluginName` property allows you to override the default name
* with your own.
*
* var Filler = can.Control({
* pluginName: 'fillWith'
* },{});
*
* $("#foo").fillWith();
*
* If you don't provide a `pluginName`, the control falls back to the
* [can.Construct.fullName fullName] attribute:
*
* can.Control('Ui.Layout.FillWith', {}, {});
* $("#foo").ui_layout_fill_with();
*
*/
var pluginName = this.pluginName || this._fullName;
// create jQuery plugin
if(pluginName !== 'can_control'){
this.plugin(pluginName);
}
old.apply(this, arguments);
}
};
/*
* prototype
*/
$.fn.extend({
/**
* @function jQuery.fn.controls
* @parent can.Control.plugin
*
* When the widget is initialized, the plugin control creates an array
* of control instance(s) with the DOM element it was initialized on using
* [can.data] method.
*
* The `controls` method allows you to get the control instance(s) for any element.
*
* //- Inits the widgets
* $('.widgets:eq(0)').my_box();
* $('.widgets:eq(1)').my_clock();
*
*
*
*
* $('.widgets').controls() //-> [ MyBox, MyClock ]
*
* Additionally, you can invoke it passing the name of a control
* to fetch a specific instance(s).
*
* //- Inits the widgets
* $('.widgets:eq(0)').my_box();
* $('.widgets:eq(1)').my_clock();
*
*
*
*
* $('.widgets').controls('MyBox') //-> [ MyBox ]
*
* @param {Object} control (optional) if exists the control instance(s) with that constructor function or type will be returned.
* @return {Array} an array of control instance(s).
*/
controls: function() {
var controllerNames = makeArray(arguments),
instances = [],
controls, c, cname;
//check if arguments
this.each(function() {
controls = can.$(this).data("controls");
if(!controls){
return;
}
for(var i=0; i
*
* $('.widgets').controls() //-> MyBox
*
* @param {Object} control (optional) if exists the first control instance with that constructor function or type will be returned.
* @return {can.Control} the first control.
*/
control: function( control ) {
return this.controls.apply(this, arguments)[0];
}
});
can.Control.plugin = function(pluginname){
var control = this;
if (!$.fn[pluginname]) {
$.fn[pluginname] = function(options){
var args = makeArray(arguments), //if the arg is a method on this control
isMethod = typeof options == "string" && $.isFunction(control.prototype[options]), meth = args[0];
return this.each(function(){
//check if created
var plugin = can.$(this).control(control);
if (plugin) {
if (isMethod) {
// call a method on the control with the remaining args
plugin[meth].apply(plugin, args.slice(1));
}
else {
// call the plugin's update method
plugin.update.apply(plugin, args);
}
}
else {
//create a new control instance
control.newInstance.apply(control, [this].concat(args));
}
});
};
}
}
/**
* @function can.Control.prototype.update
* @parent can.Control.plugin
*
* Update extends [can.Control.prototype.options options]
* with the `options` argument and rebinds all events. It
* re-configures the control.
*
* For example, the following control wraps a recipe form. When the form
* is submitted, it creates the recipe on the server. When the recipe
* is `created`, it resets the form with a new instance.
*
* var Creator = can.Control({
* "{recipe} created" : function(){
* this.update({recipe : new Recipe()});
* this.element[0].reset();
* this.element.find("[type=submit]").val("Create Recipe")
* },
* "submit" : function(el, ev){
* ev.preventDefault();
* var recipe = this.options.recipe;
* recipe.attrs( this.element.formParams() );
* this.element.find("[type=submit]").val("Saving...")
* recipe.save();
* }
* });
*
* $('#createRecipes').creator({ recipe : new Recipe() })
*
* *Update* is called if a control's plugin helper is called with the plugin options on an element
* that already has a control instance of the same type. If you want to implement your
* own update method make sure to call the old one either using the [can.Construct.super super] plugin or
* by calling `can.Control.prototype.update.apply(this, arguments);`.
* For example, you can change the content of the control element every time the options change:
*
* var Plugin = can.Control({
* pluginName: 'myPlugin'
* }, {
* init : function(el, options) {
* this.updateCount = 0;
* this.update({
* text : 'Initialized'
* });
* },
* update : function(options) {
* // Call the can.Control update first.
* // Use this._super when using can/construct/super
* can.Control.prototype.update.call(this, options);
* this.element.html(this.options.text + ' ' +
* (++this.updateCount) + ' times');
* }
* });
*
* $('#control').myPlugin();
* $('#control').html();
* // Initialized. Updated 1 times
*
* $('#control').myPlugin({ text : 'Calling update. Updated' });
* $('#control').html();
* // Calling update. Updated 2 times
*
* @demo can/control/plugin/demo-update.html
*
* @param {Object} options A list of options to merge with
* [can.Control.prototype.options this.options]. Often this method
* is called by the [can.Control.plugin jQuery helper function].
*/
can.Control.prototype.update = function( options ) {
can.extend(this.options, options);
this.on();
};
})(this.can, this )