sudojs-rails 0.3.9 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d17b74bb3098b4723edc90b9fa980afeb0383d50
4
+ data.tar.gz: 44e320bb23e74d1b40e2d3ef4fabca5f8ab7fd85
5
+ SHA512:
6
+ metadata.gz: 1f3cd16671d9f91c5173519f5e5f533a071211bc7fc0e9a47592af1af400daa651b351071eb33d73bbce6fd29ebbdd419ceac31fca56a362cc5d0c7461765007
7
+ data.tar.gz: 49fa86d4bcbd5d32bdbd40f3bab6e12af1fb92df093c66832a8452cda9437aa0a761025ff37acb6a3e70ae5fe37fb1d82e2c9a6a729a5bf2b1cdb3cefb145a83
@@ -24,8 +24,8 @@ module Sudojs
24
24
  'ViewController' => '_.ViewController'
25
25
  }
26
26
 
27
- @js_app_path = 'app/assets/javascripts/application'
28
- @css_app_path = 'app/assets/stylesheets/application'
27
+ @js_app_path = 'app/assets/javascripts/views/application'
28
+ @css_app_path = 'app/assets/stylesheets/views/application'
29
29
  @js_model_path = 'app/assets/javascripts/models'
30
30
  @js_views_path = 'app/assets/javascripts/views'
31
31
  @css_views_path = 'app/assets/stylesheets/views'
@@ -111,7 +111,7 @@ module Sudojs
111
111
  js_pre = '//= '
112
112
  css_pre = ' *= '
113
113
  if @is_application
114
- req = "require application/#{@a_name}"
114
+ req = "require views/application/#{@a_name}"
115
115
  else
116
116
  # user passed option can take precedence
117
117
  req = "require #{@js_dir || @js_path}/#{@c_name}/#{@a_name}"
@@ -2,7 +2,7 @@
2
2
  * This is a css manifest for the <%= @c_name%> controller
3
3
  *
4
4
  <% if @is_application %>
5
- *= require application/<%= @a_name %>
5
+ *= require views/application/<%= @a_name %>
6
6
  <% else %>
7
7
  *= require views/<%= @c_name %>/<%= @a_name %>
8
8
  <% end %>
@@ -1,7 +1,7 @@
1
1
  // This is a js manifest for the <%= @c_name%> controller
2
2
  //
3
3
  <% if @is_application %>
4
- //= require application/<%= @a_name %>
4
+ //= require views/application/<%= @a_name %>
5
5
  <% else %>
6
6
  //= require views/<%= @c_name %>/<%= @a_name %>
7
7
  <% end %>
@@ -22,14 +22,14 @@ Example:
22
22
  assets/
23
23
  stylesheets/
24
24
  manifests/
25
- application.css
25
+ application.*
26
26
  javascripts/
27
- application/
28
- yourNamespace.js
29
27
  manifests/
30
- application.js
28
+ application.*
31
29
  models/
32
- base.js
30
+ base.*
33
31
  views/
32
+ application/
33
+ yourNamespace.*
34
34
  config/
35
35
  sudo_js.yml
@@ -21,7 +21,7 @@ module Sudojs
21
21
  end
22
22
 
23
23
  def create_dir_structure
24
- %W{application manifests models views}.each do |dir|
24
+ %W{manifests models views}.each do |dir|
25
25
  directory = "app/assets/javascripts/#{dir}"
26
26
  css_directory = "app/assets/stylesheets/#{dir}"
27
27
  unless File.directory? directory
@@ -34,6 +34,9 @@ module Sudojs
34
34
  end
35
35
  end
36
36
  end
37
+ # place the application/ in the views/
38
+ empty_directory 'app/assets/javascripts/views/application'
39
+ empty_directory 'app/assets/stylesheets/views/application'
37
40
  end
38
41
 
39
42
  def place_install_files
@@ -44,11 +47,11 @@ module Sudojs
44
47
 
45
48
  # TODO templates for other javascript pre-processors
46
49
  if js_extension_arg == '.js.coffee'
47
- template 'namespace.coffee.erb', "app/assets/javascripts/application/#{name}.js.coffee"
50
+ template 'namespace.coffee.erb', "app/assets/javascripts/views/application/#{name}.js.coffee"
48
51
  template 'model.coffee.erb', 'app/assets/javascripts/models/base.js.coffee'
49
52
  else
50
53
  # for now any other js flavor gets the baseline .js
51
- template 'namespace.js.erb', "app/assets/javascripts/application/#{name}#{js_extension_arg}"
54
+ template 'namespace.js.erb', "app/assets/javascripts/views/application/#{name}#{js_extension_arg}"
52
55
  template 'model.js.erb', "app/assets/javascripts/models/base#{js_extension_arg}"
53
56
  end
54
57
 
@@ -2,5 +2,5 @@
2
2
  // listed below.
3
3
  //
4
4
  //= require sudojs/<%= which_sudo_arg %>
5
- //= require application/<%= name %>
5
+ //= require views/application/<%= name %>
6
6
  //= require models/base
@@ -1,3 +1,3 @@
1
1
  module Sudojs
2
- VERSION = '0.3.9'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -1818,4 +1818,4 @@ sudo.delegates.Data.prototype.role = 'data';
1818
1818
  sudo.version = "0.9.4";
1819
1819
  window.sudo = sudo;
1820
1820
  if(typeof window._ === "undefined") window._ = sudo;
1821
- }).call(this, this);
1821
+ }).call(this, this);
@@ -0,0 +1,833 @@
1
+ (function(window) {
2
+ // #Sudo Namespace
3
+ var sudo = {
4
+ // Namespace for `Delegate` Class Objects used to delegate functionality
5
+ // from a `delegator`
6
+ //
7
+ // `namespace`
8
+ delegates: {},
9
+ // The sudo.extensions namespace holds the objects that are stand alone `modules` which
10
+ // can be `implemented` (mixed-in) in sudo Class Objects
11
+ //
12
+ // `namespace`
13
+ extensions: {},
14
+ // ###getPath
15
+ // Extract a value located at `path` relative to the passed in object
16
+ //
17
+ // `param` {String} `path`. The key in the form of a dot-delimited path.
18
+ // `param` {object} `obj`. An object literal to operate on.
19
+ //
20
+ // `returns` {*|undefined}. The value at keypath or undefined if not found.
21
+ getPath: function getPath(path, obj) {
22
+ var key, p;
23
+ p = path.split('.');
24
+ for (key; p.length && (key = p.shift());) {
25
+ if(!p.length) {
26
+ return obj[key];
27
+ } else {
28
+ obj = obj[key] || {};
29
+ }
30
+ }
31
+ return obj;
32
+ },
33
+ // ###inherit
34
+ // Inherit the prototype from a parent to a child.
35
+ // Set the childs constructor for subclasses of child.
36
+ // Subclasses of the library base classes will not
37
+ // want to use this function in *most* use-cases. Why? User Sudo Class Objects
38
+ // possess their own constructors and any call back to a `superclass` constructor
39
+ // will generally be looking for the library Object's constructor.
40
+ //
41
+ // `param` {function} `parent`
42
+ // `param` {function} `child`
43
+ inherit: function inherit(parent, child) {
44
+ child.prototype = Object.create(parent.prototype);
45
+ child.prototype.constructor = child;
46
+ },
47
+ // ###makeMeASandwich
48
+ // Notice there is no need to extrinsically instruct *how* to
49
+ // make the sandwich, just the elegant single command.
50
+ //
51
+ // `returns` {string}
52
+ makeMeASandwich: function makeMeASandwich() {return 'Okay.';},
53
+ // ###namespace
54
+ // Method for assuring a Namespace is defined.
55
+ //
56
+ // `param` {string} `path`. The path that leads to a blank Object.
57
+ namespace: function namespace(path) {
58
+ if (!this.getPath(path, window)) {
59
+ this.setPath(path, {}, window);
60
+ }
61
+ },
62
+ // ###premier
63
+ // The premier object takes precedence over all others so define it at the topmost level.
64
+ //
65
+ // `type` {Object}
66
+ premier: null,
67
+ // ###setPath
68
+ // Traverse the keypath and get each object
69
+ // (or make blank ones) eventually setting the value
70
+ // at the end of the path
71
+ //
72
+ // `param` {string} `path`. The path to traverse when setting a value.
73
+ // `param` {*} `value`. What to set.
74
+ // `param` {Object} `obj`. The object literal to operate on.
75
+ setPath: function setPath(path, value, obj) {
76
+ var p = path.split('.'), key;
77
+ for (key; p.length && (key = p.shift());) {
78
+ if(!p.length) {
79
+ obj[key] = value;
80
+ } else if (obj[key]) {
81
+ obj = obj[key];
82
+ } else {
83
+ obj = obj[key] = {};
84
+ }
85
+ }
86
+ },
87
+ // ####uid
88
+ // Some sudo Objects use a unique integer as a `tag` for identification.
89
+ // (Views for example). This ensures they are indeed unique.
90
+ uid: 0,
91
+ // ####unique
92
+ // An integer used as 'tags' by some sudo Objects as well
93
+ // as a unique string for views when needed
94
+ //
95
+ // `param` {string} prefix. Optional string identifier
96
+ unique: function unique(prefix) {
97
+ return prefix ? prefix + this.uid++ : this.uid++;
98
+ },
99
+ // ###unsetPath
100
+ // Remove a key:value pair from this object's data store
101
+ // located at <path>
102
+ //
103
+ // `param` {String} `path`
104
+ // `param` {Object} `obj` The object to operate on.
105
+ unsetPath: function unsetPath(path, obj) {
106
+ var p = path.split('.'), key;
107
+ for (key; p.length && (key = p.shift());) {
108
+ if(!p.length) {
109
+ delete obj[key];
110
+ } else {
111
+ // this can fail if a faulty path is passed.
112
+ // using getPath beforehand can prevent that
113
+ obj = obj[key];
114
+ }
115
+ }
116
+ }
117
+ };
118
+ // ##Base Class Object
119
+ //
120
+ // All sudo.js objects inherit base, giving the ability
121
+ // to utilize delegation, the `base` function and the
122
+ // `construct` convenience method.
123
+ //
124
+ // `constructor`
125
+ sudo.Base = function() {
126
+ // can delegate
127
+ this.delegates = [];
128
+ // a beautiful and unique snowflake
129
+ this.uid = sudo.unique();
130
+ };
131
+ // ###addDelegate
132
+ // Push an instance of a Class Object into this object's `_delegates_` list.
133
+ //
134
+ // `param` {Object} an instance of a sudo.delegates Class Object
135
+ // `returns` {Object} `this`
136
+ sudo.Base.prototype.addDelegate = function addDelegate(del) {
137
+ del.delegator = this;
138
+ this.delegates.push(del);
139
+ return this;
140
+ };
141
+ // ###base
142
+ // Lookup the function matching the name passed in and call it with
143
+ // any passed in argumets scoped to the calling object.
144
+ // This method will avoid the recursive-loop problem by making sure
145
+ // that the first match is not the function that called `base`.
146
+ //
147
+ // `params` {*} any other number of arguments to be passed to the looked up method
148
+ // along with the initial method name
149
+ sudo.Base.prototype.base = function base() {
150
+ var args = Array.prototype.slice.call(arguments),
151
+ name = args.shift(),
152
+ found = false,
153
+ obj = this,
154
+ curr;
155
+ // find method on the prototype, excluding the caller
156
+ while(!found) {
157
+ curr = Object.getPrototypeOf(obj);
158
+ if(curr[name] && curr[name] !== this[name]) found = true;
159
+ // keep digging
160
+ else obj = curr;
161
+ }
162
+ return curr[name].apply(this, args);
163
+ };
164
+ // ###construct
165
+ // A convenience method that alleviates the need to place:
166
+ // `Object.getPrototypeOf(this).consturctor.apply(this, arguments)`
167
+ // in every constructor
168
+ sudo.Base.prototype.construct = function construct() {
169
+ Object.getPrototypeOf(this).constructor.apply(this, arguments || []);
170
+ };
171
+ // ###delegate
172
+ // From this object's list of delegates find the object whose `_role_` matches
173
+ // the passed `name` and:
174
+ // 1. if `meth` is falsy return the delegate.
175
+ // 2 if `meth` is truthy bind its method (to the delegate) and return the method
176
+ //
177
+ // `param` {String} `role` The role property to match in this object's delegates list
178
+ // `param` {String} `meth` Optional method to bind to the action this delegate is being used for
179
+ // `returns`
180
+ sudo.Base.prototype.delegate = function delegate(role, meth) {
181
+ var del = this.delegates, i;
182
+ for(i = 0; i < del.length; i++) {
183
+ if(del[i].role === role) {
184
+ if(!meth) return del[i];
185
+ return del[i][meth].bind(del[i]);
186
+ }
187
+ }
188
+ };
189
+ // ###getDelegate
190
+ // Fetch a delegate whose role property matches the passed in argument.
191
+ // Uses the `delegate` method in its 'single argument' form, included for
192
+ // API consistency
193
+ //
194
+ // `param` {String} `role`
195
+ // 'returns' {Object|undefined}
196
+ sudo.Base.prototype.getDelegate = function getDelegate(role) {
197
+ return this.delegate(role);
198
+ };
199
+ // ###removeDelegate
200
+ // From this objects `delegates` list remove the object (there should only ever be 1)
201
+ // whose role matches the passed in argument
202
+ //
203
+ // `param` {String} `role`
204
+ // `returns` {Object} `this`
205
+ sudo.Base.prototype.removeDelegate = function removeDelegate(role) {
206
+ var del = this.delegates, i;
207
+ for(i = 0; i < del.length; i++) {
208
+ if(del[i].role === role) {
209
+ // no _delegator_ for you
210
+ del[i].delegator = void 0;
211
+ del.splice(i, 1);
212
+ return this;
213
+ }
214
+ }
215
+ return this;
216
+ };
217
+ // `private`
218
+ sudo.Base.prototype.role = 'base';
219
+ // ##Model Class Object
220
+ //
221
+ // Model Objects expose methods for setting and getting data, and
222
+ // can be observed if implementing the `Observable Extension`
223
+ //
224
+ // `param` {object} data. An initial state for this model.
225
+ //
226
+ // `constructor`
227
+ sudo.Model = function(data) {
228
+ sudo.Base.call(this);
229
+ this.data = data || {};
230
+ // only models are `observable`
231
+ this.callbacks = [];
232
+ this.changeRecords = [];
233
+ };
234
+ // Model inherits from sudo.Base
235
+ // `private`
236
+ sudo.inherit(sudo.Base, sudo.Model);
237
+ // ###get
238
+ // Returns the value associated with a key.
239
+ //
240
+ // `param` {String} `key`. The name of the key
241
+ // `returns` {*}. The value associated with the key or false if not found.
242
+ sudo.Model.prototype.get = function get(key) {
243
+ return this.data[key];
244
+ };
245
+ // ###getPath
246
+ //
247
+ // Uses the sudo namespace's getpath function operating on the model's
248
+ // data hash.
249
+ //
250
+ // `returns` {*|undefined}. The value at keypath or undefined if not found.
251
+ sudo.Model.prototype.getPath = function getPath(path) {
252
+ return sudo.getPath(path, this.data);
253
+ };
254
+ // ###gets
255
+ // Assembles and returns an object of key:value pairs for each key
256
+ // contained in the passed in Array.
257
+ //
258
+ // `param` {array} `ary`. An array of keys.
259
+ // `returns` {object}
260
+ sudo.Model.prototype.gets = function gets(ary) {
261
+ var i, obj = {};
262
+ for (i = 0; i < ary.length; i++) {
263
+ obj[ary[i]] = ary[i].indexOf('.') === -1 ? this.data[ary[i]] :
264
+ this.getPath(ary[i]);
265
+ }
266
+ return obj;
267
+ };
268
+ // `private`
269
+ sudo.Model.prototype.role = 'model';
270
+ // ###set
271
+ // Set a key:value pair.
272
+ //
273
+ // `param` {String} `key`. The name of the key.
274
+ // `param` {*} `value`. The value associated with the key.
275
+ // `returns` {Object} `this`
276
+ sudo.Model.prototype.set = function set(key, value) {
277
+ // _NOTE: intentional possibilty of setting a falsy value_
278
+ this.data[key] = value;
279
+ return this;
280
+ };
281
+ // ###setPath
282
+ //
283
+ // Uses the sudo namespace's setpath function operating on the model's
284
+ // data hash.
285
+ //
286
+ // `param` {String} `path`
287
+ // `param` {*} `value`
288
+ // `returns` {Object} this.
289
+ sudo.Model.prototype.setPath = function setPath(path, value) {
290
+ sudo.setPath(path, value, this.data);
291
+ return this;
292
+ };
293
+ // ###sets
294
+ // Invokes `set()` or `setPath()` for each key value pair in `obj`.
295
+ // Any listeners for those keys or paths will be called.
296
+ //
297
+ // `param` {Object} `obj`. The keys and values to set.
298
+ // `returns` {Object} `this`
299
+ sudo.Model.prototype.sets = function sets(obj) {
300
+ var i, k = Object.keys(obj);
301
+ for(i = 0; i < k.length; i++) {
302
+ k[i].indexOf('.') === -1 ? this.set(k[i], obj[k[i]]) :
303
+ this.setPath(k[i], obj[k[i]]);
304
+ }
305
+ return this;
306
+ };
307
+ // ###unset
308
+ // Remove a key:value pair from this object's data store
309
+ //
310
+ // `param` {String} key
311
+ // `returns` {Object} `this`
312
+ sudo.Model.prototype.unset = function unset(key) {
313
+ delete this.data[key];
314
+ return this;
315
+ };
316
+ // ###unsetPath
317
+ // Uses `sudo.unsetPath` operating on this models data hash
318
+ //
319
+ // `param` {String} path
320
+ // `returns` {Object} `this`
321
+ sudo.Model.prototype.unsetPath = function unsetPath(path) {
322
+ sudo.unsetPath(path, this.data);
323
+ return this;
324
+ };
325
+ // ###unsets
326
+ // Deletes a number of keys or paths from this object's data store
327
+ //
328
+ // `param` {array} `ary`. An array of keys or paths.
329
+ // `returns` {Objaect} `this`
330
+ sudo.Model.prototype.unsets = function unsets(ary) {
331
+ var i;
332
+ for(i = 0; i < ary.length; i++) {
333
+ ary[i].indexOf('.') === -1 ? this.unset(ary[i]) :
334
+ this.unsetPath(ary[i]);
335
+ }
336
+ return this;
337
+ };
338
+ // ##Container Class Object
339
+ //
340
+ // A container is any object that can both contain other objects and
341
+ // itself be contained
342
+ //
343
+ // `constructor`
344
+ sudo.Container = function() {
345
+ sudo.Base.call(this);
346
+ this.children = [];
347
+ this.childNames = {};
348
+ };
349
+ // Container is a subclass of sudo.Base
350
+ sudo.inherit(sudo.Base, sudo.Container);
351
+ // ###addChild
352
+ // Adds a View to this container's list of children.
353
+ // Also adds an 'index' property and an entry in the childNames hash.
354
+ // If `addedToParent` if found on the child, call it, sending `this` as an argument.
355
+ //
356
+ // `param` {Object} `child`. View (or View subclass) instance.
357
+ // `param` {String} `name`. An optional name for the child that will go in the childNames hash.
358
+ // `returns` {Object} `this`
359
+ sudo.Container.prototype.addChild = function addChild(child, name) {
360
+ var c = this.children;
361
+ child.parent = this;
362
+ child.index = c.length;
363
+ if(name) {
364
+ child.name = name;
365
+ this.childNames[name] = child.index;
366
+ }
367
+ c.push(child);
368
+ if('addedToParent' in child) child.addedToParent(this);
369
+ return this;
370
+ };
371
+ // ###bubble
372
+ // By default, `bubble` returns the current view's parent (if it has one)
373
+ //
374
+ // `returns` {Object|undefined}
375
+ sudo.Container.prototype.bubble = function bubble() {return this.parent;};
376
+ // ###getChild
377
+ // If a child was added with a name, via `addChild`,
378
+ // that object can be fetched by name. This prevents us from having to reference a
379
+ // containers children by index. That is possible however, though not preferred.
380
+ //
381
+ // `param` {String|Number} `id`. The string `name` or numeric `index` of the child to fetch.
382
+ // `returns` {Object|undefined} The found child
383
+ sudo.Container.prototype.getChild = function getChild(id) {
384
+ return typeof id === 'string' ? this.children[this.childNames[id]] :
385
+ this.children[id];
386
+ };
387
+ // ###_indexChildren_
388
+ // Method is called with the `index` property of a subview that is being removed.
389
+ // Beginning at <i> decrement subview indices.
390
+ // `param` {Number} `i`
391
+ // `private`
392
+ sudo.Container.prototype._indexChildren_ = function _indexChildren_(i) {
393
+ var c = this.children, obj = this.childNames, len;
394
+ for (len = c.length; i < len; i++) {
395
+ c[i].index--;
396
+ // adjust any entries in childNames
397
+ if(c[i].name in obj) obj[c[i].name] = c[i].index;
398
+ }
399
+ };
400
+ // ###removeChild
401
+ // Find the intended child from my list of children and remove it, removing the name reference and re-indexing
402
+ // remaining children. This method does not remove the child's DOM.
403
+ // Override this method, doing whatever you want to the child's DOM, then call `base('removeChild')` to do so.
404
+ //
405
+ // `param` {String|Number|Object} `arg`. Children will always have an `index` number, and optionally a `name`.
406
+ // If passed a string `name` is assumed, so be sure to pass an actual number if expecting to use index.
407
+ // An object will be assumed to be an actual sudo Class Object.
408
+ // `returns` {Object} `this`
409
+ sudo.Container.prototype.removeChild = function removeChild(arg) {
410
+ var i, t = typeof arg, c;
411
+ // normalize the input
412
+ if(t === 'object') c = arg;
413
+ else c = t === 'string' ? this.children[this.childNames[arg]] : this.children[arg];
414
+ i = c.index;
415
+ // remove from the children Array
416
+ this.children.splice(i, 1);
417
+ // remove from the named child hash if present
418
+ delete this.childNames[c.name];
419
+ // child is now an `orphan`
420
+ delete c.parent;
421
+ delete c.index;
422
+ delete c.name;
423
+ this._indexChildren_(i);
424
+ return this;
425
+ };
426
+
427
+ // ###removeChildren
428
+ // Remove all children, name references and adjust indexes accordingly.
429
+ // This method calls removeFromParent as each child may have overridden logic there.
430
+ //
431
+ // `returns` {object} `this`
432
+ sudo.Container.prototype.removeChildren = function removeChildren() {
433
+ while(this.children.length) {
434
+ this.children.shift().removeFromParent();
435
+ }
436
+ return this;
437
+ };
438
+
439
+ // ###removeFromParent
440
+ // Remove this object from its parents list of children.
441
+ // Does not alter the dom - do that yourself by overriding this method
442
+ // or chaining method calls
443
+ sudo.Container.prototype.removeFromParent = function removeFromParent() {
444
+ // will error without a parent, but that would be your fault...
445
+ this.parent.removeChild(this);
446
+ return this;
447
+ };
448
+ sudo.Container.prototype.role = 'container';
449
+ // ###send
450
+ // The call to the specific method on a (un)specified target happens here.
451
+ // If this Object is part of a `sudo.Container` maintained hierarchy
452
+ // the 'target' may be left out, causing the `bubble()` method to be called.
453
+ // What this does is allow children of a `sudo.Container` to simply pass
454
+ // events upward, delegating the responsibility of deciding what to do to the parent.
455
+ //
456
+ // TODO Currently, only the first target method found is called, then the
457
+ // bubbling is stopped. Should bubbling continue all the way up the 'chain'?
458
+ //
459
+ // `param` {*} Any number of arguments is supported, but the first is the only one searched for info.
460
+ // A sendMethod will be located by:
461
+ // 1. using the first argument if it is a string
462
+ // 2. looking for a `sendMethod` property if it is an object
463
+ // In the case a specified target exists at `this.model.get('sendTarget')` it will be used
464
+ // Any other args will be passed to the sendMethod after `this`
465
+ // `returns` {Object} `this`
466
+ sudo.Container.prototype.send = function send(/*args*/) {
467
+ var args = Array.prototype.slice.call(arguments),
468
+ d = this.model && this.model.data, meth, targ, fn;
469
+ // normalize the input, common use cases first
470
+ if(d && 'sendMethod' in d) meth = d.sendMethod;
471
+ else if(typeof args[0] === 'string') meth = args.shift();
472
+ // less common but viable options
473
+ if(!meth) {
474
+ // passed as a jquery custom data attr bound in events
475
+ meth = 'data' in args[0] ? args[0].data.sendMethod :
476
+ // passed in a hash from something or not passed at all
477
+ args[0].sendMethod || void 0;
478
+ }
479
+ // target is either specified or my parent
480
+ targ = d && d.sendTarget || this.bubble();
481
+ // obvious chance for errors here, don't be dumb
482
+ fn = targ[meth];
483
+ while(!fn && (targ = targ.bubble())) {
484
+ fn = targ[meth];
485
+ }
486
+ // sendMethods expect a signature (sender, ...)
487
+ if(fn) {
488
+ args.unshift(this);
489
+ fn.apply(targ, args);
490
+ }
491
+ return this;
492
+ };
493
+ // ##View Class Object
494
+
495
+ // Create an instance of a sudo.View object. A view is any object
496
+ // that maintains its own `el`, that being some type of DOM element.
497
+ // Pass in a string selector or an actual dom node reference to have the object
498
+ // set that as its `el`. If no `el` is specified one will be created upon instantiation
499
+ // based on the `tagName` (`div` by default). Specify `className`, `id` (or other attributes if desired)
500
+ // as an (optional) `attributes` object literal on the `data` arg.
501
+ //
502
+ // The view object uses jquery for dom manipulation
503
+ // and event delegation etc... A jquerified `this` reference is located
504
+ // at `this.$el` and `this.$` scopes queries to this objects `el`, i.e it's
505
+ // a shortcut for `this.$el.find(selector)`
506
+ //
507
+ // `param` {string|element|jQuery} `el`. Otional el for the View instance.
508
+ // `param` {Object} `data`. Optional data object-literal which becomes the initial state
509
+ // of a new model located at `this.model`. Also can be a reference to an existing sudo.Model instance
510
+ //
511
+ // `constructor`
512
+ sudo.View = function(el, data) {
513
+ sudo.Container.call(this);
514
+ // allow model instance to be passed in as well
515
+ if(data) {
516
+ this.model = data.role === 'model' ? data :
517
+ this.model = new sudo.Model(data);
518
+ }
519
+ this.setEl(el);
520
+ if(this.role === 'view') this.init();
521
+ };
522
+ // View inherits from Container
523
+ // `private`
524
+ sudo.inherit(sudo.Container, sudo.View);
525
+ // ###becomePremier
526
+ // Premier functionality provides hooks for behavioral differentiation
527
+ // among elements or class objects.
528
+ //
529
+ // `returns` {Object} `this`
530
+ sudo.View.prototype.becomePremier = function becomePremier() {
531
+ var p, f = function() {
532
+ this.isPremier = true;
533
+ sudo.premier = this;
534
+ }.bind(this);
535
+ // is there an existing premier that isn't me?
536
+ if((p = sudo.premier) && p.uid !== this.uid) {
537
+ // ask it to resign and call the cb
538
+ p.resignPremier(f);
539
+ } else f(); // no existing premier
540
+ return this;
541
+ };
542
+ // ###init
543
+ // A 'contruction-time' hook to call for further initialization needs in
544
+ // View objects (and their subclasses). A noop by default child classes should override.
545
+ sudo.View.prototype.init = $.noop;
546
+ // the el needs to be normalized before use
547
+ // `private`
548
+ sudo.View.prototype._normalizedEl_ = function _normalizedEl_(el) {
549
+ if(typeof el === 'string') {
550
+ return $(el);
551
+ } else {
552
+ // Passed an already `jquerified` Element?
553
+ // It will have a length of 1 if so.
554
+ return el.length ? el : $(el);
555
+ }
556
+ };
557
+ // ### resignPremier
558
+ // Resign premier status
559
+ //
560
+ // `param` {Function} `cb`. An optional callback to execute
561
+ // after resigning premier status.
562
+ // `returns` {Object} `this`
563
+ sudo.View.prototype.resignPremier = function resignPremier(cb) {
564
+ var p;
565
+ this.isPremier = false;
566
+ // only remove the global premier if it is me
567
+ if((p = sudo.premier) && p.uid === this.uid) {
568
+ sudo.premier = null;
569
+ }
570
+ // fire the cb if passed
571
+ if(cb) cb();
572
+ return this;
573
+ };
574
+ // `private`
575
+ sudo.View.prototype.role = 'view';
576
+ // ###setEl
577
+ // A view must have an element, set that here.
578
+ // Stores a jquerified object as `this.$el` the raw
579
+ // node is always then available as `this.$el[0]`.
580
+ //
581
+ // `param` {string=|element} `el`
582
+ // `returns` {Object} `this`
583
+ sudo.View.prototype.setEl = function setEl(el) {
584
+ var d = this.model && this.model.data, a, t;
585
+ if(!el) {
586
+ // normalize any relevant data
587
+ t = d ? d.tagName || 'div': 'div';
588
+ this.$el = $(document.createElement(t));
589
+ if(d && (a = d.attributes)) this.$el.attr(a);
590
+ } else {
591
+ this.$el = this._normalizedEl_(el);
592
+ }
593
+ return this;
594
+ };
595
+ // ###this.$
596
+ // Return a single Element matching `sel` scoped to this View's el.
597
+ // This is an alias to `this.$el.find(sel)`.
598
+ //
599
+ // `param` {string} `sel`. A jQuery compatible selector
600
+ // `returns` {jQuery} A 'jquerified' result matching the selector
601
+ sudo.View.prototype.$ = function(sel) {
602
+ return this.$el.find(sel);
603
+ };
604
+ // ## Observable Extension Object
605
+ //
606
+ // Implementaion of the ES6 Harmony Observer pattern.
607
+ // Extend a `sudo.Model` class with this object if
608
+ // data-mutation-observation is required
609
+ sudo.extensions.observable = {
610
+ // ###_deliver_
611
+ // Called from deliverChangeRecords when ready to send
612
+ // changeRecords to observers.
613
+ //
614
+ // `private`
615
+ _deliver_: function _deliver_(obj) {
616
+ var i, cb = this.callbacks;
617
+ for(i = 0; i < cb.length; i++) {
618
+ cb[i](obj);
619
+ }
620
+ },
621
+ // ###deliverChangeRecords
622
+ // Iterate through the changeRecords array(emptying it as you go), delivering them to the
623
+ // observers. You can override this method to change the standard delivery behavior.
624
+ //
625
+ // `returns` {Object} `this`
626
+ deliverChangeRecords: function deliverChangeRecords() {
627
+ var rec, cr = this.changeRecords;
628
+ // FIFO
629
+ for(rec; cr.length && (rec = cr.shift());) {
630
+ this._deliver_(rec);
631
+ }
632
+ return this;
633
+ },
634
+ // ###observe
635
+ // In a quasi-ES6 Object.observe pattern, calling observe on an `observable` and
636
+ // passing a callback will cause that callback to be called whenever any
637
+ // property on the observable's data store is set, changed or deleted
638
+ // via set, unset, setPath or unsetPath with an object containing:
639
+ // {
640
+ // type: <new, updated, deleted>,
641
+ // object: <the object being observed>,
642
+ // name: <the key that was modified>,
643
+ // oldValue: <if a previous value existed for this key>
644
+ // }
645
+ // For ease of 'unobserving' the same Function passed in is returned.
646
+ //
647
+ // `param` {Function} `fn` The callback to be called with changeRecord(s)
648
+ // `returns` {Function} the Function passed in as an argument
649
+ observe: function observe(fn) {
650
+ // this will fail if mixed-in and no `callbacks` created so don't do that.
651
+ // Per the spec, do not allow the same callback to be added
652
+ var d = this.callbacks;
653
+ if(d.indexOf(fn) === -1) d.push(fn);
654
+ return fn;
655
+ },
656
+ // ###observes
657
+ // Allow an array of callbacks to be registered as changeRecord recipients
658
+ //
659
+ // `param` {Array} ary
660
+ // `returns` {Array} the Array passed in to observe
661
+ observes: function observes(ary) {
662
+ var i;
663
+ for(i = 0; i < ary.length; i++) {
664
+ this.observe(ary[i]);
665
+ }
666
+ return ary;
667
+ },
668
+ // ###set
669
+ // Overrides sudo.Base.set to check for observers
670
+ //
671
+ // `param` {String} `key`. The name of the key
672
+ // `param` {*} `value`
673
+ // `param` {Bool} `hold` Call _deliver_ (falsy) or store the change notification
674
+ // to be delivered upon a call to deliverChangeRecords (truthy)
675
+ //
676
+ // `returns` {Object|*} `this` or calls deliverChangeRecords
677
+ set: function set(key, value, hold) {
678
+ var obj = {name: key, object: this.data};
679
+ // did this key exist already
680
+ if(key in this.data) {
681
+ obj.type = 'updated';
682
+ // then there is an oldValue
683
+ obj.oldValue = this.data[key];
684
+ } else obj.type = 'new';
685
+ // now actually set the value
686
+ this.data[key] = value;
687
+ this.changeRecords.push(obj);
688
+ // call the observers or not
689
+ if(hold) return this;
690
+ return this.deliverChangeRecords();
691
+ },
692
+ // ###setPath
693
+ // Overrides sudo.Base.setPath to check for observers.
694
+ // Change records originating from a `setPath` operation
695
+ // send back the passed in `path` as `name` as well as the
696
+ // top level object being observed (this observable's data).
697
+ // this allows for easy filtering either manually or via a
698
+ // `change delegate`
699
+ //
700
+ // `param` {String} `path`
701
+ // `param` {*} `value`
702
+ // `param` {Bool} `hold` Call _deliver_ (falsy) or store the change notification
703
+ // to be delivered upon a call to deliverChangeRecords (truthy)
704
+ // `returns` {Object|*} `this` or calls deliverChangeRecords
705
+ setPath: function setPath(path, value, hold) {
706
+ var curr = this.data, obj = {name: path, object: this.data},
707
+ p = path.split('.'), key;
708
+ for (key; p.length && (key = p.shift());) {
709
+ if(!p.length) {
710
+ // reached the last refinement, pre-existing?
711
+ if (key in curr) {
712
+ obj.type = 'updated';
713
+ obj.oldValue = curr[key];
714
+ } else obj.type = 'new';
715
+ curr[key] = value;
716
+ } else if (curr[key]) {
717
+ curr = curr[key];
718
+ } else {
719
+ curr = curr[key] = {};
720
+ }
721
+ }
722
+ this.changeRecords.push(obj);
723
+ // call all observers or not
724
+ if(hold) return this;
725
+ return this.deliverChangeRecords();
726
+ },
727
+ // ###sets
728
+ // Overrides Base.sets to hold the call to _deliver_ until
729
+ // all operations are done
730
+ //
731
+ // `returns` {Object|*} `this` or calls deliverChangeRecords
732
+ sets: function sets(obj, hold) {
733
+ var i, k = Object.keys(obj);
734
+ for(i = 0; i < k.length; i++) {
735
+ k[i].indexOf('.') === -1 ? this.set(k[i], obj[k[i]], true) :
736
+ this.setPath(k[i], obj[k[i]], true);
737
+ }
738
+ if(hold) return this;
739
+ return this.deliverChangeRecords();
740
+ },
741
+ // ###unobserve
742
+ // Remove a particular callback from this observable
743
+ //
744
+ // `param` {Function} the function passed in to `observe`
745
+ // `returns` {Object} `this`
746
+ unobserve: function unobserve(fn) {
747
+ var cb = this.callbacks, i = cb.indexOf(fn);
748
+ if(i !== -1) cb.splice(i, 1);
749
+ return this;
750
+ },
751
+ // ###unobserves
752
+ // Allow an array of callbacks to be unregistered as changeRecord recipients
753
+ //
754
+ // `param` {Array} ary
755
+ // `returns` {Object} `this`
756
+ unobserves: function unobserves(ary) {
757
+ var i;
758
+ for(i = 0; i < ary.length; i++) {
759
+ this.unobserve(ary[i]);
760
+ }
761
+ return this;
762
+ },
763
+ // ###unset
764
+ // Overrides sudo.Base.unset to check for observers
765
+ //
766
+ // `param` {String} `key`. The name of the key
767
+ // `param` {Bool} `hold`
768
+ //
769
+ // `returns` {Object|*} `this` or calls deliverChangeRecords
770
+ unset: function unset(key, hold) {
771
+ var obj = {name: key, object: this.data, type: 'deleted'},
772
+ val = !!this.data[key];
773
+ delete this.data[key];
774
+ // call the observers if there was a val to delete
775
+ return this._unset_(obj, val, hold);
776
+ },
777
+ // ###_unset_
778
+ // Helper for the unset functions
779
+ //
780
+ // `private`
781
+ _unset_: function _unset_(o, v, h) {
782
+ if(v) {
783
+ this.changeRecords.push(o);
784
+ if(h) return this;
785
+ return this.deliverChangeRecords();
786
+ }
787
+ return this;
788
+ },
789
+ // ###setPath
790
+ // Overrides sudo.Base.unsetPath to check for observers
791
+ //
792
+ // `param` {String} `path`
793
+ // `param` {*} `value`
794
+ // `param` {bool} `hold`
795
+ //
796
+ // `returns` {Object|*} `this` or calls deliverChangeRecords
797
+ unsetPath: function unsetPath(path, hold) {
798
+ var obj = {name: path, object: this.data, type: 'deleted'},
799
+ curr = this.data, p = path.split('.'),
800
+ key, val;
801
+ for (key; p.length && (key = p.shift());) {
802
+ if(!p.length) {
803
+ // reached the last refinement
804
+ val = !!curr[key];
805
+ delete curr[key];
806
+ } else {
807
+ // this can obviously fail, but can be prevented by checking
808
+ // with `getPath` first.
809
+ curr = curr[key];
810
+ }
811
+ }
812
+ return this._unset_(obj, val, hold);
813
+ },
814
+ // ###unsets
815
+ // Override of Base.unsets to hold the call to _deliver_ until done
816
+ //
817
+ // `param` ary
818
+ // `param` hold
819
+ // `returns` {Object|*} `this` or calls deliverChangeRecords
820
+ unsets: function unsets(ary, hold) {
821
+ var i;
822
+ for(i = 0; i < ary.length; i++) {
823
+ ary[i].indexOf('.') === -1 ? this.unset(k[i], true) :
824
+ this.unsetPath(k[i], true);
825
+ }
826
+ if(hold) return this;
827
+ return this.deliverChangeRecords();
828
+ }
829
+ };
830
+ sudo.version = "0.9.4";
831
+ window.sudo = sudo;
832
+ if(typeof window._ === "undefined") window._ = sudo;
833
+ }).call(this, this);
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sudojs-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.9
5
- prerelease:
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - robrobbins
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-05-06 00:00:00.000000000 Z
11
+ date: 2013-05-07 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rspec
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -67,32 +64,25 @@ files:
67
64
  - vendor/assets/javascripts/sudojs/sudo.js
68
65
  homepage: https://github.com/robrobbins/sudojs-rails
69
66
  licenses: []
67
+ metadata: {}
70
68
  post_install_message:
71
69
  rdoc_options: []
72
70
  require_paths:
73
71
  - lib
74
72
  required_ruby_version: !ruby/object:Gem::Requirement
75
- none: false
76
73
  requirements:
77
- - - ! '>='
74
+ - - '>='
78
75
  - !ruby/object:Gem::Version
79
76
  version: '0'
80
- segments:
81
- - 0
82
- hash: -4367349649715488954
83
77
  required_rubygems_version: !ruby/object:Gem::Requirement
84
- none: false
85
78
  requirements:
86
- - - ! '>='
79
+ - - '>='
87
80
  - !ruby/object:Gem::Version
88
81
  version: '0'
89
- segments:
90
- - 0
91
- hash: -4367349649715488954
92
82
  requirements: []
93
83
  rubyforge_project:
94
- rubygems_version: 1.8.24
84
+ rubygems_version: 2.0.3
95
85
  signing_key:
96
- specification_version: 3
86
+ specification_version: 4
97
87
  summary: Install and use sudo.js quickly and easily with rails 3.2+.
98
88
  test_files: []