sudojs-rails 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +83 -3
- data/Rakefile +5 -3
- data/lib/sudojs/version.rb +1 -1
- data/vendor/assets/javascripts/es5-sham +25 -0
- data/vendor/assets/javascripts/es5-shim +948 -0
- data/vendor/assets/javascripts/sudo-x.js +341 -262
- data/vendor/assets/javascripts/sudo.js +222 -191
- metadata +6 -4
@@ -11,19 +11,36 @@ var sudo = {
|
|
11
11
|
//
|
12
12
|
// `namespace`
|
13
13
|
ext: {},
|
14
|
-
// ###
|
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
|
15
34
|
// Inherit the prototype from a parent to a child.
|
16
35
|
// Set the childs constructor for subclasses of child.
|
17
|
-
//
|
36
|
+
// Subclasses of the library base classes will not
|
18
37
|
// want to use this function in *most* use-cases. Why? User Sudo Class Objects
|
19
38
|
// possess their own constructors and any call back to a `superclass` constructor
|
20
39
|
// will generally be looking for the library Object's constructor.
|
21
40
|
//
|
22
41
|
// `param` {function} `parent`
|
23
42
|
// `param` {function} `child`
|
24
|
-
|
25
|
-
// `private`
|
26
|
-
_inherit_: function _inherit_(parent, child) {
|
43
|
+
inherit: function inherit(parent, child) {
|
27
44
|
child.prototype = Object.create(parent.prototype);
|
28
45
|
child.prototype.constructor = child;
|
29
46
|
},
|
@@ -34,13 +51,12 @@ var sudo = {
|
|
34
51
|
// `returns` {string}
|
35
52
|
makeMeASandwich: function makeMeASandwich() {return 'Okay.';},
|
36
53
|
// ###namespace
|
37
|
-
//
|
38
|
-
// the optional `obj` arg with the Base objects `setPath` method.
|
54
|
+
// Method for assuring a Namespace is defined.
|
39
55
|
//
|
40
56
|
// `param` {string} `path`. The path that leads to a blank Object.
|
41
57
|
namespace: function namespace(path) {
|
42
|
-
if (!
|
43
|
-
|
58
|
+
if (!this.getPath(path, window)) {
|
59
|
+
this.setPath(path, {}, window);
|
44
60
|
}
|
45
61
|
},
|
46
62
|
// ###premier
|
@@ -48,39 +64,69 @@ var sudo = {
|
|
48
64
|
//
|
49
65
|
// `type` {Object}
|
50
66
|
premier: null,
|
51
|
-
//
|
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
|
52
88
|
// Some sudo Objects use a unique integer as a `tag` for identification.
|
53
89
|
// (Views for example). This ensures they are indeed unique.
|
54
|
-
|
55
|
-
//
|
56
|
-
_uid_: 0,
|
57
|
-
// ####_unique_
|
90
|
+
uid: 0,
|
91
|
+
// ####unique
|
58
92
|
// An integer used as 'tags' by some sudo Objects as well
|
59
93
|
// as a unique string for views when needed
|
60
94
|
//
|
61
95
|
// `param` {string} prefix. Optional string identifier
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
+
}
|
66
116
|
}
|
67
117
|
};
|
68
118
|
// ##Base Class Object
|
69
119
|
//
|
70
|
-
// All sudo.js objects inherit base
|
71
|
-
//
|
72
|
-
// `
|
120
|
+
// All sudo.js objects inherit base, giving the ability
|
121
|
+
// to utilize delegation, the `base` function and the
|
122
|
+
// `construct` convenience method.
|
73
123
|
//
|
74
124
|
// `constructor`
|
75
|
-
sudo.Base = function(
|
76
|
-
this._data_ = data || {};
|
125
|
+
sudo.Base = function() {
|
77
126
|
// can delegate
|
78
|
-
this.
|
79
|
-
// may implement `observable`
|
80
|
-
this._callbacks_ = [];
|
81
|
-
this._changeRecords_ = [];
|
127
|
+
this.delegates = [];
|
82
128
|
// a beautiful and unique snowflake
|
83
|
-
this.
|
129
|
+
this.uid = sudo.unique();
|
84
130
|
};
|
85
131
|
// ###addDelegate
|
86
132
|
// Push an instance of a Class Object into this object's `_delegates_` list.
|
@@ -88,8 +134,8 @@ sudo.Base = function(data) {
|
|
88
134
|
// `param` {Object} an instance of a sudo.delegates Class Object
|
89
135
|
// `returns` {Object} `this`
|
90
136
|
sudo.Base.prototype.addDelegate = function addDelegate(del) {
|
91
|
-
del.
|
92
|
-
this.
|
137
|
+
del.delegator = this;
|
138
|
+
this.delegates.push(del);
|
93
139
|
return this;
|
94
140
|
};
|
95
141
|
// ###base
|
@@ -99,6 +145,7 @@ sudo.Base.prototype.addDelegate = function addDelegate(del) {
|
|
99
145
|
// that the first match is not the function that called `base`.
|
100
146
|
//
|
101
147
|
// `params` {*} any other number of arguments to be passed to the looked up method
|
148
|
+
// along with the initial method name
|
102
149
|
sudo.Base.prototype.base = function base() {
|
103
150
|
var args = Array.prototype.slice.call(arguments),
|
104
151
|
name = args.shift(),
|
@@ -127,28 +174,20 @@ sudo.Base.prototype.construct = function construct() {
|
|
127
174
|
// 1. if `meth` is falsy return the delegate.
|
128
175
|
// 2 if `meth` is truthy bind its method (to the delegate) and return the method
|
129
176
|
//
|
130
|
-
// `param` {String} `role` The
|
177
|
+
// `param` {String} `role` The role property to match in this object's delegates list
|
131
178
|
// `param` {String} `meth` Optional method to bind to the action this delegate is being used for
|
132
179
|
// `returns`
|
133
180
|
sudo.Base.prototype.delegate = function delegate(role, meth) {
|
134
|
-
var del = this.
|
181
|
+
var del = this.delegates, i;
|
135
182
|
for(i = 0; i < del.length; i++) {
|
136
|
-
if(del[i].
|
183
|
+
if(del[i].role === role) {
|
137
184
|
if(!meth) return del[i];
|
138
185
|
return del[i][meth].bind(del[i]);
|
139
186
|
}
|
140
187
|
}
|
141
188
|
};
|
142
|
-
// ###get
|
143
|
-
// Returns the value associated with a key in this object's data store.
|
144
|
-
//
|
145
|
-
// `param` {String} `key`. The name of the key
|
146
|
-
// `returns` {*}. The value associated with the key or false if not found.
|
147
|
-
sudo.Base.prototype.get = function get(key) {
|
148
|
-
return this._data_[key];
|
149
|
-
};
|
150
189
|
// ###getDelegate
|
151
|
-
// Fetch a delegate whose
|
190
|
+
// Fetch a delegate whose role property matches the passed in argument.
|
152
191
|
// Uses the `delegate` method in its 'single argument' form, included for
|
153
192
|
// API consistency
|
154
193
|
//
|
@@ -157,24 +196,59 @@ sudo.Base.prototype.get = function get(key) {
|
|
157
196
|
sudo.Base.prototype.getDelegate = function getDelegate(role) {
|
158
197
|
return this.delegate(role);
|
159
198
|
};
|
160
|
-
// ###
|
161
|
-
//
|
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
|
162
202
|
//
|
163
|
-
// `param` {String} `
|
164
|
-
// `
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
return
|
173
|
-
} else {
|
174
|
-
curr = curr[key] || {};
|
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;
|
175
213
|
}
|
176
214
|
}
|
177
|
-
return
|
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
|
+
this.data = data || {};
|
229
|
+
// only models are `observable`
|
230
|
+
this.callbacks = [];
|
231
|
+
this.changeRecords = [];
|
232
|
+
};
|
233
|
+
// Model inherits from sudo.Base
|
234
|
+
// `private`
|
235
|
+
sudo.inherit(sudo.Base, sudo.Model);
|
236
|
+
// ###get
|
237
|
+
// Returns the value associated with a key.
|
238
|
+
//
|
239
|
+
// `param` {String} `key`. The name of the key
|
240
|
+
// `returns` {*}. The value associated with the key or false if not found.
|
241
|
+
sudo.Model.prototype.get = function get(key) {
|
242
|
+
return this.data[key];
|
243
|
+
};
|
244
|
+
// ###getPath
|
245
|
+
//
|
246
|
+
// Uses the sudo namespace's getpath function operating on the model's
|
247
|
+
// data hash.
|
248
|
+
//
|
249
|
+
// `returns` {*|undefined}. The value at keypath or undefined if not found.
|
250
|
+
sudo.Model.prototype.getPath = function getPath(path) {
|
251
|
+
return sudo.getPath(path, this.data);
|
178
252
|
};
|
179
253
|
// ###gets
|
180
254
|
// Assembles and returns an object of key:value pairs for each key
|
@@ -182,66 +256,38 @@ sudo.Base.prototype.getPath = function getPath(path, obj) {
|
|
182
256
|
//
|
183
257
|
// `param` {array} `ary`. An array of keys.
|
184
258
|
// `returns` {object}
|
185
|
-
sudo.
|
259
|
+
sudo.Model.prototype.gets = function gets(ary) {
|
186
260
|
var i, obj = {};
|
187
261
|
for (i = 0; i < ary.length; i++) {
|
188
|
-
obj[ary[i]] = ary[i].indexOf('.') === -1 ? this.
|
262
|
+
obj[ary[i]] = ary[i].indexOf('.') === -1 ? this.data[ary[i]] :
|
189
263
|
this.getPath(ary[i]);
|
190
264
|
}
|
191
265
|
return obj;
|
192
266
|
};
|
193
|
-
// ###removeDelegate
|
194
|
-
// From this objects `delegates` list remove the object (there should only ever be 1)
|
195
|
-
// whose _role_ matches the passed in argument
|
196
|
-
//
|
197
|
-
// `param` {String} `role`
|
198
|
-
// `returns` {Object} `this`
|
199
|
-
sudo.Base.prototype.removeDelegate = function removeDelegate(role) {
|
200
|
-
var del = this._delegates_, i;
|
201
|
-
for(i = 0; i < del.length; i++) {
|
202
|
-
if(del[i]._role_ === role) {
|
203
|
-
// no _delegator_ for you
|
204
|
-
del[i]._delegator_ = void 0;
|
205
|
-
del.splice(i, 1);
|
206
|
-
return this;
|
207
|
-
}
|
208
|
-
}
|
209
|
-
return this;
|
210
|
-
};
|
211
267
|
// `private`
|
212
|
-
sudo.
|
268
|
+
sudo.Model.prototype.role = 'model';
|
213
269
|
// ###set
|
214
|
-
// Set a key:value pair
|
270
|
+
// Set a key:value pair.
|
215
271
|
//
|
216
272
|
// `param` {String} `key`. The name of the key.
|
217
273
|
// `param` {*} `value`. The value associated with the key.
|
218
274
|
// `returns` {Object} `this`
|
219
|
-
sudo.
|
275
|
+
sudo.Model.prototype.set = function set(key, value) {
|
220
276
|
// _NOTE: intentional possibilty of setting a falsy value_
|
221
|
-
this.
|
277
|
+
this.data[key] = value;
|
222
278
|
return this;
|
223
279
|
};
|
224
280
|
// ###setPath
|
225
|
-
// Traverse the keypath and get each object
|
226
|
-
// (or make blank ones) eventually setting the value
|
227
|
-
// at the end of the path
|
228
281
|
//
|
229
|
-
//
|
230
|
-
//
|
231
|
-
//
|
232
|
-
// `
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
} else if (curr[key]) {
|
239
|
-
curr = curr[key];
|
240
|
-
} else {
|
241
|
-
curr = curr[key] = {};
|
242
|
-
}
|
243
|
-
}
|
244
|
-
return this;
|
282
|
+
// Uses the sudo namespace's setpath function operating on the model's
|
283
|
+
// data hash.
|
284
|
+
//
|
285
|
+
// `param` {String} `path`
|
286
|
+
// `param` {*} `value`
|
287
|
+
// `returns` {Object} this.
|
288
|
+
sudo.Model.prototype.setPath = function setPath(path, value) {
|
289
|
+
sudo.setPath(path, value, this.data);
|
290
|
+
return this;
|
245
291
|
};
|
246
292
|
// ###sets
|
247
293
|
// Invokes `set()` or `setPath()` for each key value pair in `obj`.
|
@@ -249,7 +295,7 @@ sudo.Base.prototype.setPath = function setPath(path, value, obj) {
|
|
249
295
|
//
|
250
296
|
// `param` {Object} `obj`. The keys and values to set.
|
251
297
|
// `returns` {Object} `this`
|
252
|
-
sudo.
|
298
|
+
sudo.Model.prototype.sets = function sets(obj) {
|
253
299
|
var i, k = Object.keys(obj);
|
254
300
|
for(i = 0; i < k.length; i++) {
|
255
301
|
k[i].indexOf('.') === -1 ? this.set(k[i], obj[k[i]]) :
|
@@ -262,35 +308,25 @@ sudo.Base.prototype.sets = function sets(obj) {
|
|
262
308
|
//
|
263
309
|
// `param` {String} key
|
264
310
|
// `returns` {Object} `this`
|
265
|
-
sudo.
|
266
|
-
delete this.
|
311
|
+
sudo.Model.prototype.unset = function unset(key) {
|
312
|
+
delete this.data[key];
|
267
313
|
return this;
|
268
314
|
};
|
269
315
|
// ###unsetPath
|
270
|
-
//
|
271
|
-
// located at <path>
|
316
|
+
// Uses `sudo.unsetPath` operating on this models data hash
|
272
317
|
//
|
273
318
|
// `param` {String} path
|
274
319
|
// `returns` {Object} `this`
|
275
|
-
sudo.
|
276
|
-
|
277
|
-
|
278
|
-
if(!p.length) {
|
279
|
-
delete curr[key];
|
280
|
-
} else {
|
281
|
-
// this can fail if a faulty path is passed.
|
282
|
-
// using getPath beforehand can prevent that
|
283
|
-
curr = curr[key];
|
284
|
-
}
|
285
|
-
}
|
286
|
-
return this;
|
320
|
+
sudo.Model.prototype.unsetPath = function unsetPath(path) {
|
321
|
+
sudo.unsetPath(path, this.data);
|
322
|
+
return this;
|
287
323
|
};
|
288
324
|
// ###unsets
|
289
325
|
// Deletes a number of keys or paths from this object's data store
|
290
326
|
//
|
291
327
|
// `param` {array} `ary`. An array of keys or paths.
|
292
328
|
// `returns` {Objaect} `this`
|
293
|
-
sudo.
|
329
|
+
sudo.Model.prototype.unsets = function unsets(ary) {
|
294
330
|
var i;
|
295
331
|
for(i = 0; i < ary.length; i++) {
|
296
332
|
ary[i].indexOf('.') === -1 ? this.unset(ary[i]) :
|
@@ -304,13 +340,13 @@ sudo.Base.prototype.unsets = function unsets(ary) {
|
|
304
340
|
// itself be contained
|
305
341
|
//
|
306
342
|
// `constructor`
|
307
|
-
sudo.Container = function(
|
308
|
-
sudo.Base.call(this
|
309
|
-
this.
|
310
|
-
this.
|
343
|
+
sudo.Container = function() {
|
344
|
+
sudo.Base.call(this);
|
345
|
+
this.children = [];
|
346
|
+
this.childNames = {};
|
311
347
|
};
|
312
|
-
//
|
313
|
-
sudo.
|
348
|
+
// Container is a subclass of sudo.Base
|
349
|
+
sudo.inherit(sudo.Base, sudo.Container);
|
314
350
|
// ###addChild
|
315
351
|
// Adds a View to this container's list of children.
|
316
352
|
// Also adds an 'index' property and an entry in the childNames hash.
|
@@ -320,12 +356,12 @@ sudo._inherit_(sudo.Base, sudo.Container);
|
|
320
356
|
// `param` {String} `name`. An optional name for the child that will go in the childNames hash.
|
321
357
|
// `returns` {Object} `this`
|
322
358
|
sudo.Container.prototype.addChild = function addChild(child, name) {
|
323
|
-
var c = this.
|
324
|
-
child.
|
325
|
-
child.
|
359
|
+
var c = this.children;
|
360
|
+
child.parent = this;
|
361
|
+
child.index = c.length;
|
326
362
|
if(name) {
|
327
|
-
child.
|
328
|
-
this.
|
363
|
+
child.name = name;
|
364
|
+
this.childNames[name] = child.index;
|
329
365
|
}
|
330
366
|
c.push(child);
|
331
367
|
if('addedToParent' in child) child.addedToParent(this);
|
@@ -335,7 +371,7 @@ sudo.Container.prototype.addChild = function addChild(child, name) {
|
|
335
371
|
// By default, `bubble` returns the current view's parent (if it has one)
|
336
372
|
//
|
337
373
|
// `returns` {Object|undefined}
|
338
|
-
sudo.Container.prototype.bubble = function bubble() {return this.
|
374
|
+
sudo.Container.prototype.bubble = function bubble() {return this.parent;};
|
339
375
|
// ###getChild
|
340
376
|
// If a child was added with a name, via `addChild`,
|
341
377
|
// that object can be fetched by name. This prevents us from having to reference a
|
@@ -344,8 +380,8 @@ sudo.Container.prototype.bubble = function bubble() {return this._parent_;};
|
|
344
380
|
// `param` {String|Number} `id`. The string `name` or numeric `index` of the child to fetch.
|
345
381
|
// `returns` {Object|undefined} The found child
|
346
382
|
sudo.Container.prototype.getChild = function getChild(id) {
|
347
|
-
return typeof id === 'string' ? this.
|
348
|
-
this.
|
383
|
+
return typeof id === 'string' ? this.children[this.childNames[id]] :
|
384
|
+
this.children[id];
|
349
385
|
};
|
350
386
|
// ###_indexChildren_
|
351
387
|
// Method is called with the `index` property of a subview that is being removed.
|
@@ -353,11 +389,11 @@ sudo.Container.prototype.getChild = function getChild(id) {
|
|
353
389
|
// `param` {Number} `i`
|
354
390
|
// `private`
|
355
391
|
sudo.Container.prototype._indexChildren_ = function _indexChildren_(i) {
|
356
|
-
var c = this.
|
392
|
+
var c = this.children, obj = this.childNames, len;
|
357
393
|
for (len = c.length; i < len; i++) {
|
358
|
-
c[i].
|
394
|
+
c[i].index--;
|
359
395
|
// adjust any entries in childNames
|
360
|
-
if(c[i].
|
396
|
+
if(c[i].name in obj) obj[c[i].name] = c[i].index;
|
361
397
|
}
|
362
398
|
};
|
363
399
|
// ###removeChild
|
@@ -370,28 +406,19 @@ sudo.Container.prototype._indexChildren_ = function _indexChildren_(i) {
|
|
370
406
|
// An object will be assumed to be an actual sudo Class Object.
|
371
407
|
// `returns` {Object} `this`
|
372
408
|
sudo.Container.prototype.removeChild = function removeChild(arg) {
|
373
|
-
var t = typeof arg, c;
|
374
|
-
//
|
375
|
-
if(t === 'object')
|
376
|
-
else
|
377
|
-
|
378
|
-
this._removeChild_(c);
|
379
|
-
}
|
380
|
-
return this;
|
381
|
-
};
|
382
|
-
// ###_removeChild_
|
383
|
-
// Helper method for 'public' removeChild
|
384
|
-
// `param` {Object} `child`. The view that is going to be removed.
|
385
|
-
// `private`
|
386
|
-
sudo.Container.prototype._removeChild_ = function _removeChild_(child) {
|
387
|
-
var i = child._index_;
|
409
|
+
var i, t = typeof arg, c;
|
410
|
+
// normalize the input
|
411
|
+
if(t === 'object') c = arg;
|
412
|
+
else c = t === 'string' ? this.children[this.childNames[arg]] : this.children[arg];
|
413
|
+
i = c.index;
|
388
414
|
// remove from the children Array
|
389
|
-
this.
|
415
|
+
this.children.splice(i, 1);
|
390
416
|
// remove from the named child hash if present
|
391
|
-
delete this.
|
417
|
+
delete this.childNames[c.name];
|
392
418
|
// child is now an `orphan`
|
393
|
-
delete
|
419
|
+
delete c.parent;
|
394
420
|
this._indexChildren_(i);
|
421
|
+
return this;
|
395
422
|
};
|
396
423
|
// ###removeFromParent
|
397
424
|
// Remove this object from its parents list of children.
|
@@ -399,10 +426,10 @@ sudo.Container.prototype._removeChild_ = function _removeChild_(child) {
|
|
399
426
|
// or chaining method calls
|
400
427
|
sudo.Container.prototype.removeFromParent = function removeFromParent() {
|
401
428
|
// will error without a parent, but that would be your fault...
|
402
|
-
this.
|
429
|
+
this.parent.removeChild(this);
|
403
430
|
return this;
|
404
431
|
};
|
405
|
-
sudo.Container.prototype.
|
432
|
+
sudo.Container.prototype.role = 'container';
|
406
433
|
// ###send
|
407
434
|
// The call to the specific method on a (un)specified target happens here.
|
408
435
|
// If this Object is part of a `sudo.ext.container` maintained hierarchy
|
@@ -414,14 +441,14 @@ sudo.Container.prototype._role_ = 'container';
|
|
414
441
|
// A sendMethod will be located by:
|
415
442
|
// 1. using the first argument if it is a string
|
416
443
|
// 2. looking for a `sendMethod` property if it is an object
|
417
|
-
// In the case a specified target exists at `this.get('sendTarget')` it will be used
|
444
|
+
// In the case a specified target exists at `this.model.get('sendTarget')` it will be used
|
418
445
|
// Any other args will be passed to the sendMethod after `this`
|
419
446
|
// `returns` {Object} `this`
|
420
447
|
sudo.Container.prototype.send = function send(/*args*/) {
|
421
448
|
var args = Array.prototype.slice.call(arguments),
|
422
|
-
meth, targ, fn;
|
449
|
+
d = this.model && this.model.data, meth, targ, fn;
|
423
450
|
// normalize the input, common use cases first
|
424
|
-
if('sendMethod' in
|
451
|
+
if(d && 'sendMethod' in d) meth = d.sendMethod;
|
425
452
|
else if(typeof args[0] === 'string') meth = args.shift();
|
426
453
|
// less common but viable options
|
427
454
|
if(!meth) {
|
@@ -431,7 +458,7 @@ sudo.Container.prototype.send = function send(/*args*/) {
|
|
431
458
|
args[0].sendMethod || void 0;
|
432
459
|
}
|
433
460
|
// target is either specified or my parent
|
434
|
-
targ =
|
461
|
+
targ = d && d.sendTarget || this.parent;
|
435
462
|
// obvious chance for errors here, don't be dumb
|
436
463
|
fn = targ[meth];
|
437
464
|
while(!fn && (targ = targ.bubble())) {
|
@@ -459,17 +486,19 @@ sudo.Container.prototype.send = function send(/*args*/) {
|
|
459
486
|
// a shortcut for `this.$el.find(selector)`
|
460
487
|
//
|
461
488
|
// `param` {string|element|jQuery} `el`. Otional el for the View instance.
|
462
|
-
// `param` {Object} `data`. Optional data object
|
489
|
+
// `param` {Object} `data`. Optional data object which becomes the initial state
|
490
|
+
// of a new model located at `this.model`.
|
463
491
|
//
|
464
492
|
// `constructor`
|
465
493
|
sudo.View = function(el, data) {
|
466
|
-
sudo.Container.call(this
|
494
|
+
sudo.Container.call(this);
|
495
|
+
if(data) this.model = new sudo.Model(data);
|
467
496
|
this.setEl(el);
|
468
|
-
if(this.
|
497
|
+
if(this.role === 'view') this.init();
|
469
498
|
};
|
470
499
|
// View inherits from Container
|
471
500
|
// `private`
|
472
|
-
sudo.
|
501
|
+
sudo.inherit(sudo.Container, sudo.View);
|
473
502
|
// ###becomePremier
|
474
503
|
// Premier functionality provides hooks for behavioral differentiation
|
475
504
|
// among elements or class objects.
|
@@ -477,11 +506,11 @@ sudo._inherit_(sudo.Container, sudo.View);
|
|
477
506
|
// `returns` {Object} `this`
|
478
507
|
sudo.View.prototype.becomePremier = function becomePremier() {
|
479
508
|
var p, f = function() {
|
480
|
-
this.
|
509
|
+
this.isPremier = true;
|
481
510
|
sudo.premier = this;
|
482
511
|
}.bind(this);
|
483
512
|
// is there an existing premier that isn't me?
|
484
|
-
if((p = sudo.premier) && p.
|
513
|
+
if((p = sudo.premier) && p.uid !== this.uid) {
|
485
514
|
// ask it to resign and call the cb
|
486
515
|
p.resignPremier(f);
|
487
516
|
} else f(); // no existing premier
|
@@ -510,9 +539,9 @@ sudo.View.prototype._normalizedEl_ = function _normalizedEl_(el) {
|
|
510
539
|
// `returns` {Object} `this`
|
511
540
|
sudo.View.prototype.resignPremier = function resignPremier(cb) {
|
512
541
|
var p;
|
513
|
-
this.
|
542
|
+
this.isPremier = false;
|
514
543
|
// only remove the global premier if it is me
|
515
|
-
if((p = sudo.premier) && p.
|
544
|
+
if((p = sudo.premier) && p.uid === this.uid) {
|
516
545
|
sudo.premier = null;
|
517
546
|
}
|
518
547
|
// fire the cb if passed
|
@@ -520,7 +549,7 @@ sudo.View.prototype.resignPremier = function resignPremier(cb) {
|
|
520
549
|
return this;
|
521
550
|
};
|
522
551
|
// `private`
|
523
|
-
sudo.View.prototype.
|
552
|
+
sudo.View.prototype.role = 'view';
|
524
553
|
// ###setEl
|
525
554
|
// A view must have an element, set that here.
|
526
555
|
// Stores a jquerified object as `this.$el` the raw
|
@@ -529,12 +558,12 @@ sudo.View.prototype._role_ = 'view';
|
|
529
558
|
// `param` {string=|element} `el`
|
530
559
|
// `returns` {Object} `this`
|
531
560
|
sudo.View.prototype.setEl = function setEl(el) {
|
532
|
-
var a, t;
|
561
|
+
var d = this.model && this.model.data, a, t;
|
533
562
|
if(!el) {
|
534
563
|
// normalize any relevant data
|
535
|
-
t =
|
564
|
+
t = d ? d.tagName || 'div': 'div';
|
536
565
|
this.$el = $(document.createElement(t));
|
537
|
-
if((a =
|
566
|
+
if(d && (a = d.attributes)) this.$el.attr(a);
|
538
567
|
} else {
|
539
568
|
this.$el = this._normalizedEl_(el);
|
540
569
|
}
|
@@ -550,7 +579,9 @@ sudo.View.prototype.$ = function(sel) {
|
|
550
579
|
return this.$el.find(sel);
|
551
580
|
};
|
552
581
|
// ## Observable Extension Object
|
553
|
-
// Implementaion of the ES6 Harmony Observer pattern
|
582
|
+
// Implementaion of the ES6 Harmony Observer pattern.
|
583
|
+
// Extend a `sudo.Model` class with this object if
|
584
|
+
// data-mutation-observation is required
|
554
585
|
sudo.ext.observable = {
|
555
586
|
// ###_deliver_
|
556
587
|
// Called from deliverChangeRecords when ready to send
|
@@ -558,7 +589,7 @@ sudo.ext.observable = {
|
|
558
589
|
//
|
559
590
|
// `private`
|
560
591
|
_deliver_: function _deliver_(obj) {
|
561
|
-
var i, cb = this.
|
592
|
+
var i, cb = this.callbacks;
|
562
593
|
for(i = 0; i < cb.length; i++) {
|
563
594
|
cb[i](obj);
|
564
595
|
}
|
@@ -569,7 +600,7 @@ sudo.ext.observable = {
|
|
569
600
|
//
|
570
601
|
// `returns` {Object} `this`
|
571
602
|
deliverChangeRecords: function deliverChangeRecords() {
|
572
|
-
var rec, cr = this.
|
603
|
+
var rec, cr = this.changeRecords;
|
573
604
|
// FIFO
|
574
605
|
for(rec; cr.length && (rec = cr.shift());) {
|
575
606
|
this._deliver_(rec);
|
@@ -594,7 +625,7 @@ sudo.ext.observable = {
|
|
594
625
|
observe: function observe(fn) {
|
595
626
|
// this will fail if mixed-in and no `callbacks` created so don't do that.
|
596
627
|
// Per the spec, do not allow the same callback to be added
|
597
|
-
var d = this.
|
628
|
+
var d = this.callbacks;
|
598
629
|
if(d.indexOf(fn) === -1) d.push(fn);
|
599
630
|
return fn;
|
600
631
|
},
|
@@ -620,16 +651,16 @@ sudo.ext.observable = {
|
|
620
651
|
//
|
621
652
|
// `returns` {Object|*} `this` or calls deliverChangeRecords
|
622
653
|
set: function set(key, value, hold) {
|
623
|
-
var obj = {name: key, object: this.
|
654
|
+
var obj = {name: key, object: this.data};
|
624
655
|
// did this key exist already
|
625
|
-
if(key in this.
|
656
|
+
if(key in this.data) {
|
626
657
|
obj.type = 'updated';
|
627
658
|
// then there is an oldValue
|
628
|
-
obj.oldValue = this.
|
659
|
+
obj.oldValue = this.data[key];
|
629
660
|
} else obj.type = 'new';
|
630
661
|
// now actually set the value
|
631
|
-
this.
|
632
|
-
this.
|
662
|
+
this.data[key] = value;
|
663
|
+
this.changeRecords.push(obj);
|
633
664
|
// call the observers or not
|
634
665
|
if(hold) return this;
|
635
666
|
return this.deliverChangeRecords();
|
@@ -638,7 +669,7 @@ sudo.ext.observable = {
|
|
638
669
|
// Overrides sudo.Base.setPath to check for observers.
|
639
670
|
// Change records originating from a `setPath` operation
|
640
671
|
// send back the passed in `path` as `name` as well as the
|
641
|
-
// top level object being observed (this observable's
|
672
|
+
// top level object being observed (this observable's data).
|
642
673
|
// this allows for easy filtering either manually or via a
|
643
674
|
// `change delegate`
|
644
675
|
//
|
@@ -648,7 +679,7 @@ sudo.ext.observable = {
|
|
648
679
|
// to be delivered upon a call to deliverChangeRecords (truthy)
|
649
680
|
// `returns` {Object|*} `this` or calls deliverChangeRecords
|
650
681
|
setPath: function setPath(path, value, hold) {
|
651
|
-
var curr = this.
|
682
|
+
var curr = this.data, obj = {name: path, object: this.data},
|
652
683
|
p = path.split('.'), key;
|
653
684
|
for (key; p.length && (key = p.shift());) {
|
654
685
|
if(!p.length) {
|
@@ -664,7 +695,7 @@ sudo.ext.observable = {
|
|
664
695
|
curr = curr[key] = {};
|
665
696
|
}
|
666
697
|
}
|
667
|
-
this.
|
698
|
+
this.changeRecords.push(obj);
|
668
699
|
// call all observers or not
|
669
700
|
if(hold) return this;
|
670
701
|
return this.deliverChangeRecords();
|
@@ -689,7 +720,7 @@ sudo.ext.observable = {
|
|
689
720
|
// `param` {Function} the function passed in to `observe`
|
690
721
|
// `returns` {Object} `this`
|
691
722
|
unobserve: function unobserve(fn) {
|
692
|
-
var cb = this.
|
723
|
+
var cb = this.callbacks, i = cb.indexOf(fn);
|
693
724
|
if(i !== -1) cb.splice(i, 1);
|
694
725
|
return this;
|
695
726
|
},
|
@@ -713,9 +744,9 @@ sudo.ext.observable = {
|
|
713
744
|
//
|
714
745
|
// `returns` {Object|*} `this` or calls deliverChangeRecords
|
715
746
|
unset: function unset(key, hold) {
|
716
|
-
var obj = {name: key, object: this.
|
717
|
-
val = !!this.
|
718
|
-
delete this.
|
747
|
+
var obj = {name: key, object: this.data, type: 'deleted'},
|
748
|
+
val = !!this.data[key];
|
749
|
+
delete this.data[key];
|
719
750
|
// call the observers if there was a val to delete
|
720
751
|
return this._unset_(obj, val, hold);
|
721
752
|
},
|
@@ -725,7 +756,7 @@ sudo.ext.observable = {
|
|
725
756
|
// `private`
|
726
757
|
_unset_: function _unset_(o, v, h) {
|
727
758
|
if(v) {
|
728
|
-
this.
|
759
|
+
this.changeRecords.push(o);
|
729
760
|
if(h) return this;
|
730
761
|
return this.deliverChangeRecords();
|
731
762
|
}
|
@@ -740,8 +771,8 @@ sudo.ext.observable = {
|
|
740
771
|
//
|
741
772
|
// `returns` {Object|*} `this` or calls deliverChangeRecords
|
742
773
|
unsetPath: function unsetPath(path, hold) {
|
743
|
-
var obj = {name: path, object: this.
|
744
|
-
curr = this.
|
774
|
+
var obj = {name: path, object: this.data, type: 'deleted'},
|
775
|
+
curr = this.data, p = path.split('.'),
|
745
776
|
key, val;
|
746
777
|
for (key; p.length && (key = p.shift());) {
|
747
778
|
if(!p.length) {
|
@@ -772,7 +803,7 @@ sudo.ext.observable = {
|
|
772
803
|
return this.deliverChangeRecords();
|
773
804
|
}
|
774
805
|
};
|
775
|
-
sudo.version = "0.
|
806
|
+
sudo.version = "0.9.0";
|
776
807
|
window.sudo = sudo;
|
777
808
|
if(typeof window._ === "undefined") window._ = sudo;
|
778
809
|
}).call(this, this);
|