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
|
});
|
data/lib/sudojs/version.rb
CHANGED
@@ -425,10 +425,11 @@ sudo.Container.prototype.removeChild = function removeChild(arg) {
|
|
425
425
|
};
|
426
426
|
|
427
427
|
// ###removeChildren
|
428
|
-
// Remove all children,
|
429
|
-
// This method calls removeFromParent
|
430
|
-
//
|
431
|
-
|
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
|
-
|
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
|
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
|
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.
|
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-
|
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:
|
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:
|
91
|
+
hash: -4367349649715488954
|
92
92
|
requirements: []
|
93
93
|
rubyforge_project:
|
94
|
-
rubygems_version: 1.8.
|
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+.
|