sudojs-rails 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,5 +9,5 @@ _.namespace('<%= @path_to_object %>');
9
9
 
10
10
  <%= @path_to_object %>.<%= @a_pascal %>.prototype = $.extend(Object.create(<%= @parent %>.prototype), {
11
11
  // optional init method for your new viewController, delete if unused
12
- init: function init() {};
12
+ init: function init() {}
13
13
  });
@@ -1,3 +1,3 @@
1
1
  module Sudojs
2
- VERSION = '0.3.8'
2
+ VERSION = '0.3.9'
3
3
  end
@@ -425,10 +425,11 @@ sudo.Container.prototype.removeChild = function removeChild(arg) {
425
425
  };
426
426
 
427
427
  // ###removeChildren
428
- // Remove all children, removing the name references and index
429
- // This method calls removeFromParent on each child. If it's a DataView also removes the child's DOM.
430
- // `returns` {Object} `this`
431
- sudo.Container.prototype.removeChildren = function removeChildren(arg) {
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() {
432
433
  while(this.children.length) {
433
434
  this.children.shift().removeFromParent();
434
435
  }
@@ -452,6 +453,9 @@ sudo.Container.prototype.role = 'container';
452
453
  // What this does is allow children of a `sudo.Container` to simply pass
453
454
  // events upward, delegating the responsibility of deciding what to do to the parent.
454
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
+ //
455
459
  // `param` {*} Any number of arguments is supported, but the first is the only one searched for info.
456
460
  // A sendMethod will be located by:
457
461
  // 1. using the first argument if it is a string
@@ -855,6 +859,7 @@ sudo.DataView = function(el, data) {
855
859
  if((t = d.template)) {
856
860
  if(typeof t === 'string') this.model.data.template = sudo.template(t);
857
861
  }
862
+ this.build();
858
863
  this.bindEvents();
859
864
  if(this.role === 'dataview') this.init();
860
865
  };
@@ -866,6 +871,15 @@ sudo.inherit(sudo.View, sudo.DataView);
866
871
  sudo.DataView.prototype.addedToParent = function(parent) {
867
872
  return this.render();
868
873
  };
874
+ // ###build
875
+ // Construct the innerHTML of the $el here so that the behavior of the
876
+ // DataView, that the markup is ready after a subclass calls `this.construct`,
877
+ // is the same as other View classes
878
+ sudo.DataView.prototype.build = function build() {
879
+ this.$el.html(this.model.data.template(this.model.data));
880
+ this.built = true;
881
+ return this;
882
+ };
869
883
  // ###removeFromParent
870
884
  // Remove this object from the DOM and its parent's list of children.
871
885
  // Overrides `sudo.View.removeFromParent` to actually remove the DOM as well
@@ -892,7 +906,10 @@ sudo.DataView.prototype.render = function render(change) {
892
906
  // return early if a `blacklisted` key is set to my model
893
907
  if(change && this.autoRenderBlacklist[change.name]) return this;
894
908
  d = this.model.data;
895
- this.$el.html(d.template(d));
909
+ // has `build` been called already? If not:
910
+ if(!this.built) this.$el.html(d.template(d));
911
+ // if so erase the flag
912
+ else this.built = false;
896
913
  if(d.renderTarget) {
897
914
  this._normalizedEl_(d.renderTarget)[d.renderMethod || 'append'](this.$el);
898
915
  delete d.renderTarget;
@@ -1526,6 +1543,13 @@ sudo.extensions.listener = {
1526
1543
  this.$el.off(e.name, e.sel);
1527
1544
  }
1528
1545
  },
1546
+ // ###rebindEvents
1547
+ // Convenience method for `this.unbindEvents().bindEvents()`
1548
+ //
1549
+ // 'returns' {object} 'this'
1550
+ rebindEvents: function rebindEvents() {
1551
+ return this.unbindEvents().bindEvents();
1552
+ },
1529
1553
  // ###unbindEvents
1530
1554
  // Unbind the events in the data store from this object's $el
1531
1555
  //
@@ -1574,7 +1598,7 @@ sudo.extensions.persistable = {
1574
1598
  //
1575
1599
  // `param` {object} `params` Optional hash of options for the XHR
1576
1600
  // `returns` {object} jqXhr
1577
- destroy: function _delete(params) {
1601
+ destroy: function destroy(params) {
1578
1602
  return this._sendData_('DELETE', params);
1579
1603
  },
1580
1604
  // ###_normalizeParams_
@@ -1610,7 +1634,7 @@ sudo.extensions.persistable = {
1610
1634
  // `param` {object} `params`. Optional info for the XHR call. If
1611
1635
  // present will override any set in this model's `ajax` options object.
1612
1636
  // `returns` {object} The jQuery XHR object
1613
- read: function post(params) {
1637
+ read: function read(params) {
1614
1638
  return $.ajax(this._normalizeParams_('GET', null, params));
1615
1639
  },
1616
1640
  // ###save
@@ -1794,4 +1818,4 @@ sudo.delegates.Data.prototype.role = 'data';
1794
1818
  sudo.version = "0.9.4";
1795
1819
  window.sudo = sudo;
1796
1820
  if(typeof window._ === "undefined") window._ = sudo;
1797
- }).call(this, this);
1821
+ }).call(this, this);
@@ -1,817 +0,0 @@
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
- // ###removeFromParent
427
- // Remove this object from its parents list of children.
428
- // Does not alter the dom - do that yourself by overriding this method
429
- // or chaining method calls
430
- sudo.Container.prototype.removeFromParent = function removeFromParent() {
431
- // will error without a parent, but that would be your fault...
432
- this.parent.removeChild(this);
433
- return this;
434
- };
435
- sudo.Container.prototype.role = 'container';
436
- // ###send
437
- // The call to the specific method on a (un)specified target happens here.
438
- // If this Object is part of a `sudo.Container` maintained hierarchy
439
- // the 'target' may be left out, causing the `bubble()` method to be called.
440
- // What this does is allow children of a `sudo.Container` to simply pass
441
- // events upward, delegating the responsibility of deciding what to do to the parent.
442
- //
443
- // `param` {*} Any number of arguments is supported, but the first is the only one searched for info.
444
- // A sendMethod will be located by:
445
- // 1. using the first argument if it is a string
446
- // 2. looking for a `sendMethod` property if it is an object
447
- // In the case a specified target exists at `this.model.get('sendTarget')` it will be used
448
- // Any other args will be passed to the sendMethod after `this`
449
- // `returns` {Object} `this`
450
- sudo.Container.prototype.send = function send(/*args*/) {
451
- var args = Array.prototype.slice.call(arguments),
452
- d = this.model && this.model.data, meth, targ, fn;
453
- // normalize the input, common use cases first
454
- if(d && 'sendMethod' in d) meth = d.sendMethod;
455
- else if(typeof args[0] === 'string') meth = args.shift();
456
- // less common but viable options
457
- if(!meth) {
458
- // passed as a jquery custom data attr bound in events
459
- meth = 'data' in args[0] ? args[0].data.sendMethod :
460
- // passed in a hash from something or not passed at all
461
- args[0].sendMethod || void 0;
462
- }
463
- // target is either specified or my parent
464
- targ = d && d.sendTarget || this.bubble();
465
- // obvious chance for errors here, don't be dumb
466
- fn = targ[meth];
467
- while(!fn && (targ = targ.bubble())) {
468
- fn = targ[meth];
469
- }
470
- // sendMethods expect a signature (sender, ...)
471
- if(fn) {
472
- args.unshift(this);
473
- fn.apply(targ, args);
474
- }
475
- return this;
476
- };
477
- // ##View Class Object
478
-
479
- // Create an instance of a sudo.View object. A view is any object
480
- // that maintains its own `el`, that being some type of DOM element.
481
- // Pass in a string selector or an actual dom node reference to have the object
482
- // set that as its `el`. If no `el` is specified one will be created upon instantiation
483
- // based on the `tagName` (`div` by default). Specify `className`, `id` (or other attributes if desired)
484
- // as an (optional) `attributes` object literal on the `data` arg.
485
- //
486
- // The view object uses jquery for dom manipulation
487
- // and event delegation etc... A jquerified `this` reference is located
488
- // at `this.$el` and `this.$` scopes queries to this objects `el`, i.e it's
489
- // a shortcut for `this.$el.find(selector)`
490
- //
491
- // `param` {string|element|jQuery} `el`. Otional el for the View instance.
492
- // `param` {Object} `data`. Optional data object-literal which becomes the initial state
493
- // of a new model located at `this.model`. Also can be a reference to an existing sudo.Model instance
494
- //
495
- // `constructor`
496
- sudo.View = function(el, data) {
497
- sudo.Container.call(this);
498
- // allow model instance to be passed in as well
499
- if(data) {
500
- this.model = data.role === 'model' ? data :
501
- this.model = new sudo.Model(data);
502
- }
503
- this.setEl(el);
504
- if(this.role === 'view') this.init();
505
- };
506
- // View inherits from Container
507
- // `private`
508
- sudo.inherit(sudo.Container, sudo.View);
509
- // ###becomePremier
510
- // Premier functionality provides hooks for behavioral differentiation
511
- // among elements or class objects.
512
- //
513
- // `returns` {Object} `this`
514
- sudo.View.prototype.becomePremier = function becomePremier() {
515
- var p, f = function() {
516
- this.isPremier = true;
517
- sudo.premier = this;
518
- }.bind(this);
519
- // is there an existing premier that isn't me?
520
- if((p = sudo.premier) && p.uid !== this.uid) {
521
- // ask it to resign and call the cb
522
- p.resignPremier(f);
523
- } else f(); // no existing premier
524
- return this;
525
- };
526
- // ###init
527
- // A 'contruction-time' hook to call for further initialization needs in
528
- // View objects (and their subclasses). A noop by default child classes should override.
529
- sudo.View.prototype.init = $.noop;
530
- // the el needs to be normalized before use
531
- // `private`
532
- sudo.View.prototype._normalizedEl_ = function _normalizedEl_(el) {
533
- if(typeof el === 'string') {
534
- return $(el);
535
- } else {
536
- // Passed an already `jquerified` Element?
537
- // It will have a length of 1 if so.
538
- return el.length ? el : $(el);
539
- }
540
- };
541
- // ### resignPremier
542
- // Resign premier status
543
- //
544
- // `param` {Function} `cb`. An optional callback to execute
545
- // after resigning premier status.
546
- // `returns` {Object} `this`
547
- sudo.View.prototype.resignPremier = function resignPremier(cb) {
548
- var p;
549
- this.isPremier = false;
550
- // only remove the global premier if it is me
551
- if((p = sudo.premier) && p.uid === this.uid) {
552
- sudo.premier = null;
553
- }
554
- // fire the cb if passed
555
- if(cb) cb();
556
- return this;
557
- };
558
- // `private`
559
- sudo.View.prototype.role = 'view';
560
- // ###setEl
561
- // A view must have an element, set that here.
562
- // Stores a jquerified object as `this.$el` the raw
563
- // node is always then available as `this.$el[0]`.
564
- //
565
- // `param` {string=|element} `el`
566
- // `returns` {Object} `this`
567
- sudo.View.prototype.setEl = function setEl(el) {
568
- var d = this.model && this.model.data, a, t;
569
- if(!el) {
570
- // normalize any relevant data
571
- t = d ? d.tagName || 'div': 'div';
572
- this.$el = $(document.createElement(t));
573
- if(d && (a = d.attributes)) this.$el.attr(a);
574
- } else {
575
- this.$el = this._normalizedEl_(el);
576
- }
577
- return this;
578
- };
579
- // ###this.$
580
- // Return a single Element matching `sel` scoped to this View's el.
581
- // This is an alias to `this.$el.find(sel)`.
582
- //
583
- // `param` {string} `sel`. A jQuery compatible selector
584
- // `returns` {jQuery} A 'jquerified' result matching the selector
585
- sudo.View.prototype.$ = function(sel) {
586
- return this.$el.find(sel);
587
- };
588
- // ## Observable Extension Object
589
- //
590
- // Implementaion of the ES6 Harmony Observer pattern.
591
- // Extend a `sudo.Model` class with this object if
592
- // data-mutation-observation is required
593
- sudo.extensions.observable = {
594
- // ###_deliver_
595
- // Called from deliverChangeRecords when ready to send
596
- // changeRecords to observers.
597
- //
598
- // `private`
599
- _deliver_: function _deliver_(obj) {
600
- var i, cb = this.callbacks;
601
- for(i = 0; i < cb.length; i++) {
602
- cb[i](obj);
603
- }
604
- },
605
- // ###deliverChangeRecords
606
- // Iterate through the changeRecords array(emptying it as you go), delivering them to the
607
- // observers. You can override this method to change the standard delivery behavior.
608
- //
609
- // `returns` {Object} `this`
610
- deliverChangeRecords: function deliverChangeRecords() {
611
- var rec, cr = this.changeRecords;
612
- // FIFO
613
- for(rec; cr.length && (rec = cr.shift());) {
614
- this._deliver_(rec);
615
- }
616
- return this;
617
- },
618
- // ###observe
619
- // In a quasi-ES6 Object.observe pattern, calling observe on an `observable` and
620
- // passing a callback will cause that callback to be called whenever any
621
- // property on the observable's data store is set, changed or deleted
622
- // via set, unset, setPath or unsetPath with an object containing:
623
- // {
624
- // type: <new, updated, deleted>,
625
- // object: <the object being observed>,
626
- // name: <the key that was modified>,
627
- // oldValue: <if a previous value existed for this key>
628
- // }
629
- // For ease of 'unobserving' the same Function passed in is returned.
630
- //
631
- // `param` {Function} `fn` The callback to be called with changeRecord(s)
632
- // `returns` {Function} the Function passed in as an argument
633
- observe: function observe(fn) {
634
- // this will fail if mixed-in and no `callbacks` created so don't do that.
635
- // Per the spec, do not allow the same callback to be added
636
- var d = this.callbacks;
637
- if(d.indexOf(fn) === -1) d.push(fn);
638
- return fn;
639
- },
640
- // ###observes
641
- // Allow an array of callbacks to be registered as changeRecord recipients
642
- //
643
- // `param` {Array} ary
644
- // `returns` {Array} the Array passed in to observe
645
- observes: function observes(ary) {
646
- var i;
647
- for(i = 0; i < ary.length; i++) {
648
- this.observe(ary[i]);
649
- }
650
- return ary;
651
- },
652
- // ###set
653
- // Overrides sudo.Base.set to check for observers
654
- //
655
- // `param` {String} `key`. The name of the key
656
- // `param` {*} `value`
657
- // `param` {Bool} `hold` Call _deliver_ (falsy) or store the change notification
658
- // to be delivered upon a call to deliverChangeRecords (truthy)
659
- //
660
- // `returns` {Object|*} `this` or calls deliverChangeRecords
661
- set: function set(key, value, hold) {
662
- var obj = {name: key, object: this.data};
663
- // did this key exist already
664
- if(key in this.data) {
665
- obj.type = 'updated';
666
- // then there is an oldValue
667
- obj.oldValue = this.data[key];
668
- } else obj.type = 'new';
669
- // now actually set the value
670
- this.data[key] = value;
671
- this.changeRecords.push(obj);
672
- // call the observers or not
673
- if(hold) return this;
674
- return this.deliverChangeRecords();
675
- },
676
- // ###setPath
677
- // Overrides sudo.Base.setPath to check for observers.
678
- // Change records originating from a `setPath` operation
679
- // send back the passed in `path` as `name` as well as the
680
- // top level object being observed (this observable's data).
681
- // this allows for easy filtering either manually or via a
682
- // `change delegate`
683
- //
684
- // `param` {String} `path`
685
- // `param` {*} `value`
686
- // `param` {Bool} `hold` Call _deliver_ (falsy) or store the change notification
687
- // to be delivered upon a call to deliverChangeRecords (truthy)
688
- // `returns` {Object|*} `this` or calls deliverChangeRecords
689
- setPath: function setPath(path, value, hold) {
690
- var curr = this.data, obj = {name: path, object: this.data},
691
- p = path.split('.'), key;
692
- for (key; p.length && (key = p.shift());) {
693
- if(!p.length) {
694
- // reached the last refinement, pre-existing?
695
- if (key in curr) {
696
- obj.type = 'updated';
697
- obj.oldValue = curr[key];
698
- } else obj.type = 'new';
699
- curr[key] = value;
700
- } else if (curr[key]) {
701
- curr = curr[key];
702
- } else {
703
- curr = curr[key] = {};
704
- }
705
- }
706
- this.changeRecords.push(obj);
707
- // call all observers or not
708
- if(hold) return this;
709
- return this.deliverChangeRecords();
710
- },
711
- // ###sets
712
- // Overrides Base.sets to hold the call to _deliver_ until
713
- // all operations are done
714
- //
715
- // `returns` {Object|*} `this` or calls deliverChangeRecords
716
- sets: function sets(obj, hold) {
717
- var i, k = Object.keys(obj);
718
- for(i = 0; i < k.length; i++) {
719
- k[i].indexOf('.') === -1 ? this.set(k[i], obj[k[i]], true) :
720
- this.setPath(k[i], obj[k[i]], true);
721
- }
722
- if(hold) return this;
723
- return this.deliverChangeRecords();
724
- },
725
- // ###unobserve
726
- // Remove a particular callback from this observable
727
- //
728
- // `param` {Function} the function passed in to `observe`
729
- // `returns` {Object} `this`
730
- unobserve: function unobserve(fn) {
731
- var cb = this.callbacks, i = cb.indexOf(fn);
732
- if(i !== -1) cb.splice(i, 1);
733
- return this;
734
- },
735
- // ###unobserves
736
- // Allow an array of callbacks to be unregistered as changeRecord recipients
737
- //
738
- // `param` {Array} ary
739
- // `returns` {Object} `this`
740
- unobserves: function unobserves(ary) {
741
- var i;
742
- for(i = 0; i < ary.length; i++) {
743
- this.unobserve(ary[i]);
744
- }
745
- return this;
746
- },
747
- // ###unset
748
- // Overrides sudo.Base.unset to check for observers
749
- //
750
- // `param` {String} `key`. The name of the key
751
- // `param` {Bool} `hold`
752
- //
753
- // `returns` {Object|*} `this` or calls deliverChangeRecords
754
- unset: function unset(key, hold) {
755
- var obj = {name: key, object: this.data, type: 'deleted'},
756
- val = !!this.data[key];
757
- delete this.data[key];
758
- // call the observers if there was a val to delete
759
- return this._unset_(obj, val, hold);
760
- },
761
- // ###_unset_
762
- // Helper for the unset functions
763
- //
764
- // `private`
765
- _unset_: function _unset_(o, v, h) {
766
- if(v) {
767
- this.changeRecords.push(o);
768
- if(h) return this;
769
- return this.deliverChangeRecords();
770
- }
771
- return this;
772
- },
773
- // ###setPath
774
- // Overrides sudo.Base.unsetPath to check for observers
775
- //
776
- // `param` {String} `path`
777
- // `param` {*} `value`
778
- // `param` {bool} `hold`
779
- //
780
- // `returns` {Object|*} `this` or calls deliverChangeRecords
781
- unsetPath: function unsetPath(path, hold) {
782
- var obj = {name: path, object: this.data, type: 'deleted'},
783
- curr = this.data, p = path.split('.'),
784
- key, val;
785
- for (key; p.length && (key = p.shift());) {
786
- if(!p.length) {
787
- // reached the last refinement
788
- val = !!curr[key];
789
- delete curr[key];
790
- } else {
791
- // this can obviously fail, but can be prevented by checking
792
- // with `getPath` first.
793
- curr = curr[key];
794
- }
795
- }
796
- return this._unset_(obj, val, hold);
797
- },
798
- // ###unsets
799
- // Override of Base.unsets to hold the call to _deliver_ until done
800
- //
801
- // `param` ary
802
- // `param` hold
803
- // `returns` {Object|*} `this` or calls deliverChangeRecords
804
- unsets: function unsets(ary, hold) {
805
- var i;
806
- for(i = 0; i < ary.length; i++) {
807
- ary[i].indexOf('.') === -1 ? this.unset(k[i], true) :
808
- this.unsetPath(k[i], true);
809
- }
810
- if(hold) return this;
811
- return this.deliverChangeRecords();
812
- }
813
- };
814
- sudo.version = "0.9.4";
815
- window.sudo = sudo;
816
- if(typeof window._ === "undefined") window._ = sudo;
817
- }).call(this, this);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sudojs-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: 0.3.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-08 00:00:00.000000000 Z
12
+ date: 2013-05-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -79,7 +79,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
79
  version: '0'
80
80
  segments:
81
81
  - 0
82
- hash: 67341650352489792
82
+ hash: -4367349649715488954
83
83
  required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
@@ -88,10 +88,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
88
  version: '0'
89
89
  segments:
90
90
  - 0
91
- hash: 67341650352489792
91
+ hash: -4367349649715488954
92
92
  requirements: []
93
93
  rubyforge_project:
94
- rubygems_version: 1.8.25
94
+ rubygems_version: 1.8.24
95
95
  signing_key:
96
96
  specification_version: 3
97
97
  summary: Install and use sudo.js quickly and easily with rails 3.2+.