UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

212 lines (211 loc) 7.87 kB
/*! * CanJS - 2.3.34 * http://canjs.com/ * Copyright (c) 2018 Bitovi * Mon, 30 Apr 2018 20:56:51 GMT * Licensed MIT */ /*can@2.3.34#control/control*/ define([ 'can/util/library', 'can/construct' ], function (can) { var bind = function (el, ev, callback) { can.bind.call(el, ev, callback); return function () { can.unbind.call(el, ev, callback); }; }, isFunction = can.isFunction, extend = can.extend, each = can.each, slice = [].slice, paramReplacer = /\{([^\}]+)\}/g, special = can.getObject('$.event.special', [can]) || {}, delegate = function (el, selector, ev, callback) { can.delegate.call(el, selector, ev, callback); return function () { can.undelegate.call(el, selector, ev, callback); }; }, binder = function (el, ev, callback, selector) { return selector ? delegate(el, can.trim(selector), ev, callback) : bind(el, ev, callback); }, basicProcessor; var Control = can.Control = can.Construct({ setup: function () { can.Construct.setup.apply(this, arguments); if (can.Control) { var control = this, funcName; control.actions = {}; for (funcName in control.prototype) { if (control._isAction(funcName)) { control.actions[funcName] = control._action(funcName); } } } }, _shifter: function (context, name) { var method = typeof name === 'string' ? context[name] : name; if (!isFunction(method)) { method = context[method]; } return function () { context.called = name; return method.apply(context, [this.nodeName ? can.$(this) : this].concat(slice.call(arguments, 0))); }; }, _isAction: function (methodName) { var val = this.prototype[methodName], type = typeof val; return methodName !== 'constructor' && (type === 'function' || type === 'string' && isFunction(this.prototype[val])) && !!(special[methodName] || processors[methodName] || /[^\w]/.test(methodName)); }, _action: function (methodName, options) { paramReplacer.lastIndex = 0; if (options || !paramReplacer.test(methodName)) { var convertedName = options ? can.sub(methodName, this._lookup(options)) : methodName; if (!convertedName) { can.dev.log('can/control/control.js: No property found for handling ' + methodName); return null; } var arr = can.isArray(convertedName), name = arr ? convertedName[1] : convertedName, parts = name.split(/\s+/g), event = parts.pop(); return { processor: processors[event] || basicProcessor, parts: [ name, parts.join(' '), event ], delegate: arr ? convertedName[0] : undefined }; } }, _lookup: function (options) { return [ options, window ]; }, processors: {}, defaults: {} }, { setup: function (element, options) { var cls = this.constructor, pluginname = cls.pluginName || cls._fullName, arr; this.element = can.$(element); if (pluginname && pluginname !== 'can_control') { this.element.addClass(pluginname); } arr = can.data(this.element, 'controls'); if (!arr) { arr = []; can.data(this.element, 'controls', arr); } arr.push(this); this.options = extend({}, cls.defaults, options); this.on(); return [ this.element, this.options ]; }, on: function (el, selector, eventName, func) { if (!el) { this.off(); var cls = this.constructor, bindings = this._bindings, actions = cls.actions, element = this.element, destroyCB = can.Control._shifter(this, 'destroy'), funcName, ready; for (funcName in actions) { if (actions.hasOwnProperty(funcName)) { ready = actions[funcName] || cls._action(funcName, this.options, this); if (ready) { bindings.control[funcName] = ready.processor(ready.delegate || element, ready.parts[2], ready.parts[1], funcName, this); } } } can.bind.call(element, 'removed', destroyCB); bindings.user.push(function (el) { can.unbind.call(el, 'removed', destroyCB); }); return bindings.user.length; } if (typeof el === 'string') { func = eventName; eventName = selector; selector = el; el = this.element; } if (func === undefined) { func = eventName; eventName = selector; selector = null; } if (typeof func === 'string') { func = can.Control._shifter(this, func); } this._bindings.user.push(binder(el, eventName, func, selector)); return this._bindings.user.length; }, off: function () { var el = this.element[0], bindings = this._bindings; if (bindings) { each(bindings.user || [], function (value) { value(el); }); each(bindings.control || {}, function (value) { value(el); }); } this._bindings = { user: [], control: {} }; }, destroy: function () { if (this.element === null) { can.dev.warn('can/control/control.js: Control already destroyed'); return; } var Class = this.constructor, pluginName = Class.pluginName || Class._fullName, controls; this.off(); if (pluginName && pluginName !== 'can_control') { this.element.removeClass(pluginName); } controls = can.data(this.element, 'controls'); controls.splice(can.inArray(this, controls), 1); can.trigger(this, 'destroyed'); this.element = null; } }); var processors = can.Control.processors; basicProcessor = function (el, event, selector, methodName, control) { return binder(el, event, can.Control._shifter(control, methodName), selector); }; each([ 'change', 'click', 'contextmenu', 'dblclick', 'keydown', 'keyup', 'keypress', 'mousedown', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'reset', 'resize', 'scroll', 'select', 'submit', 'focusin', 'focusout', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchcancel', 'touchend', 'touchleave', 'inserted', 'removed', 'dragstart', 'dragenter', 'dragover', 'dragleave', 'drag', 'drop', 'dragend' ], function (v) { processors[v] = basicProcessor; }); return Control; });