rails_jskit 5.0.2 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a15f3760d8c6e81a5ac1c0ffd2344c9201881cf3
4
- data.tar.gz: 38b50b8168b5e20d38023fb5686dde1c08727ffa
3
+ metadata.gz: 240307149b562d4e71edf1aefeafcb18dcffd2f9
4
+ data.tar.gz: 5db7168702b8598eed85b76d16cd4fe7d57cf781
5
5
  SHA512:
6
- metadata.gz: 3d926442464ed5aad88ec72dc60396491dddc28ba3410ea5394560c996b98bec35770a99a9c39ea671f7b3ed6d846feeb1175e2a9c6c7135d73ff78369ae93ee
7
- data.tar.gz: db51a062072c0768ec026976656c3e6ec30bc072442d375a59d3b1e1b9a576ad79092a007f7eae312d75fb6d71012508c9abf8d167826c982f7c7e79c873e4fe
6
+ metadata.gz: e2de89050713116fbaad34b612b5193b810944c758a6fb9b14664da23e251a029e5238e5a12709d2c5a005902aa43714be804eccbd215d81949a9400ebf361ff
7
+ data.tar.gz: 94f6f5ddf9910a6a8632bb10ae9fb93963cc6807b236258f64b62db454105ab4f04dc457d604d079a57a4cae3d520b0f8e6d6b672658f70fc99de2c91339f68e
data/README.md CHANGED
@@ -107,7 +107,7 @@ Documentation
107
107
 
108
108
  ### Application Object
109
109
 
110
- RailsJskit will automatically create a JSkit application object for you, using the configured `app_namespace` for the global variable name _(defaults to "App")_. This global namespace provides you a way to interact with your JSkit application. You can #{link_to "configure", "#configuration"} this setting in your initializer `(config/initializers/rails_jskit.rb)`.
110
+ RailsJskit will automatically create a JSkit application object for you, using the configured `app_namespace` for the global variable name _(defaults to "App")_. This global namespace provides you a way to interact with your JSkit application. You can [configure](#configuration) this setting in your initializer `(config/initializers/rails_jskit.rb)`.
111
111
 
112
112
  #### Dispatcher
113
113
 
@@ -472,7 +472,7 @@ Testing
472
472
 
473
473
  One of the main advantages of RailsJSkit is that it provides a simple structure that's easily tested. There are however, a few things you need to keep in mind while testing JSkit controllers.
474
474
 
475
- When testing, it's important to use the #{link_to "Controller Factories", "#controller-factories"} to create your test subjects. This ensures that you always have a fresh version of the controller that has not been mutated by previous tests. A basic jasmine/mocha style JSkit controller test looks something like this:
475
+ When testing, it's important to use the [Controller Factories](#controller-factories) to create your test subjects. This ensures that you always have a fresh version of the controller that has not been mutated by previous tests. A basic jasmine/mocha style JSkit controller test looks something like this:
476
476
 
477
477
  ```js
478
478
  // spec/javscripts/controllers/posts_controller_spec.js
@@ -6,7 +6,6 @@
6
6
  */
7
7
  var JSkit = (function() {
8
8
  if (!_) throw new Error("JSkit: lodash or underscore is required");
9
- if (!$) throw new Error("JSkit: jQuery or equivalent is required");
10
9
 
11
10
  return {
12
11
  /**
@@ -27,8 +26,8 @@ var JSkit = (function() {
27
26
  * @class Dispatcher
28
27
  */
29
28
  JSkit.Dispatcher = (function() {
30
- var contains = _.contains;
31
- var pluck = _.pluck;
29
+ var any = _.any;
30
+ var each = _.each;
32
31
 
33
32
  /**
34
33
  Get all handler functions for a given dispatcher and event.
@@ -69,7 +68,7 @@ JSkit.Dispatcher = (function() {
69
68
  */
70
69
  function registerHandler(registeredHandlers, eventHandler, method) {
71
70
  method = method || "push";
72
- if (!contains(pluck(registeredHandlers, "handler"), eventHandler.handler)) {
71
+ if (!any(registeredHandlers, eventHandler)) {
73
72
  registeredHandlers[method](eventHandler);
74
73
  }
75
74
  }
@@ -146,7 +145,7 @@ JSkit.Dispatcher = (function() {
146
145
  var eventHhandlers = this.__events__[eventName] || [];
147
146
  var args = _.rest(arguments);
148
147
 
149
- _.each(eventHhandlers, function(eventHandler) {
148
+ each(eventHhandlers, function(eventHandler) {
150
149
  var handler = eventHandler.handler;
151
150
  var context = eventHandler.context;
152
151
  handler.apply(context, args);
@@ -157,301 +156,228 @@ JSkit.Dispatcher = (function() {
157
156
  };
158
157
  })();
159
158
 
160
- /**
161
- * @module JSkit
162
- * @class Controller
163
- */
164
159
  JSkit.Controller = (function() {
160
+ var bind = _.bind;
165
161
  var bindAll = _.bindAll;
162
+ var cloneDeep = _.cloneDeep;
166
163
  var compact = _.compact;
167
164
  var defaults = _.defaults;
168
165
  var each = _.each;
166
+ var extend = _.extend;
169
167
  var first = _.first;
170
168
  var flatten = _.flatten;
171
- var functions = _.functions;
172
- var isFunc = _.isFunction;
169
+ var includes = _.includes;
170
+ var isArray = _.isArray;
171
+ var isFunction = _.isFunction;
173
172
  var isObject = _.isObject;
174
173
  var keys = _.keys;
175
174
  var last = _.last;
176
175
  var map = _.map;
177
- var pairs = _.pairs;
178
176
  var reduce = _.reduce;
179
- var uniq = _.uniq;
180
- var values = _.values;
177
+ var underscore = _.snakeCase;
178
+
179
+ function restrictKeywords(attrs) {
180
+ var keywords = [
181
+ "registerEvents",
182
+ "registerActions",
183
+ "cacheElements",
184
+ "eventNameForAction"
185
+ ];
186
+
187
+ each(keys(attrs), function(keyword) {
188
+ if (includes(keywords, keyword)) {
189
+ throw new Error("JSkit.Controller.create: " + keyword + " is a restricted keyword");
190
+ }
191
+ });
192
+ }
181
193
 
182
- /**
183
- * Take a string and put underscores between names and delimiters
184
- *
185
- * @private
186
- * @method constantize
187
- * @param {String} string
188
- * @return {String}
189
- */
190
- function underscore(string) {
191
- string = string || "";
192
- return string.replace(/([A-Z])/g, " $1").replace(/^\s?/, "").replace(/-|\s/g, "_").toLowerCase();
194
+ function eventNameForAction(controller, action) {
195
+ return compact([
196
+ controller.namespace,
197
+ controller.channel,
198
+ controller.controllerEventName,
199
+ action
200
+ ]).join(controller.eventSeparator);
193
201
  }
194
202
 
195
- /**
196
- * Register the controller's actions to the dispatcher
197
- *
198
- * @private
199
- * @method registerActions
200
- * @param {Controller} controller
201
- */
202
- function registerActions(controller) {
203
- each(controller.actions, function(action) {
204
- each(mapAction(action), function(actionMap) {
205
- ensureActionIsDefined(controller, actionMap);
206
- controller.dispatcher.on(actionEventName(controller, actionMap.name), controller[actionMap.method], controller);
207
- }, controller);
208
- }, controller);
203
+ function registerAllAction(controller) {
204
+ if (!includes(controller.actions, "all")) controller.actions.unshift("all");
209
205
  }
210
206
 
211
- /**
212
- * Take an action string or mapped action and return
213
- * an object containing the action name and method.
214
- *
215
- * @private
216
- * @method mapAction
217
- * @param {String,Object} action/mappedAction
218
- * @return {Array} action/event maps
219
- */
220
- function mapAction(action) {
221
- return isObject(action) ? map(action, createActionMap) : [createActionMap(action, action)];
207
+ function normalizeActions(controller) {
208
+ controller.__actions__ = flatten(map(controller.actions, function(action) {
209
+ return normalizeAction(action);
210
+ }));
222
211
  }
223
212
 
224
- /**
225
- * Create a list of maps of action name/method pairs.
226
- *
227
- * @private
228
- * @method createActionMap
229
- * @param {String} method to map to action
230
- * @param {String} action to map to method
231
- */
232
- function createActionMap(method, action) {
233
- return { name: action, method: method };
213
+ function normalizeAction(action) {
214
+ return isObject(action) ? map(action, createActionObject) : [createActionObject(action, action)];
234
215
  }
235
216
 
236
- /**
237
- * Take a controller and an actionMap and determine if
238
- * the action is defined on the controller. If not, throw
239
- * an error.
240
- *
241
- * @private
242
- * @method ensureActionIsDefined
243
- * @param {Controller} controller
244
- * @param {Object} actionMap
245
- */
246
- function ensureActionIsDefined(controller, actionMap) {
247
- if (!isFunc(controller[actionMap.method])) {
248
- throw new Error(controller.name + ' action "' + actionMap.name + ":" + actionMap.method + '" method is undefined');
217
+ function createActionObject(method, name) {
218
+ return { name: name, method: method };
219
+ }
220
+
221
+ function ensureActionIsDefined(controller, action) {
222
+ if (!isFunction(controller[action.method])) {
223
+ throw new Error(controller.name + ' action "' + action.name + ":" + action.method + '" method is undefined');
249
224
  }
250
225
  }
251
226
 
252
- /**
253
- * Return an event name based on the controller properties
254
- * that make up an event name.
255
- *
256
- * @private
257
- * @method actionEventName
258
- * @param {Controller} controller
259
- * @param {String} action
260
- * @return String
261
- */
262
- function actionEventName(controller, action) {
263
- return compact([
264
- controller.namespace,
265
- controller.channel,
266
- controller.controllerEventName,
267
- action
268
- ]).join(controller.eventSeparator);
227
+ function registerActions(controller) {
228
+ each(controller.__actions__, function(action) {
229
+ ensureActionIsDefined(controller, action);
230
+ controller.dispatcher.on(eventNameForAction(controller, action.name), controller[action.method], controller);
231
+ });
232
+ }
233
+
234
+ function normalizeControllerElements(controller) {
235
+ controller.__elements__ = reduce(controller.elements, function(memo, elements, action) {
236
+ memo[action] = normalizeElements(elements);
237
+ return memo;
238
+ }, {});
239
+ }
240
+
241
+ function normalizeElements(elements) {
242
+ return reduce(elements, function(memo, selector, name) {
243
+ if (_.isArray(selector)) selector = first(selector);
244
+ memo[name] = selector;
245
+ return memo;
246
+ }, {});
247
+ }
248
+
249
+ function normalizeControllerEvents(controller) {
250
+ controller.__events__ = reduce(controller.elements, function(memo, elements, action) {
251
+ memo[action] = normalizeEvents(elements);
252
+ return memo;
253
+ }, {});
254
+ }
255
+
256
+ function normalizeEvents(elements) {
257
+ return reduce(elements, function(memo, selector, name) {
258
+ if (_.isArray(selector)) memo["$" + name] = last(selector);
259
+
260
+ return memo;
261
+ }, {});
262
+ }
263
+
264
+ function isMappedAction(action) {
265
+ return action.name != action.method;
266
+ }
267
+
268
+ function nativeFind(selector) {
269
+ return document.querySelectorAll(selector);
270
+ }
271
+
272
+ function findInDOM(selector) {
273
+ var finder = $ ? $ : nativeFind;
274
+ return finder(selector);
269
275
  }
270
276
 
271
- /**
272
- * Iterate over the given controller's elements object
273
- * and cache a reference to each selected element.
274
- *
275
- * @private
276
- * @method cacheElements
277
- * @param {Controller} controller
278
- * @param {String} action
279
- */
280
277
  function cacheElements(controller, action) {
281
- if (reduceElements(controller.elements, first)[action]) {
282
- each(reduceElements(controller.elements, first)[action], function(selector, name) {
283
- controller["$" + name] = $(selector);
284
- }, controller);
278
+ if (!action) throw new Error("JSkit.Controller.cacheElements: action is undefined");
279
+
280
+ var actionElements = controller.__elements__[action];
281
+
282
+ if (actionElements) {
283
+ each(actionElements, function(selector, name) {
284
+ var element = controller["$" + name] = findInDOM(selector);
285
+
286
+ if (!element.length) {
287
+ throw new Error("JSkit.Controller.cacheElements: " + selector + " is not in the DOM");
288
+ }
289
+ });
285
290
  }
286
291
  }
287
292
 
288
- /**
289
- * Iterate over the given action's events and register
290
- * the event handlers on each element.
291
- *
292
- * @private
293
- * @method registerEvents
294
- * @param {Controller} controller
295
- * @param {String} action
296
- */
297
- function registerEvents(controller, action) {
298
- if (reduceElements(controller.elements, last)[action]) {
299
- each(reduceElements(controller.elements, last)[action], function(eventMap, element) {
300
- each(eventMap, function(method, evnt) {
301
- var handler = controller[method];
302
- var $element = controller["$" + element];
303
- $element.on(evnt, handler);
304
- }, controller);
305
- }, controller);
306
- }
293
+ function decorateCacheElements(controller) {
294
+ controller.cacheElements = function(action) {
295
+ return cacheElements(controller, action);
296
+ };
307
297
  }
308
298
 
309
- /**
310
- * Iterate over the controller's elements
311
- * and register to cache each action's events.
312
- *
313
- * @private
314
- * @method registerElementCaching
315
- * @param {Controller} controller
316
- */
317
- function registerElementCaching(controller) {
318
- each(reduceElements(controller.elements, first), function(elements, action) {
319
- controller.dispatcher.before(actionEventName(controller, action), function() {
320
- cacheElements(controller, action);
321
- }, controller);
322
- }, controller);
299
+ function registerActionEvents(controller, action) {
300
+ each(controller.__events__[action], function(events, element) {
301
+ if (!controller[element]) cacheElements(controller, action);
302
+ registerElementEvents(controller, element, events);
303
+ });
323
304
  }
324
305
 
325
- /**
326
- * Iterate over the controller's events
327
- * and register to handle each action's element events.
328
- *
329
- * @private
330
- * @method registerControllerEvents
331
- * @param {Controller} controller
332
- */
333
- function registerControllerEvents(controller) {
334
- each(reduceElements(controller.elements, last), function(eventMap, action) {
335
- controller.dispatcher.on(actionEventName(controller, action), function() {
336
- registerEvents(controller, action);
337
- }, controller);
338
- }, controller);
306
+ function registerElementEvents(controller, element, events) {
307
+ var eventsBinder = bind(eventsBinderFor(events), controller);
308
+ var on = bind($.prototype.on, controller[element]);
309
+ eventsBinder(on);
339
310
  }
340
311
 
341
- /**
342
- * Reduce the controller's elements object into an object
343
- * that only contains either the elements to cache or the
344
- * events to register to that element.
345
- *
346
- * @private
347
- *
348
- * @method reduceElements
349
- * @param {Object} controller's elements object
350
- * @param {Function} function to grab either head or tail (first, last)
351
- * @return {Object}
352
- */
353
- function reduceElements(elements, accessMethod) {
354
- return reduce(elements, function(memo, value, key) {
355
- memo[key] = {};
356
- each(value, function(v, k) {
357
- memo[key][k] = accessMethod(flatten([v]));
312
+ function eventsBinderFor(events) {
313
+ if(events instanceof Function) {
314
+ return events;
315
+ }
316
+
317
+ return function(on) {
318
+ var controller = this;
319
+ each(events, function(handler, evnt) {
320
+ on(evnt, controller[handler]);
358
321
  });
359
- return memo;
360
- }, {});
322
+ };
323
+ }
324
+
325
+ function decorateRegisterEvents(controller) {
326
+ controller.registerEvents = function(action) {
327
+ return registerActionEvents(controller, action);
328
+ };
329
+ }
330
+
331
+ function registerCacheElementsForActions(controller) {
332
+ each(controller.__actions__, function(action) {
333
+ var eventName = eventNameForAction(controller, action.name);
334
+ controller.dispatcher.before(eventName, function() {
335
+ return cacheElements(controller, action.name);
336
+ })
337
+ });
338
+ }
339
+
340
+ function registerControllerElementEvents(controller) {
341
+ each(controller.__actions__, function(action) {
342
+ registerActionEvents(controller, action.name);
343
+ });
361
344
  }
362
345
 
363
346
  return {
364
- /**
365
- * Factory function to create fresh controller objects
366
- * with the given attributes.
367
- *
368
- * @method create
369
- * @static
370
- * @param {Object} [attrs={}]
371
- *
372
- * @return {Controller}
373
- */
374
347
  create: function(attrs) {
375
- attrs = attrs || {};
376
- if (!attrs.name) throw new Error("Controller.create(name): name is undefined");
377
-
348
+ attrs = extend({}, attrs);
349
+ if (!attrs.name) throw new Error("JSkit.Controller: name is undefined");
350
+ restrictKeywords(attrs);
378
351
  var controller = defaults(attrs, {
379
- /**
380
- * Array of actions to be wired up.
381
- *
382
- * @property actions
383
- * @type Array
384
- * @default []
385
- */
386
352
  actions: [],
387
- /**
388
- * Namespace that controller events are namespaced under.
389
- *
390
- * @property namespace
391
- * @type String
392
- * @default ""
393
- */
394
- namespace: "",
395
- /**
396
- * Channel that controller events use under namespace.
397
- *
398
- * @property channel
399
- * @type String
400
- * @default "controller"
401
- */
402
353
  channel: "controller",
403
- /**
404
- * Underscored name of controller for use in events.
405
- *
406
- * @property controllerEventName
407
- * @type String
408
- * @default "controller"
409
- */
410
354
  controllerEventName: underscore(attrs.name),
411
- /**
412
- * Event dispatcher for registering events.
413
- *
414
- * @property dispatcher
415
- * @type Dispatcher
416
- * @default JSkit.Dispatcher.create()
417
- */
418
355
  dispatcher: JSkit.Dispatcher.create(),
419
- /**
420
- * Object of element names/selectors to
421
- * cache per action.
422
- *
423
- * @property elements
424
- * @type Object
425
- * @default {}
426
- */
427
356
  elements: {},
428
- /**
429
- * Object of events for each action to
430
- * register on given elements.
431
- *
432
- * @property events
433
- * @type Object
434
- * @default {}
435
- */
436
357
  eventSeparator: ":",
437
- /**
438
- * Default implementation that commits no operation
439
- * @method all
440
- */
358
+ namespace: "",
359
+ initialize: function() {},
441
360
  all: function() {},
442
- /**
443
- * Default implementation that commits no operation
444
- * @method initialize
445
- */
446
- initialize: function() {}
361
+ eventNameForAction: function(action) {
362
+ return eventNameForAction(this, action);
363
+ }
447
364
  });
365
+
448
366
  bindAll(controller);
449
- controller.actions.unshift("all");
450
367
 
451
- registerElementCaching(controller);
452
- registerControllerEvents(controller);
368
+ registerAllAction(controller);
369
+ normalizeActions(controller);
453
370
  registerActions(controller);
454
371
 
372
+ normalizeControllerElements(controller);
373
+ normalizeControllerEvents(controller);
374
+
375
+ registerCacheElementsForActions(controller);
376
+ registerControllerElementEvents(controller);
377
+
378
+ decorateCacheElements(controller);
379
+ decorateRegisterEvents(controller);
380
+
455
381
  controller.initialize();
456
382
 
457
383
  return controller;
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_jskit
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.2
4
+ version: 5.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dayton Nolan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-08 00:00:00.000000000 Z
11
+ date: 2015-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
170
170
  version: '0'
171
171
  requirements: []
172
172
  rubyforge_project:
173
- rubygems_version: 2.2.2
173
+ rubygems_version: 2.4.5.1
174
174
  signing_key:
175
175
  specification_version: 4
176
176
  summary: Gem that provides Rails integration for jskit