extended-spine
Advanced tools
// Generated by CoffeeScript 1.6.3 | ||
(function() { | ||
var $, Controller, Spine, hasAttr, isMobile, num, | ||
var $, Controller, DI, Spine, hasAttr, isMobile, num, | ||
__hasProp = {}.hasOwnProperty, | ||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; | ||
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, | ||
__slice = [].slice; | ||
@@ -11,2 +12,4 @@ Spine = require('spine'); | ||
DI = require('dependency-injection'); | ||
$ = null; | ||
@@ -25,4 +28,28 @@ | ||
Controller.DATA_APPLICATION_SCOPE_NAME = 'data-application'; | ||
Controller.DATA_CONTROLLER_NAME = 'data-controller'; | ||
Controller.DATA_CONTROLLER_FULL_NAME = 'data-controller-path'; | ||
Controller.DATA_LAZY_CONTROLLER_NAME = 'data-lazy'; | ||
Controller.DATA_COMPUTER_NAME = 'data-computer'; | ||
Controller.DATA_MOBILE_NAME = 'data-mobile'; | ||
Controller.DATA_INSTANCE_NAME = '__spine_controller__'; | ||
Controller.AUTO_ID_PREFIX = '_spine_controller'; | ||
Controller.di = null; | ||
Controller.controllers = { | ||
__unknown__: [] | ||
}; | ||
Controller.prototype.id = null; | ||
Controller.prototype.fullName = null; | ||
function Controller(el) { | ||
@@ -36,23 +63,30 @@ if (el == null) { | ||
Controller.__super__.constructor.call(this, this, []); | ||
if (this.el && hasAttr(this.el, Controller.DATA_CONTROLLER_FULL_NAME)) { | ||
this.fullName = this.el.attr(Controller.DATA_CONTROLLER_FULL_NAME); | ||
} else { | ||
Controller.controllers.__unknown__.push(this); | ||
} | ||
this.id = this.el.attr('id'); | ||
this.el.data('controller', this); | ||
this.el.data(Controller.DATA_INSTANCE_NAME, this); | ||
} | ||
Controller.init = function(jQuery, scope) { | ||
var that; | ||
if (scope == null) { | ||
scope = '[data-application]:first'; | ||
Controller.init = function() { | ||
var args, defaultDi, defaultScope, di, jQuery, scope, _ref; | ||
jQuery = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; | ||
$ = jQuery; | ||
defaultScope = "[" + Controller.DATA_APPLICATION_SCOPE_NAME + "]:first"; | ||
defaultDi = null; | ||
if (args[0] instanceof DI) { | ||
di = args[0]; | ||
scope = defaultScope; | ||
} else if ((_ref = typeof args[0]) === 'string' || _ref === 'boolean') { | ||
di = typeof args[1] === 'undefined' ? defaultDi : args[1]; | ||
scope = args[0]; | ||
} | ||
$ = jQuery; | ||
that = this; | ||
if (di !== null && !(di instanceof DI)) { | ||
throw new Error('di container must be an instance of dependency-injection class.'); | ||
} | ||
Controller.di = di; | ||
$.fn.getController = function() { | ||
var controller, | ||
_this = this; | ||
controller = $(this).data('controller'); | ||
if (!controller || typeof controller === 'string' && hasAttr($(this), 'data-controller') && hasAttr($(this), 'data-lazy')) { | ||
return function() { | ||
return that.createController($(_this).attr('data-controller'), $(_this)); | ||
}; | ||
} | ||
return controller; | ||
return Controller.find($(this)); | ||
}; | ||
@@ -64,2 +98,25 @@ if (scope !== false) { | ||
Controller.release = function() { | ||
var c, controller, i, name, _i, _j, _len, _len1, _ref; | ||
_ref = Controller.controllers; | ||
for (controller = _i = 0, _len = _ref.length; _i < _len; controller = ++_i) { | ||
name = _ref[controller]; | ||
if (name === '__unknown__') { | ||
for (i = _j = 0, _len1 = controller.length; _j < _len1; i = ++_j) { | ||
c = controller[i]; | ||
c._unbind(); | ||
} | ||
} else { | ||
controller._unbind(); | ||
} | ||
} | ||
Controller.controllers = { | ||
__unknown__: [] | ||
}; | ||
delete $.fn.getController; | ||
$ = null; | ||
num = 0; | ||
return Controller.di = null; | ||
}; | ||
Controller.prototype.getAllEvents = function() { | ||
@@ -105,5 +162,11 @@ var context, event, events, match, method, parent_prototype, result, selector; | ||
Controller.prototype._unbind = function() { | ||
this.unbind(); | ||
this.stopListening(); | ||
this.unbindUiEvents(); | ||
return this.el.data(Controller.DATA_INSTANCE_NAME, null); | ||
}; | ||
Controller.findElementsWithController = function(scope, self) { | ||
var result, | ||
_this = this; | ||
var result; | ||
if (scope == null) { | ||
@@ -117,8 +180,7 @@ scope = 'html'; | ||
result = []; | ||
if (self && hasAttr(scope, 'data-controller')) { | ||
if (self && hasAttr(scope, Controller.DATA_CONTROLLER_NAME)) { | ||
result.push(scope); | ||
} | ||
scope.find('*[data-controller]:not([data-lazy])').each(function(i, el) { | ||
el = $(el); | ||
return result.push(el); | ||
scope.find("*[" + Controller.DATA_CONTROLLER_NAME + "]:not([" + Controller.DATA_LAZY_CONTROLLER_NAME + "])").each(function(i, el) { | ||
return result.push($(el)); | ||
}); | ||
@@ -128,4 +190,23 @@ return result; | ||
Controller.findElementsWithLazyController = function(scope, self) { | ||
var result; | ||
if (scope == null) { | ||
scope = 'html'; | ||
} | ||
if (self == null) { | ||
self = true; | ||
} | ||
scope = $(scope); | ||
result = []; | ||
if (self && hasAttr(scope, Controller.DATA_LAZY_CONTROLLER_NAME)) { | ||
result.push(scope); | ||
} | ||
scope.find("*[" + Controller.DATA_CONTROLLER_NAME + "][" + Controller.DATA_LAZY_CONTROLLER_NAME + "]").each(function(i, el) { | ||
return result.push($(el)); | ||
}); | ||
return result; | ||
}; | ||
Controller.refresh = function(scope, self) { | ||
var el, _i, _len, _ref, _results; | ||
var el, _i, _j, _len, _len1, _ref, _ref1, _results; | ||
if (scope == null) { | ||
@@ -137,8 +218,13 @@ scope = 'html'; | ||
} | ||
_ref = this.findElementsWithController(scope, self); | ||
_results = []; | ||
_ref = Controller.findElementsWithController(scope, self); | ||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | ||
el = _ref[_i]; | ||
_results.push(this.register(el.attr('data-controller'), el)); | ||
Controller.createController(el.attr(Controller.DATA_CONTROLLER_NAME), el); | ||
} | ||
_ref1 = Controller.findElementsWithLazyController(scope, self); | ||
_results = []; | ||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { | ||
el = _ref1[_j]; | ||
_results.push(el.data(Controller.DATA_CONTROLLER_FULL_NAME, require.resolve(el.attr(Controller.DATA_COMPUTER_NAME)))); | ||
} | ||
return _results; | ||
@@ -155,11 +241,8 @@ }; | ||
} | ||
_ref = this.findElementsWithController(scope, self); | ||
_ref = Controller.findElementsWithController(scope, self); | ||
_results = []; | ||
for (_i = 0, _len = _ref.length; _i < _len; _i++) { | ||
el = _ref[_i]; | ||
controller = el.data('controller'); | ||
controller.unbind(); | ||
controller.stopListening(); | ||
controller.unbindUiEvents(); | ||
_results.push(el.data('controller', null)); | ||
controller = el.data(Controller.DATA_INSTANCE_NAME); | ||
_results.push(controller._unbind()); | ||
} | ||
@@ -170,11 +253,18 @@ return _results; | ||
Controller.register = function(path, el) { | ||
var computer, mobile; | ||
if (el == null) { | ||
el = null; | ||
} | ||
return Controller.createController(path, el); | ||
}; | ||
Controller.createController = function(name, el) { | ||
var c, computer, mobile; | ||
if (el == null) { | ||
el = null; | ||
} | ||
if (el !== null) { | ||
el = $(el); | ||
} | ||
computer = hasAttr(el, 'data-computer'); | ||
mobile = hasAttr(el, 'data-mobile'); | ||
computer = hasAttr(el, Controller.DATA_COMPUTER_NAME); | ||
mobile = hasAttr(el, Controller.DATA_MOBILE_NAME); | ||
if (el !== null && (computer || mobile)) { | ||
@@ -189,16 +279,69 @@ if (computer && isMobile()) { | ||
if (el !== null && el.length > 0 && !hasAttr(el, 'id')) { | ||
el.attr('id', '_controller' + num); | ||
el.attr('id', Controller.AUTO_ID_PREFIX + num); | ||
num++; | ||
} | ||
return this.createController(path, el); | ||
name = require.resolve(name); | ||
if (el !== null) { | ||
el.attr(Controller.DATA_CONTROLLER_FULL_NAME, name); | ||
} | ||
c = require(name); | ||
if (Controller.di === null) { | ||
c = new c(el); | ||
} else { | ||
c = Controller.di.createInstance(c, [el]); | ||
} | ||
if (typeof Controller.controllers[name] !== 'undefined') { | ||
if (Object.prototype.toString.call(Controller.controllers[name]) !== '[object Array]') { | ||
Controller.controllers[name] = [Controller.controllers[name]]; | ||
} | ||
Controller.controllers[name].push(c); | ||
} else { | ||
Controller.controllers[name] = c; | ||
} | ||
return c; | ||
}; | ||
Controller.createController = function(name, el) { | ||
return new (require(name))(el); | ||
Controller.find = function(nameOrElement) { | ||
var controller, el, fullName, name, result, | ||
_this = this; | ||
if (typeof nameOrElement === 'string') { | ||
name = nameOrElement; | ||
fullName = require.resolve(name); | ||
if (typeof Controller.controllers[fullName] === 'undefined') { | ||
el = $("[" + Controller.DATA_CONTROLLER_FULL_NAME + "=\"" + fullName + "\"][" + Controller.DATA_LAZY_CONTROLLER_NAME + "]"); | ||
if (el.length === 0) { | ||
el = $("[" + Controller.DATA_CONTROLLER_NAME + "=\"" + name + "\"][" + Controller.DATA_LAZY_CONTROLLER_NAME + "]"); | ||
if (el.length > 0) { | ||
el.attr(Controller.DATA_CONTROLLER_FULL_NAME, fullName); | ||
} | ||
} | ||
if (el.length === 0) { | ||
return null; | ||
} else if (el.length === 1) { | ||
return function() { | ||
return Controller.createController(fullName, el); | ||
}; | ||
} else { | ||
result = []; | ||
el.each(function(i, el) { | ||
return result.push(function() { | ||
return Controller.createController(fullName, el); | ||
}); | ||
}); | ||
return result; | ||
} | ||
} | ||
return Controller.controllers[fullName]; | ||
} else if (nameOrElement instanceof $) { | ||
el = nameOrElement; | ||
controller = el.data(Controller.DATA_INSTANCE_NAME); | ||
if (!controller && hasAttr(el, Controller.DATA_CONTROLLER_NAME) && hasAttr(el, Controller.DATA_LAZY_CONTROLLER_NAME)) { | ||
return function() { | ||
return Controller.createController(el.attr(Controller.DATA_CONTROLLER_NAME), el); | ||
}; | ||
} | ||
return controller; | ||
} | ||
}; | ||
Controller.find = function(controller) { | ||
return $('[data-controller="' + controller + '"]').getController(); | ||
}; | ||
return Controller; | ||
@@ -205,0 +348,0 @@ |
{ | ||
"name": "extended-spine", | ||
"description": "Some extensions for spine framework", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"author": { | ||
@@ -26,3 +26,4 @@ "name": "David Kudera", | ||
"spine": "1.2.2", | ||
"is-mobile": "0.2.2" | ||
"is-mobile": "0.2.2", | ||
"dependency-injection": "2.0.1" | ||
}, | ||
@@ -29,0 +30,0 @@ "devDependencies": { |
@@ -7,3 +7,3 @@ [](http://badge.fury.io/js/extended-spine) | ||
Extended [spine](https://npmjs.org/package/spine) framework. It gives you ability to instantiate controllers almost | ||
Extended [spine](https://npmjs.org/package/spine) framework. It gives you ability to work with controllers almost | ||
like in [Angular](http://angularjs.org/). | ||
@@ -66,2 +66,44 @@ | ||
## Using dependency-injection | ||
If you like [dependency injection](http://en.wikipedia.org/wiki/Dependency_injection) pattern with autowired dependencies | ||
(again for example like in angular), you can use this feature also with this module. | ||
Uses [dependency-injection](https://github.com/sakren/node-dependency-injection) module. | ||
``` | ||
DI = require 'dependency-injection' | ||
di = new DI | ||
Controller.init($, di) | ||
``` | ||
Some controller: | ||
``` | ||
Controller = require 'extended-spine/Controller' | ||
class Chat extends Controller | ||
http: null | ||
jquery: null | ||
model: null | ||
constructor: (@el, @http, @jquery, @model) -> | ||
module.exports = Chat | ||
``` | ||
Chat module is dependent on three services. First argument will always be the container element and others will be services | ||
from DI container. | ||
Check [documentation](https://github.com/sakren/node-dependency-injection/blob/master/README.md) of dependency-injection | ||
module to see how to add services into your DI container. | ||
This works only with controllers which were created with data-controller attribute. | ||
## Refreshing elements | ||
@@ -137,2 +179,9 @@ | ||
* 1.3.0 | ||
+ Refactoring | ||
+ Added dependency injection (package [extended-spine-di](https://github.com/sakren/node-extended-spine-di) will be removed) | ||
+ Added property fullName into controllers | ||
+ Updated dependencies | ||
+ Better find method | ||
* 1.2.0 | ||
@@ -139,0 +188,0 @@ + Tests modules does not need to be installed globally |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
243711
26.53%24
4.35%3432
32.77%208
30.82%0
-100%3
50%17
183.33%