bob-rails 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +4 -0
- data/Rakefile +8 -0
- data/app/assets/javascripts/bob.js +1989 -0
- data/lib/bob/rails/compiler.rb +61 -0
- data/lib/bob/rails/engine.rb +11 -0
- data/lib/bob/rails/paged.js +11 -0
- data/lib/bob/rails/version.rb +5 -0
- data/lib/bob/rails.rb +2 -0
- metadata +94 -0
@@ -0,0 +1,1989 @@
|
|
1
|
+
(function() {
|
2
|
+
"use strict";
|
3
|
+
var utils$bind$$bind;
|
4
|
+
|
5
|
+
if (typeof Function.prototype.bind === 'function') {
|
6
|
+
utils$bind$$bind = function(func, target) {
|
7
|
+
return func && func.bind(target);
|
8
|
+
};
|
9
|
+
} else {
|
10
|
+
utils$bind$$bind = function(func, target) {
|
11
|
+
return func && function() {
|
12
|
+
func.apply(target, arguments);
|
13
|
+
};
|
14
|
+
};
|
15
|
+
}
|
16
|
+
|
17
|
+
var utils$bind$$default = utils$bind$$bind;
|
18
|
+
|
19
|
+
function utils$logger$$NOOP() { }
|
20
|
+
|
21
|
+
function utils$logger$$consoleMethod(console, name, fallback) {
|
22
|
+
var method = typeof console === 'object' ? console[name] : null;
|
23
|
+
|
24
|
+
if (method) {
|
25
|
+
// Older IE doesn't support bind/apply, but Chrome needs it
|
26
|
+
if (typeof method.bind === 'function' || typeof method.apply === 'function') {
|
27
|
+
return utils$bind$$default(method, console);
|
28
|
+
} else {
|
29
|
+
return function(message) {
|
30
|
+
method(message);
|
31
|
+
};
|
32
|
+
}
|
33
|
+
} else if (fallback) {
|
34
|
+
return fallback;
|
35
|
+
} else {
|
36
|
+
// Use the log method with a tag (e.g. [WARN]) as a default fallback
|
37
|
+
var tag = '[' + name.toUpperCase() + '] ';
|
38
|
+
return function(message) {
|
39
|
+
this.log(tag + message);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
var utils$logger$$LEVELS = {
|
45
|
+
debug: 0,
|
46
|
+
info: 1,
|
47
|
+
warn: 2,
|
48
|
+
error: 3,
|
49
|
+
all: 4
|
50
|
+
};
|
51
|
+
|
52
|
+
function utils$logger$$Logger(console, minLevel) {
|
53
|
+
minLevel = utils$logger$$LEVELS[minLevel] - 1;
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Logs *message* to the console.
|
57
|
+
*
|
58
|
+
* @method log
|
59
|
+
* @params {Object} [message] The message to log.
|
60
|
+
*/
|
61
|
+
this.log = utils$logger$$consoleMethod(console, 'log', utils$logger$$NOOP);
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Logs *message* to the console at the `debug` level.
|
65
|
+
*
|
66
|
+
* @method debug
|
67
|
+
* @params {Object} [message] The message to log.
|
68
|
+
*/
|
69
|
+
this.debug = (minLevel >= utils$logger$$LEVELS.debug) ? utils$logger$$NOOP : utils$logger$$consoleMethod(console, 'debug');
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Logs *message* to the console at the `info` level.
|
73
|
+
*
|
74
|
+
* @method info
|
75
|
+
* @params {Object} [message] The message to log.
|
76
|
+
*/
|
77
|
+
this.info = (minLevel >= utils$logger$$LEVELS.info) ? utils$logger$$NOOP : utils$logger$$consoleMethod(console, 'info');
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Logs *message* to the console at the `warn` level.
|
81
|
+
*
|
82
|
+
* @method warn
|
83
|
+
* @params {Object} [message] The message to log.
|
84
|
+
*/
|
85
|
+
this.warn = (minLevel >= utils$logger$$LEVELS.warn) ? utils$logger$$NOOP : utils$logger$$consoleMethod(console, 'warn');
|
86
|
+
|
87
|
+
/**
|
88
|
+
* Logs *message* to the console at the `error` level.
|
89
|
+
*
|
90
|
+
* @method log
|
91
|
+
* @params {Object} [message] The message to log.
|
92
|
+
*/
|
93
|
+
this.error = (minLevel >= utils$logger$$LEVELS.error) ? utils$logger$$NOOP : utils$logger$$consoleMethod(console, 'error');
|
94
|
+
}
|
95
|
+
var utils$logger$$default = utils$logger$$Logger;
|
96
|
+
var utils$create$$create;
|
97
|
+
|
98
|
+
function utils$create$$Factory() {}
|
99
|
+
|
100
|
+
if (typeof Object.create === "function") {
|
101
|
+
utils$create$$create = Object.create;
|
102
|
+
} else {
|
103
|
+
utils$create$$create = function(proto) {
|
104
|
+
if (typeof proto !== "object" && typeof proto !== "function") {
|
105
|
+
throw new TypeError("Object prototype may only be an Object");
|
106
|
+
}
|
107
|
+
|
108
|
+
utils$create$$Factory.prototype = proto;
|
109
|
+
|
110
|
+
return new utils$create$$Factory();
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
var utils$create$$default = utils$create$$create;
|
115
|
+
function utils$object$$REQUIRED() {
|
116
|
+
return utils$object$$REQUIRED;
|
117
|
+
}
|
118
|
+
|
119
|
+
utils$object$$REQUIRED.toString = function() {
|
120
|
+
return "(Required Property)";
|
121
|
+
};
|
122
|
+
|
123
|
+
function utils$object$$LAZY(factory) {
|
124
|
+
if (this instanceof utils$object$$LAZY) {
|
125
|
+
this.factory = factory;
|
126
|
+
} else {
|
127
|
+
return new utils$object$$LAZY(factory);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
utils$object$$LAZY.prototype.toString = function() {
|
132
|
+
return "(Lazy Property)";
|
133
|
+
};
|
134
|
+
|
135
|
+
/**
|
136
|
+
* The base class for other objects in Bob. The purpose of this base class is to
|
137
|
+
* facilate class-based inheritance in JavaScript by providing helpers for
|
138
|
+
* subclassing, overriding methods and introspecting the inheritance chain.
|
139
|
+
*
|
140
|
+
* @class Object
|
141
|
+
* @namespace Bob
|
142
|
+
*/
|
143
|
+
var utils$object$$BobObject;
|
144
|
+
|
145
|
+
function utils$object$$NOOP() { }
|
146
|
+
|
147
|
+
function utils$object$$wrap(func, superFunc) {
|
148
|
+
if (
|
149
|
+
typeof superFunc === "undefined" ||
|
150
|
+
typeof superFunc !== "function" ||
|
151
|
+
superFunc.__class__ ||
|
152
|
+
superFunc.__interface__ ||
|
153
|
+
superFunc === utils$object$$REQUIRED ||
|
154
|
+
superFunc instanceof utils$object$$LAZY
|
155
|
+
) {
|
156
|
+
return func;
|
157
|
+
}
|
158
|
+
|
159
|
+
function superWrapper() {
|
160
|
+
var ret;
|
161
|
+
var sup = this && this.__nextSuper;
|
162
|
+
if(this) { this.__nextSuper = superFunc; }
|
163
|
+
ret = func.apply(this, arguments);
|
164
|
+
if(this) { this.__nextSuper = sup; }
|
165
|
+
return ret;
|
166
|
+
}
|
167
|
+
|
168
|
+
return superWrapper;
|
169
|
+
}
|
170
|
+
|
171
|
+
function utils$object$$mergeProtoProps(proto, protoProps) {
|
172
|
+
for (var key in protoProps) {
|
173
|
+
if (protoProps.hasOwnProperty(key)) {
|
174
|
+
if (typeof protoProps[key] === "function") {
|
175
|
+
proto[key] = utils$object$$wrap(protoProps[key], proto[key]);
|
176
|
+
} else {
|
177
|
+
proto[key] = protoProps[key];
|
178
|
+
}
|
179
|
+
}
|
180
|
+
}
|
181
|
+
|
182
|
+
return proto;
|
183
|
+
}
|
184
|
+
|
185
|
+
function utils$object$$classToString() {
|
186
|
+
if (this.__name__) {
|
187
|
+
return this.__name__;
|
188
|
+
} else {
|
189
|
+
var klass = this;
|
190
|
+
|
191
|
+
while (klass && !klass.__name__) {
|
192
|
+
klass = klass.superclass;
|
193
|
+
}
|
194
|
+
|
195
|
+
if (klass && klass.__name__) {
|
196
|
+
return "(subclass of " + klass.__name__ + ")";
|
197
|
+
} else {
|
198
|
+
return "(unknown class)";
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
function utils$object$$initializeLazyProperties(instance, props) {
|
204
|
+
props.forEach(function(key) {
|
205
|
+
if(instance[key] instanceof utils$object$$LAZY) {
|
206
|
+
instance[key] = instance[key].factory.call();
|
207
|
+
}
|
208
|
+
});
|
209
|
+
}
|
210
|
+
|
211
|
+
function utils$object$$ensureRequired(instance, props) {
|
212
|
+
props.forEach(function(key) {
|
213
|
+
if(instance[key] === utils$object$$REQUIRED) {
|
214
|
+
throw key + " is required for " + instance.constructor.toString();
|
215
|
+
}
|
216
|
+
});
|
217
|
+
}
|
218
|
+
|
219
|
+
/**
|
220
|
+
* Creates a subclass.
|
221
|
+
*
|
222
|
+
* ```javascript
|
223
|
+
* var Vehicle = Bob.Object.extend();
|
224
|
+
* var Car = Vehicle.extend();
|
225
|
+
*
|
226
|
+
* var myBike = new Vehicle();
|
227
|
+
*
|
228
|
+
* myBike instanceof Object // => true
|
229
|
+
* myBike instanceof Bob.Object // => true
|
230
|
+
* myBike instanceof Vehicle // => true
|
231
|
+
* myBike instanceof Car // => false
|
232
|
+
* ```
|
233
|
+
*
|
234
|
+
* You can also pass an object to `extend` that contains a set of properties to
|
235
|
+
* define on the class's prototype. Functions inside the object becomes methods
|
236
|
+
* on the subclass. If they override an existing method on the super class, then
|
237
|
+
* the superclass' implmentation will be available through `this._super` when
|
238
|
+
* the method is invoked (see its documentaion for details). Methods should only
|
239
|
+
* be defined on a class at `extend` time, otherwise `this._super` would not
|
240
|
+
* function correctly.
|
241
|
+
*
|
242
|
+
* @method extend
|
243
|
+
* @static
|
244
|
+
* @param {Object} [protoProps] A object containing the properties and methods
|
245
|
+
* to define on the subclass.
|
246
|
+
*
|
247
|
+
* @return {Class} The constructor function for the newly created subclass.
|
248
|
+
*/
|
249
|
+
function utils$object$$extend(protoProps) {
|
250
|
+
var SuperClass = this, required = [], lazy = [];
|
251
|
+
|
252
|
+
function Class() {
|
253
|
+
utils$object$$initializeLazyProperties(this, lazy);
|
254
|
+
this.init.apply(this, arguments);
|
255
|
+
utils$object$$ensureRequired(this, required);
|
256
|
+
};
|
257
|
+
|
258
|
+
/**
|
259
|
+
* @private
|
260
|
+
*
|
261
|
+
* @property __class__
|
262
|
+
* @type Boolean
|
263
|
+
* @static
|
264
|
+
*/
|
265
|
+
Class.__class__ = true;
|
266
|
+
|
267
|
+
/**
|
268
|
+
* Points to the class' parent.
|
269
|
+
*
|
270
|
+
* @property superclass
|
271
|
+
* @type Class
|
272
|
+
* @static
|
273
|
+
*/
|
274
|
+
Class.superclass = SuperClass;
|
275
|
+
Class.extend = utils$object$$extend;
|
276
|
+
Class.toString = utils$object$$classToString;
|
277
|
+
|
278
|
+
Class.prototype = utils$create$$default(SuperClass.prototype);
|
279
|
+
Class.prototype = utils$object$$mergeProtoProps(Class.prototype, protoProps);
|
280
|
+
|
281
|
+
/**
|
282
|
+
* Points to the class that created the instance.
|
283
|
+
*
|
284
|
+
* @property constructor
|
285
|
+
* @type Class
|
286
|
+
*/
|
287
|
+
Class.prototype.constructor = Class;
|
288
|
+
|
289
|
+
// Cache the required & lazy attributes (they can only be added at `extend` time)
|
290
|
+
for (var key in Class.prototype) {
|
291
|
+
if(Class.prototype[key] === utils$object$$REQUIRED) {
|
292
|
+
required.push(key);
|
293
|
+
} else if (Class.prototype[key] instanceof utils$object$$LAZY) {
|
294
|
+
lazy.push(key);
|
295
|
+
}
|
296
|
+
}
|
297
|
+
|
298
|
+
return Class;
|
299
|
+
}
|
300
|
+
|
301
|
+
utils$object$$BobObject = utils$object$$extend.call(Object, {
|
302
|
+
|
303
|
+
/**
|
304
|
+
* Called when an instance is created with the same arguments that is passed to
|
305
|
+
* the constructor function.
|
306
|
+
*
|
307
|
+
* ```javascript
|
308
|
+
* var Person = Bob.Object.extend({
|
309
|
+
* init: function(name) {
|
310
|
+
* this.name = name;
|
311
|
+
* }
|
312
|
+
* });
|
313
|
+
*
|
314
|
+
* var bob = new Person("Bob");
|
315
|
+
*
|
316
|
+
* bob.name // => "Bob"
|
317
|
+
* ```
|
318
|
+
*
|
319
|
+
* @method init
|
320
|
+
*/
|
321
|
+
init: utils$object$$NOOP,
|
322
|
+
|
323
|
+
/**
|
324
|
+
* When invoking an overriden method on a subclass, use this method to access
|
325
|
+
* the original implementation:
|
326
|
+
*
|
327
|
+
* ```javascript
|
328
|
+
* var Person = Bob.Object.extend({
|
329
|
+
* init: function(name) {
|
330
|
+
* this.name = name;
|
331
|
+
* },
|
332
|
+
*
|
333
|
+
* sayGreeting: function() {
|
334
|
+
* return "Hello from " + this.name;
|
335
|
+
* }
|
336
|
+
* });
|
337
|
+
*
|
338
|
+
* var AngryPerson = Person.extend({
|
339
|
+
* sayGreeting: function() {
|
340
|
+
* return this._super().toUpperCase() + "!!!";
|
341
|
+
* }
|
342
|
+
* });
|
343
|
+
*
|
344
|
+
* var bob = new Person("Bob");
|
345
|
+
*
|
346
|
+
* bob.sayGreeting() // => "Hello from Bob"
|
347
|
+
*
|
348
|
+
* var angryBob = new Person("Bob");
|
349
|
+
*
|
350
|
+
* angryBob.sayGreeting() // => "HELLO FROM BOB!!!"
|
351
|
+
* ```
|
352
|
+
*
|
353
|
+
* NOTE: For this feature to work properly, methods can only be added to a
|
354
|
+
* class' prototype at `extend` time.
|
355
|
+
*
|
356
|
+
* @method _super
|
357
|
+
*/
|
358
|
+
_super: function() {
|
359
|
+
var func = this.__nextSuper;
|
360
|
+
var ret;
|
361
|
+
if (func) {
|
362
|
+
this.__nextSuper = null;
|
363
|
+
ret = func.apply(this, arguments);
|
364
|
+
this.__nextSuper = func;
|
365
|
+
}
|
366
|
+
return ret;
|
367
|
+
},
|
368
|
+
|
369
|
+
toString: function() {
|
370
|
+
return "<" + this.constructor.toString() + ">";
|
371
|
+
}
|
372
|
+
|
373
|
+
});
|
374
|
+
|
375
|
+
/**
|
376
|
+
* @private
|
377
|
+
*
|
378
|
+
* A descriptor for the class (used by `toString`).
|
379
|
+
*
|
380
|
+
* @property __name__
|
381
|
+
* @type String
|
382
|
+
* @static
|
383
|
+
*/
|
384
|
+
utils$object$$BobObject.__name__ = "Bob.Object";
|
385
|
+
|
386
|
+
var utils$object$$default = utils$object$$BobObject;
|
387
|
+
|
388
|
+
/**
|
389
|
+
* The is somewhat inspired by the Ember container (since "container" has a
|
390
|
+
* different meaning in Bob, it's called a registry instead). As usual, we only
|
391
|
+
* implement a very small subset of features compared to the Ember-eqivilant.
|
392
|
+
*/
|
393
|
+
|
394
|
+
var utils$registry$$NullRegistry = {
|
395
|
+
lookup: function() {
|
396
|
+
return undefined;
|
397
|
+
},
|
398
|
+
|
399
|
+
hasKey: function() {
|
400
|
+
return false;
|
401
|
+
}
|
402
|
+
};
|
403
|
+
|
404
|
+
var utils$registry$$default = utils$object$$default.extend({
|
405
|
+
|
406
|
+
init: function(parent) {
|
407
|
+
this.parent = parent || utils$registry$$NullRegistry;
|
408
|
+
this.content = {};
|
409
|
+
},
|
410
|
+
|
411
|
+
/**
|
412
|
+
* Register an object under *key*.
|
413
|
+
*
|
414
|
+
* By convention, the format of *key* should be:
|
415
|
+
*
|
416
|
+
* type:path
|
417
|
+
*
|
418
|
+
* Where `type` is an `identifier` and `path` is one or more `identifier`s
|
419
|
+
* joined by "/". An `identifer` should begin with a lowercase letter (a-z),
|
420
|
+
* followed by any number of lowercase letters (a-z), numbers (0-9) or the "-"
|
421
|
+
* character (a "-" should not be the last character of an `identifier`).
|
422
|
+
*
|
423
|
+
* Some examples:
|
424
|
+
*
|
425
|
+
* - "template:modern"
|
426
|
+
* - "view:container"
|
427
|
+
* - "view:container/sidebar"
|
428
|
+
* - "view:container/main/column-2"
|
429
|
+
*
|
430
|
+
* @method register
|
431
|
+
* @params {String} [key] See above.
|
432
|
+
* @params {*} [object] The object to register under *key*.
|
433
|
+
*/
|
434
|
+
register: function(key, object) {
|
435
|
+
this.content[key] = object;
|
436
|
+
return object;
|
437
|
+
},
|
438
|
+
|
439
|
+
/**
|
440
|
+
* Unregister *key*.
|
441
|
+
*
|
442
|
+
* @method unregister
|
443
|
+
* @params {String} [key] See `register`.
|
444
|
+
* @return {*} The object previously registered under *key*, if any.
|
445
|
+
*/
|
446
|
+
unregister: function(key) {
|
447
|
+
var object = this.content[key];
|
448
|
+
delete this.content[key];
|
449
|
+
return object;
|
450
|
+
},
|
451
|
+
|
452
|
+
/**
|
453
|
+
* Lookup the object registered under *key*.
|
454
|
+
*
|
455
|
+
* @method lookup
|
456
|
+
* @params {String} [key] See `register`.
|
457
|
+
* @return {*} The object registered under *key*, if any.
|
458
|
+
*/
|
459
|
+
lookup: function(key) {
|
460
|
+
if(this.content.hasOwnProperty(key)) {
|
461
|
+
return this.content[key];
|
462
|
+
} else {
|
463
|
+
return this.parent.lookup(key);
|
464
|
+
}
|
465
|
+
},
|
466
|
+
|
467
|
+
/**
|
468
|
+
* Check if an object has been registered under *key*.
|
469
|
+
*
|
470
|
+
* @method hasKey
|
471
|
+
* @params {String} [key] See `register`.
|
472
|
+
* @params {Boolean} [checkParents=false] Also check if *key* is present on the parents.
|
473
|
+
* @return {Boolean} Whether *key* has been registered.
|
474
|
+
*/
|
475
|
+
hasKey: function(key, checkParents) {
|
476
|
+
checkParents = checkParents || false;
|
477
|
+
return this.content.hasOwnProperty(key) || (checkParents && this.parent.hasKey(key, true));
|
478
|
+
}
|
479
|
+
|
480
|
+
});
|
481
|
+
|
482
|
+
/**
|
483
|
+
* The main Bob namespace.
|
484
|
+
*
|
485
|
+
* @class Bob
|
486
|
+
* @static
|
487
|
+
*/
|
488
|
+
var core$$Bob = {
|
489
|
+
|
490
|
+
/**
|
491
|
+
* A shared logger instance. You can replace this with another logger to
|
492
|
+
* control what gets logged and where to log message goes.
|
493
|
+
*
|
494
|
+
* By default, this propoerty contains a `Bob.Logger` that logs to global
|
495
|
+
* `console` object at the `"info"` log level.
|
496
|
+
*
|
497
|
+
* @property logger
|
498
|
+
* @type Bob.Logger
|
499
|
+
*/
|
500
|
+
logger: new utils$logger$$default(console, "info"),
|
501
|
+
|
502
|
+
/**
|
503
|
+
* @private
|
504
|
+
*
|
505
|
+
* The global registry.
|
506
|
+
*
|
507
|
+
* @property registry
|
508
|
+
* @type Registry
|
509
|
+
*/
|
510
|
+
registry: new utils$registry$$default(null),
|
511
|
+
|
512
|
+
/**
|
513
|
+
* Register an object under *key*.
|
514
|
+
*
|
515
|
+
* By convention, the format of *key* should be:
|
516
|
+
*
|
517
|
+
* type:path
|
518
|
+
*
|
519
|
+
* Where `type` is an `identifier` and `path` is one or more `identifier`s
|
520
|
+
* joined by "/". An `identifer` should begin with a lowercase letter (a-z),
|
521
|
+
* followed by any number of lowercase letters (a-z), numbers (0-9) or the "-"
|
522
|
+
* character (a "-" should not be the last character of an `identifier`).
|
523
|
+
*
|
524
|
+
* Some examples:
|
525
|
+
*
|
526
|
+
* - "template:modern"
|
527
|
+
* - "view:container"
|
528
|
+
* - "view:container/sidebar"
|
529
|
+
* - "view:container/main/column-2"
|
530
|
+
*
|
531
|
+
* @method register
|
532
|
+
* @params {String} [key] See above.
|
533
|
+
* @params {*} [object] The object to register under *key*.
|
534
|
+
*/
|
535
|
+
register: function(key, object) {
|
536
|
+
this.registry.register(key, object);
|
537
|
+
}
|
538
|
+
|
539
|
+
};
|
540
|
+
|
541
|
+
var core$$default = core$$Bob;
|
542
|
+
|
543
|
+
function utils$hash$lookup$$test(value) {
|
544
|
+
return value !== null && value !== undefined && value !== "";
|
545
|
+
}
|
546
|
+
|
547
|
+
var utils$hash$lookup$$default = utils$object$$default.extend({
|
548
|
+
|
549
|
+
init: function(hash) {
|
550
|
+
this.hash = hash || {};
|
551
|
+
},
|
552
|
+
|
553
|
+
/**
|
554
|
+
* Lookup the given `path` on the hash. This performs a recurrsive lookup,
|
555
|
+
* i.e. if you pass `"some.nested.key"`, it will return the value stored at
|
556
|
+
* `hash.some.nested.key`. If the path or any intermediate keys along it is
|
557
|
+
* `undefined`, `null` or an empty string, the `fallback` value (defaults to
|
558
|
+
* an empty string) is returned instead.
|
559
|
+
*
|
560
|
+
* @method get
|
561
|
+
* @params {String} [path] The lookup path.
|
562
|
+
* @params {Object} [fallback=""] The fallback value.
|
563
|
+
* @return {Object} The value at the given `path` on the lookup hash, or the
|
564
|
+
* `fallback` value if it does not exist.
|
565
|
+
*/
|
566
|
+
get: function(path, fallback) {
|
567
|
+
if (arguments.length < 2) {
|
568
|
+
fallback = "";
|
569
|
+
}
|
570
|
+
|
571
|
+
var keys = path.split("."), lookup = this.hash;
|
572
|
+
|
573
|
+
while(true) {
|
574
|
+
if (!utils$hash$lookup$$test(lookup)) {
|
575
|
+
return fallback;
|
576
|
+
} else if(keys.length === 0) {
|
577
|
+
return lookup;
|
578
|
+
} else {
|
579
|
+
lookup = lookup[keys.shift()];
|
580
|
+
}
|
581
|
+
}
|
582
|
+
},
|
583
|
+
|
584
|
+
/**
|
585
|
+
* Set the given `path` to a specific value.This performs a recurrsive set,
|
586
|
+
* i.e. if you pass `"some.nested.key"`, it will set the value stored at
|
587
|
+
* `hash.some.nested.key`, creating If any intermediate keys along the path
|
588
|
+
* is `undefined` or `null`, they will first be initialized to an empty
|
589
|
+
* object (`{}`).
|
590
|
+
*
|
591
|
+
* @method set
|
592
|
+
* @params {String} [path] The path to set.
|
593
|
+
* @params {Object} [value] The value to set.
|
594
|
+
* @return {Object} The value at the given `path` on the lookup hash, or the
|
595
|
+
* `fallback` value if it does not exist.
|
596
|
+
*/
|
597
|
+
set: function(path, value) {
|
598
|
+
var keys = path.split("."), lookup = this.hash;
|
599
|
+
|
600
|
+
while(keys.length > 1) {
|
601
|
+
if (!utils$hash$lookup$$test(lookup[keys[0]])) {
|
602
|
+
lookup[keys[0]] = {};
|
603
|
+
}
|
604
|
+
|
605
|
+
lookup = lookup[keys.shift()];
|
606
|
+
}
|
607
|
+
|
608
|
+
lookup[keys.shift()] = value;
|
609
|
+
}
|
610
|
+
|
611
|
+
});
|
612
|
+
|
613
|
+
function dom$document$$emptyNode(node) {
|
614
|
+
while (node && node.childNodes.length) {
|
615
|
+
node.removeChild(node.firstChild);
|
616
|
+
}
|
617
|
+
|
618
|
+
return node;
|
619
|
+
}
|
620
|
+
|
621
|
+
function dom$document$$doesItWork(func){
|
622
|
+
try {
|
623
|
+
return !! func.call();
|
624
|
+
} catch(e) {
|
625
|
+
return false;
|
626
|
+
}
|
627
|
+
}
|
628
|
+
|
629
|
+
var dom$document$$supportsCreateHTMLDocument = dom$document$$doesItWork(function() {
|
630
|
+
var doc = document.implementation.createHTMLDocument();
|
631
|
+
|
632
|
+
dom$document$$emptyNode(doc);
|
633
|
+
|
634
|
+
return doc &&
|
635
|
+
(doc.nodeType === Node.DOCUMENT_NODE) &&
|
636
|
+
(doc.compatMode === "CSS1Compat") &&
|
637
|
+
(doc.children.length === 0) &&
|
638
|
+
(doc.documentElement === null);
|
639
|
+
});
|
640
|
+
|
641
|
+
var dom$document$$createDocument;
|
642
|
+
|
643
|
+
if (dom$document$$supportsCreateHTMLDocument) {
|
644
|
+
dom$document$$createDocument = function() {
|
645
|
+
return dom$document$$emptyNode(document.implementation.createHTMLDocument());
|
646
|
+
};
|
647
|
+
} else {
|
648
|
+
dom$document$$createDocument = function() {
|
649
|
+
var iframe = document.createElement("iframe");
|
650
|
+
var parent = document.body || document.documentElement;
|
651
|
+
|
652
|
+
iframe.style.display = "none";
|
653
|
+
iframe.src = "about:blank";
|
654
|
+
|
655
|
+
try {
|
656
|
+
parent.appendChild(iframe);
|
657
|
+
|
658
|
+
iframe.contentDocument.open();
|
659
|
+
iframe.contentDocument.write("<!doctype HTML><html><head></head><body></body></html>");
|
660
|
+
iframe.contentDocument.close();
|
661
|
+
|
662
|
+
return dom$document$$emptyNode(iframe.contentDocument);
|
663
|
+
} finally {
|
664
|
+
try {
|
665
|
+
parent.removeChild(iframe);
|
666
|
+
} catch(e) {
|
667
|
+
// The insertion probably failed
|
668
|
+
}
|
669
|
+
}
|
670
|
+
};
|
671
|
+
}
|
672
|
+
|
673
|
+
function dom$document$$prepareDocument(doc) {
|
674
|
+
return dom$document$$emptyNode(doc);
|
675
|
+
}
|
676
|
+
|
677
|
+
var dom$dom$builder$$default = utils$object$$default.extend({
|
678
|
+
|
679
|
+
init: function(document) {
|
680
|
+
this.stack = [];
|
681
|
+
|
682
|
+
/**
|
683
|
+
* The underlying `Document` object.
|
684
|
+
*
|
685
|
+
* @property document
|
686
|
+
* @type Document
|
687
|
+
*/
|
688
|
+
this.document = document;
|
689
|
+
},
|
690
|
+
|
691
|
+
/**
|
692
|
+
* Create an element and push it on to the stack.
|
693
|
+
*
|
694
|
+
* @method createElement
|
695
|
+
* @param {String} [tagName] The tag name for the element.
|
696
|
+
*/
|
697
|
+
createElement: function(tagName) {
|
698
|
+
this.stack.push( this.document.createElement(tagName) );
|
699
|
+
},
|
700
|
+
|
701
|
+
/**
|
702
|
+
* Get the element on the top of the stack.
|
703
|
+
*
|
704
|
+
* @method getElement
|
705
|
+
* @return {Element} The element on the top of the stack.
|
706
|
+
*/
|
707
|
+
getElement: function() {
|
708
|
+
return this.stack[ this.stack.length - 1 ];
|
709
|
+
},
|
710
|
+
|
711
|
+
/**
|
712
|
+
* Get the element on the top of the stack with an assertion.
|
713
|
+
*
|
714
|
+
* @private
|
715
|
+
* @method ensureElement
|
716
|
+
* @params {Integer} [count=1] Minimum number of elements on the stack.
|
717
|
+
* @return {Element} The element on the top of the stack.
|
718
|
+
*/
|
719
|
+
ensureElement: function(count) {
|
720
|
+
count = count || 1;
|
721
|
+
|
722
|
+
if (count === 1 && this.stack.length === 0) {
|
723
|
+
throw "This operation requires an element on the stack but there are none.";
|
724
|
+
} else if(this.stack.length < count) {
|
725
|
+
throw "This operation requires "+ count + " elements on the stack but there are only " + this.stack.length + ".";
|
726
|
+
}
|
727
|
+
|
728
|
+
return this.getElement();
|
729
|
+
},
|
730
|
+
|
731
|
+
/**
|
732
|
+
* Set an attribute for the element on the top of the stack. Throws an error
|
733
|
+
* if the stack is empty.
|
734
|
+
*
|
735
|
+
* @method setAttribute
|
736
|
+
* @params {String} [name] The name of the attribute to set.
|
737
|
+
* @params {String} [value] The value of the attribute to set.
|
738
|
+
*/
|
739
|
+
setAttribute: function(name, value) {
|
740
|
+
this.ensureElement().setAttribute(name, value);
|
741
|
+
},
|
742
|
+
|
743
|
+
/**
|
744
|
+
* Create a text node and immediately append it to the current element on the
|
745
|
+
* top of the stack.
|
746
|
+
*
|
747
|
+
* @method appendTextNode
|
748
|
+
* @params {String} [content] The content of the text node to append.
|
749
|
+
*/
|
750
|
+
appendTextNode: function(content) {
|
751
|
+
this.ensureElement().appendChild( this.document.createTextNode(content) );
|
752
|
+
},
|
753
|
+
|
754
|
+
/**
|
755
|
+
* Create a comment node and immediately append it to the current element on
|
756
|
+
* the top of the stack.
|
757
|
+
*
|
758
|
+
* @method appendComment
|
759
|
+
* @params {String} [content] The content of the comment to append.
|
760
|
+
*/
|
761
|
+
appendComment: function(content) {
|
762
|
+
this.ensureElement().appendChild( this.document.createComment(content) );
|
763
|
+
},
|
764
|
+
|
765
|
+
/**
|
766
|
+
* Append the top element on the stack to the previous element and pop the top
|
767
|
+
* element off the stack.
|
768
|
+
*
|
769
|
+
* @method appendElement
|
770
|
+
*/
|
771
|
+
appendElement: function() {
|
772
|
+
this.ensureElement(2);
|
773
|
+
var child = this.stack.pop(), parent = this.getElement();
|
774
|
+
parent.appendChild( child );
|
775
|
+
}
|
776
|
+
});
|
777
|
+
|
778
|
+
function dom$serialize$$escapeHTML(text) {
|
779
|
+
return text
|
780
|
+
.replace(/&/g, '&')
|
781
|
+
.replace(/</g, '<')
|
782
|
+
.replace(/>/g, '>')
|
783
|
+
.replace(/\//g, '/');
|
784
|
+
}
|
785
|
+
|
786
|
+
// We can't apply the HTML entities escape inside a <style> tag
|
787
|
+
function dom$serialize$$escapeStyleTag(text) {
|
788
|
+
return text.replace(/<\//g, "\\00003C\\00002F");
|
789
|
+
}
|
790
|
+
|
791
|
+
function dom$serialize$$escapeAttribute(text) {
|
792
|
+
return text
|
793
|
+
.replace(/"/g, '"')
|
794
|
+
.replace(/'/g, ''');
|
795
|
+
}
|
796
|
+
|
797
|
+
// See http://www.w3.org/TR/html-markup/spec.html#comments
|
798
|
+
function dom$serialize$$escapeComment(text) {
|
799
|
+
return text
|
800
|
+
.replace(/--/g, '')
|
801
|
+
.replace(/^-?>/g, '')
|
802
|
+
.replace(/-$/g, '');
|
803
|
+
}
|
804
|
+
|
805
|
+
var dom$serialize$$voidTags = [
|
806
|
+
"area", "base", "br", "col", "command", "embed", "hr", "img", "input",
|
807
|
+
"keygen", "link", "meta", "param", "source", "track", "wbr"
|
808
|
+
];
|
809
|
+
|
810
|
+
function dom$serialize$$isVoid(element) {
|
811
|
+
return dom$serialize$$voidTags.indexOf(element.nodeName.toLowerCase()) >= 0;
|
812
|
+
}
|
813
|
+
|
814
|
+
function dom$serialize$$elementToString(element, xhtml) {
|
815
|
+
var i, buffer = [];
|
816
|
+
|
817
|
+
buffer.push("<");
|
818
|
+
buffer.push(element.nodeName.toLowerCase());
|
819
|
+
|
820
|
+
for (i=0; i<element.attributes.length; i++) {
|
821
|
+
buffer.push(" ");
|
822
|
+
buffer.push(element.attributes[i].name);
|
823
|
+
buffer.push("=\"");
|
824
|
+
buffer.push(dom$serialize$$escapeAttribute(element.attributes[i].value));
|
825
|
+
buffer.push("\"");
|
826
|
+
}
|
827
|
+
|
828
|
+
if (dom$serialize$$isVoid(element)) {
|
829
|
+
buffer.push( xhtml ? " />" : ">" );
|
830
|
+
} else {
|
831
|
+
buffer.push(">");
|
832
|
+
|
833
|
+
for (i=0; i<element.childNodes.length; i++) {
|
834
|
+
buffer.push(dom$serialize$$serialize(element.childNodes[i], xhtml, element));
|
835
|
+
}
|
836
|
+
|
837
|
+
buffer.push("</");
|
838
|
+
buffer.push(element.nodeName.toLowerCase());
|
839
|
+
buffer.push(">");
|
840
|
+
}
|
841
|
+
|
842
|
+
return buffer.join("");
|
843
|
+
}
|
844
|
+
|
845
|
+
function dom$serialize$$serialize(node, xhtml, context) {
|
846
|
+
switch(node.nodeType) {
|
847
|
+
case Node.DOCUMENT_NODE:
|
848
|
+
return dom$serialize$$serialize(node.documentElement, xhtml);
|
849
|
+
|
850
|
+
case Node.ELEMENT_NODE:
|
851
|
+
return dom$serialize$$elementToString(node, xhtml);
|
852
|
+
|
853
|
+
case Node.TEXT_NODE:
|
854
|
+
if (context && context.nodeName.toLowerCase() === "style") {
|
855
|
+
return dom$serialize$$escapeStyleTag(node.nodeValue);
|
856
|
+
} else {
|
857
|
+
return dom$serialize$$escapeHTML(node.nodeValue);
|
858
|
+
}
|
859
|
+
|
860
|
+
case Node.COMMENT_NODE:
|
861
|
+
return "<!--" + dom$serialize$$escapeComment(node.nodeValue) + "-->";
|
862
|
+
|
863
|
+
default:
|
864
|
+
return "";
|
865
|
+
}
|
866
|
+
}
|
867
|
+
var dom$serialize$$default = dom$serialize$$serialize;
|
868
|
+
function utils$interface$$Interface(name, properties) {
|
869
|
+
if (properties.hasOwnProperty("constructor")) {
|
870
|
+
throw "An interface cannot have a `constructor` property";
|
871
|
+
}
|
872
|
+
|
873
|
+
var required = [], lazy = [];
|
874
|
+
|
875
|
+
function __Interface__(obj) {
|
876
|
+
if (obj instanceof __Interface__) {
|
877
|
+
return obj;
|
878
|
+
} else if (this instanceof __Interface__) {
|
879
|
+
for (var key in obj) {
|
880
|
+
if (obj.hasOwnProperty(key)) {
|
881
|
+
this[key] = obj[key];
|
882
|
+
}
|
883
|
+
}
|
884
|
+
|
885
|
+
utils$object$$initializeLazyProperties(this, lazy);
|
886
|
+
utils$object$$ensureRequired(this, required);
|
887
|
+
} else {
|
888
|
+
return new __Interface__(obj);
|
889
|
+
}
|
890
|
+
}
|
891
|
+
|
892
|
+
__Interface__.prototype = utils$create$$default(utils$interface$$Interface.prototype);
|
893
|
+
|
894
|
+
__Interface__.prototype.constructor = __Interface__;
|
895
|
+
|
896
|
+
__Interface__.superclass = utils$interface$$Interface;
|
897
|
+
|
898
|
+
__Interface__.__interface__ = true;
|
899
|
+
|
900
|
+
__Interface__.__name__ = name;
|
901
|
+
|
902
|
+
__Interface__.toString = function() {
|
903
|
+
return name;
|
904
|
+
};
|
905
|
+
|
906
|
+
for (var key in properties) {
|
907
|
+
if (properties.hasOwnProperty(key)) {
|
908
|
+
__Interface__.prototype[key] = properties[key];
|
909
|
+
|
910
|
+
if(properties[key] === utils$object$$REQUIRED) {
|
911
|
+
required.push(key);
|
912
|
+
} else if (properties[key] instanceof utils$object$$LAZY) {
|
913
|
+
lazy.push(key);
|
914
|
+
}
|
915
|
+
}
|
916
|
+
}
|
917
|
+
|
918
|
+
return __Interface__;
|
919
|
+
}
|
920
|
+
|
921
|
+
var utils$interface$$default = utils$interface$$Interface;
|
922
|
+
|
923
|
+
utils$interface$$Interface.prototype = {};
|
924
|
+
|
925
|
+
utils$interface$$Interface.superclass = Object;
|
926
|
+
|
927
|
+
utils$interface$$Interface.__name__ = "Interface";
|
928
|
+
|
929
|
+
utils$interface$$Interface.toString = function() {
|
930
|
+
return "Interface";
|
931
|
+
};
|
932
|
+
|
933
|
+
utils$interface$$Interface.extend = function(name, props) {
|
934
|
+
return utils$interface$$Interface(name, props);
|
935
|
+
};
|
936
|
+
|
937
|
+
var template$layout$$default = utils$interface$$default("Layout", {
|
938
|
+
|
939
|
+
/**
|
940
|
+
* The root element of the layout. Must be an acceptable `documentElement` for
|
941
|
+
* the specified `doctype`.
|
942
|
+
*
|
943
|
+
* @property element
|
944
|
+
* @type Element
|
945
|
+
* @required
|
946
|
+
*/
|
947
|
+
element: utils$object$$REQUIRED,
|
948
|
+
|
949
|
+
/**
|
950
|
+
* The main container that content blocks can be inserted into.
|
951
|
+
*
|
952
|
+
* @property container
|
953
|
+
* @type Container
|
954
|
+
* @required
|
955
|
+
*/
|
956
|
+
container: utils$object$$REQUIRED,
|
957
|
+
|
958
|
+
/**
|
959
|
+
* The editable elements in the layout. These elements should be a child of
|
960
|
+
* `element` (or `element` itself) and they should not overlap (i.e. editable
|
961
|
+
* elements cannot be nested).
|
962
|
+
*
|
963
|
+
* @property editables
|
964
|
+
* @type Editable[]
|
965
|
+
* @default []
|
966
|
+
*/
|
967
|
+
editables: utils$object$$LAZY(Array)
|
968
|
+
|
969
|
+
});
|
970
|
+
|
971
|
+
var template$block$$default = utils$interface$$default("Block", {
|
972
|
+
|
973
|
+
/**
|
974
|
+
* The type of the block.
|
975
|
+
*
|
976
|
+
* @property type
|
977
|
+
* @type String
|
978
|
+
* @required
|
979
|
+
*/
|
980
|
+
type: utils$object$$REQUIRED,
|
981
|
+
|
982
|
+
/**
|
983
|
+
* The root element of the content block. Must be a block-level element.
|
984
|
+
*
|
985
|
+
* @property element
|
986
|
+
* @type Element
|
987
|
+
* @required
|
988
|
+
*/
|
989
|
+
element: utils$object$$REQUIRED,
|
990
|
+
|
991
|
+
/**
|
992
|
+
* The editable elements in the block. These elements should be a child of
|
993
|
+
* `element` (or `element` itself) and they should not overlap (i.e. editable
|
994
|
+
* elements cannot be nested).
|
995
|
+
*
|
996
|
+
* @property editables
|
997
|
+
* @type Editable[]
|
998
|
+
* @default []
|
999
|
+
*/
|
1000
|
+
editables: utils$object$$LAZY(Array)
|
1001
|
+
|
1002
|
+
});
|
1003
|
+
|
1004
|
+
var template$editable$$default = utils$interface$$default("Editable", {
|
1005
|
+
|
1006
|
+
/**
|
1007
|
+
* An identifier for the editable element.
|
1008
|
+
*
|
1009
|
+
* @property name
|
1010
|
+
* @type String
|
1011
|
+
* @required
|
1012
|
+
*/
|
1013
|
+
name: utils$object$$REQUIRED,
|
1014
|
+
|
1015
|
+
/**
|
1016
|
+
* The type of the editable content.
|
1017
|
+
*
|
1018
|
+
* @property type
|
1019
|
+
* @type String
|
1020
|
+
* @required
|
1021
|
+
*/
|
1022
|
+
type: utils$object$$REQUIRED,
|
1023
|
+
|
1024
|
+
/**
|
1025
|
+
* Options for the editor plugin.
|
1026
|
+
*
|
1027
|
+
* @property options
|
1028
|
+
* @type Object
|
1029
|
+
* @default {}
|
1030
|
+
*/
|
1031
|
+
options: utils$object$$LAZY(Object),
|
1032
|
+
|
1033
|
+
/**
|
1034
|
+
* The editable element.
|
1035
|
+
*
|
1036
|
+
* @property element
|
1037
|
+
* @type Element
|
1038
|
+
* @required
|
1039
|
+
*/
|
1040
|
+
element: utils$object$$REQUIRED
|
1041
|
+
|
1042
|
+
});
|
1043
|
+
|
1044
|
+
var template$container$$default = utils$interface$$default("Container", {
|
1045
|
+
|
1046
|
+
/**
|
1047
|
+
* The root element of the content block. The element should initially be
|
1048
|
+
* empty and it should be a valid parent for block-level elements.
|
1049
|
+
*
|
1050
|
+
* @property element
|
1051
|
+
* @type Element
|
1052
|
+
* @required
|
1053
|
+
*/
|
1054
|
+
element: utils$object$$REQUIRED
|
1055
|
+
|
1056
|
+
});
|
1057
|
+
|
1058
|
+
var views$states$$default = [
|
1059
|
+
{
|
1060
|
+
name: "hasElement",
|
1061
|
+
transitions: [
|
1062
|
+
{
|
1063
|
+
name: "insertElement",
|
1064
|
+
next: "inDOM",
|
1065
|
+
before: "willInsertElement",
|
1066
|
+
after: "didInsertElement"
|
1067
|
+
}
|
1068
|
+
]
|
1069
|
+
},
|
1070
|
+
|
1071
|
+
{
|
1072
|
+
name: "inDOM",
|
1073
|
+
transitions: [
|
1074
|
+
{
|
1075
|
+
name: "detachElement",
|
1076
|
+
next: "detached",
|
1077
|
+
before: "willDetachElement"
|
1078
|
+
},
|
1079
|
+
{
|
1080
|
+
name: "destroyElement",
|
1081
|
+
next: "destroyed",
|
1082
|
+
before: "willDestroyElement",
|
1083
|
+
cascade: true
|
1084
|
+
}
|
1085
|
+
]
|
1086
|
+
},
|
1087
|
+
|
1088
|
+
{
|
1089
|
+
name: "detached",
|
1090
|
+
transitions: [
|
1091
|
+
{
|
1092
|
+
name: "reattachElement",
|
1093
|
+
next: "inDOM",
|
1094
|
+
before: "willReattachElement",
|
1095
|
+
after: "didReattachElement",
|
1096
|
+
},
|
1097
|
+
|
1098
|
+
]
|
1099
|
+
},
|
1100
|
+
|
1101
|
+
{
|
1102
|
+
name: "destroyed"
|
1103
|
+
}
|
1104
|
+
];
|
1105
|
+
|
1106
|
+
/**
|
1107
|
+
* @private
|
1108
|
+
*
|
1109
|
+
* @class State
|
1110
|
+
* @namespace Interface
|
1111
|
+
*/
|
1112
|
+
var views$state$machine$$State = utils$interface$$default("State", {
|
1113
|
+
|
1114
|
+
/**
|
1115
|
+
* @property name
|
1116
|
+
* @type String
|
1117
|
+
* @required
|
1118
|
+
*/
|
1119
|
+
name: utils$object$$REQUIRED,
|
1120
|
+
|
1121
|
+
/**
|
1122
|
+
* @property transitions
|
1123
|
+
* @type Transition[]
|
1124
|
+
* @default []
|
1125
|
+
*/
|
1126
|
+
transitions: utils$object$$LAZY(Array)
|
1127
|
+
|
1128
|
+
});
|
1129
|
+
|
1130
|
+
/**
|
1131
|
+
* @private
|
1132
|
+
*
|
1133
|
+
* @class Transition
|
1134
|
+
* @namespace Interface
|
1135
|
+
*/
|
1136
|
+
var views$state$machine$$Transition = utils$interface$$default("Transition", {
|
1137
|
+
|
1138
|
+
/**
|
1139
|
+
* @property name
|
1140
|
+
* @type String
|
1141
|
+
* @required
|
1142
|
+
*/
|
1143
|
+
name: utils$object$$REQUIRED,
|
1144
|
+
|
1145
|
+
/**
|
1146
|
+
* @property next
|
1147
|
+
* @type String
|
1148
|
+
* @required
|
1149
|
+
*/
|
1150
|
+
next: utils$object$$REQUIRED,
|
1151
|
+
|
1152
|
+
/**
|
1153
|
+
* @property before
|
1154
|
+
* @type String
|
1155
|
+
* @default undefined
|
1156
|
+
*/
|
1157
|
+
before: undefined,
|
1158
|
+
|
1159
|
+
/**
|
1160
|
+
* @property after
|
1161
|
+
* @type String
|
1162
|
+
* @default undefined
|
1163
|
+
*/
|
1164
|
+
after: undefined,
|
1165
|
+
|
1166
|
+
/**
|
1167
|
+
* @property cascade
|
1168
|
+
* @type Boolean
|
1169
|
+
* @default false
|
1170
|
+
*/
|
1171
|
+
cascade: utils$object$$LAZY(Boolean)
|
1172
|
+
|
1173
|
+
});
|
1174
|
+
|
1175
|
+
function views$state$machine$$setState(newState) {
|
1176
|
+
this.state = newState;
|
1177
|
+
}
|
1178
|
+
|
1179
|
+
function views$state$machine$$apply(instance, method, args) {
|
1180
|
+
if (typeof method !== "function") {
|
1181
|
+
method = instance[method];
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
if (args && args.length) {
|
1185
|
+
return method.apply(instance, [].slice.call(args));
|
1186
|
+
} else {
|
1187
|
+
return method.call(instance);
|
1188
|
+
}
|
1189
|
+
}
|
1190
|
+
|
1191
|
+
function views$state$machine$$applyPreOrder(instance, method, args) {
|
1192
|
+
var childViews = instance.childViews;
|
1193
|
+
|
1194
|
+
for (var i=0; i<childViews.length; i++) {
|
1195
|
+
views$state$machine$$applyPreOrder(childViews[i], method, args);
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
return views$state$machine$$apply(instance, method, args);
|
1199
|
+
}
|
1200
|
+
|
1201
|
+
function views$state$machine$$makeTransition(state, transition) {
|
1202
|
+
return function() {
|
1203
|
+
var rtn;
|
1204
|
+
|
1205
|
+
if (this.state !== state.name) {
|
1206
|
+
throw "Cannot call " + transition.name + " from the " + this.state + " state: " + this.toString();
|
1207
|
+
}
|
1208
|
+
|
1209
|
+
if (transition.before) {
|
1210
|
+
views$state$machine$$applyPreOrder(this, transition.before);
|
1211
|
+
}
|
1212
|
+
|
1213
|
+
if (transition.cascade) {
|
1214
|
+
rtn = views$state$machine$$applyPreOrder(this, "_" + transition.name, arguments);
|
1215
|
+
} else {
|
1216
|
+
rtn = views$state$machine$$apply(this, "_" + transition.name, arguments);
|
1217
|
+
}
|
1218
|
+
|
1219
|
+
views$state$machine$$applyPreOrder(this, views$state$machine$$setState, [transition.next]);
|
1220
|
+
|
1221
|
+
if (transition.after) {
|
1222
|
+
views$state$machine$$applyPreOrder(this, transition.after);
|
1223
|
+
}
|
1224
|
+
|
1225
|
+
return rtn;
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
var views$state$machine$$default = function(states, klass) {
|
1230
|
+
if (states.length === 0) {
|
1231
|
+
throw "Need at least one state";
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
var rootState = views$state$machine$$State(states[0]);
|
1235
|
+
|
1236
|
+
var protoProps = {};
|
1237
|
+
|
1238
|
+
protoProps.init = function() {
|
1239
|
+
this._super.apply(this, arguments);
|
1240
|
+
this.state = rootState.name;
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
var state, transition;
|
1244
|
+
|
1245
|
+
for (var i=0; i<states.length; i++) {
|
1246
|
+
state = views$state$machine$$State(states[i]);
|
1247
|
+
|
1248
|
+
for (var j=0; j<state.transitions.length; j++) {
|
1249
|
+
transition = views$state$machine$$Transition(state.transitions[j]);
|
1250
|
+
protoProps[transition.name] = views$state$machine$$makeTransition(state, transition);
|
1251
|
+
}
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
return klass.extend(protoProps);
|
1255
|
+
};
|
1256
|
+
|
1257
|
+
function views$view$$NOOP() {}
|
1258
|
+
|
1259
|
+
function views$view$$NULL(value) {
|
1260
|
+
if (typeof value === "undefined") {
|
1261
|
+
return null;
|
1262
|
+
} else {
|
1263
|
+
return value;
|
1264
|
+
}
|
1265
|
+
}
|
1266
|
+
|
1267
|
+
var views$view$$default = views$state$machine$$default(views$states$$default, utils$object$$default.extend({
|
1268
|
+
|
1269
|
+
init: function(element, options, data) {
|
1270
|
+
this.element = element;
|
1271
|
+
this.options = options;
|
1272
|
+
|
1273
|
+
if (views$view$$NULL(data) === null) {
|
1274
|
+
this.data = this.serialize();
|
1275
|
+
} else {
|
1276
|
+
this.data = data;
|
1277
|
+
this.deserialize();
|
1278
|
+
}
|
1279
|
+
},
|
1280
|
+
|
1281
|
+
/**
|
1282
|
+
* The element managed by this view.
|
1283
|
+
*
|
1284
|
+
* @property element
|
1285
|
+
* @type Element
|
1286
|
+
* @required
|
1287
|
+
*/
|
1288
|
+
element: utils$object$$REQUIRED,
|
1289
|
+
|
1290
|
+
/**
|
1291
|
+
* @private
|
1292
|
+
*
|
1293
|
+
* @property parentView
|
1294
|
+
* @type View
|
1295
|
+
* @default null
|
1296
|
+
*/
|
1297
|
+
parentView: null,
|
1298
|
+
|
1299
|
+
/**
|
1300
|
+
* @private
|
1301
|
+
*
|
1302
|
+
* A list of child views managed by this view.
|
1303
|
+
*
|
1304
|
+
* @property childViews
|
1305
|
+
* @type View[]
|
1306
|
+
* @default []
|
1307
|
+
*/
|
1308
|
+
childViews: utils$object$$LAZY(Array),
|
1309
|
+
|
1310
|
+
/**
|
1311
|
+
* @private
|
1312
|
+
*
|
1313
|
+
* Add *view* to the list of managed child views.
|
1314
|
+
*
|
1315
|
+
* @method addChildView
|
1316
|
+
* @param {View} [view] The child view to add.
|
1317
|
+
*/
|
1318
|
+
addChildView: function(view) {
|
1319
|
+
this.childViews.push(view);
|
1320
|
+
view.parentView = this;
|
1321
|
+
},
|
1322
|
+
|
1323
|
+
/**
|
1324
|
+
* @private
|
1325
|
+
*
|
1326
|
+
* Remove *view* from the list of managed child views.
|
1327
|
+
*
|
1328
|
+
* @method removeChildCiew
|
1329
|
+
* @param {View} [view] The child view to remove.
|
1330
|
+
*/
|
1331
|
+
removeChildView: function(view) {
|
1332
|
+
var idx = this.childViews.indexOf(view);
|
1333
|
+
|
1334
|
+
if (idx < 0) {
|
1335
|
+
throw view.toString() + " is not a child view of " + this.toString();
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
this.childViews.splice(idx, 1);
|
1339
|
+
view.parentView = null;
|
1340
|
+
},
|
1341
|
+
|
1342
|
+
/**
|
1343
|
+
* @private
|
1344
|
+
*
|
1345
|
+
* Insert the view's `element` into the given *parent* element before the
|
1346
|
+
* *reference* element. If no reference element is given, the element will be
|
1347
|
+
* inserted at the end of the parent.
|
1348
|
+
*
|
1349
|
+
* @method insertElement
|
1350
|
+
* @param {Element} [parent] The parent element.
|
1351
|
+
* @param {Element} [reference] The reference element.
|
1352
|
+
*/
|
1353
|
+
_insertElement: function(parent, reference) {
|
1354
|
+
parent.insertBefore(this.element, reference || null);
|
1355
|
+
},
|
1356
|
+
|
1357
|
+
/**
|
1358
|
+
* @private
|
1359
|
+
*
|
1360
|
+
* Temporarily detach the element from its parent.
|
1361
|
+
*
|
1362
|
+
* @method detachElement
|
1363
|
+
*/
|
1364
|
+
_detachElement: function() {
|
1365
|
+
this.element.parentNode.removeChild(this.element);
|
1366
|
+
},
|
1367
|
+
|
1368
|
+
/**
|
1369
|
+
* @private
|
1370
|
+
*
|
1371
|
+
* Reattach the view's `element` into the given *parent* element before the
|
1372
|
+
* *reference* element. If no reference element is given, the element will be
|
1373
|
+
* inserted at the end of the parent.
|
1374
|
+
*
|
1375
|
+
* @method reattachElement
|
1376
|
+
* @param {Element} [parent] The parent element.
|
1377
|
+
* @param {Element} [reference] The reference element.
|
1378
|
+
*/
|
1379
|
+
_reattachElement: function(parent, reference) {
|
1380
|
+
this._insertElement(parent, reference);
|
1381
|
+
},
|
1382
|
+
|
1383
|
+
/**
|
1384
|
+
* @private
|
1385
|
+
*
|
1386
|
+
* Destroy a view's element.
|
1387
|
+
*
|
1388
|
+
* @method destroyElement
|
1389
|
+
*/
|
1390
|
+
_destroyElement: function() {
|
1391
|
+
this._detachElement();
|
1392
|
+
this.element = null;
|
1393
|
+
},
|
1394
|
+
|
1395
|
+
/**
|
1396
|
+
* A hook that is called before the view's element has been inserted into the
|
1397
|
+
* DOM.
|
1398
|
+
*
|
1399
|
+
* @method willInsertElement
|
1400
|
+
*/
|
1401
|
+
willInsertElement: views$view$$NOOP,
|
1402
|
+
|
1403
|
+
/**
|
1404
|
+
* A hook that will be called after the view's element has been inserted into
|
1405
|
+
* the DOM.
|
1406
|
+
*
|
1407
|
+
* @method didInsertElement
|
1408
|
+
*/
|
1409
|
+
didInsertElement: views$view$$NOOP,
|
1410
|
+
|
1411
|
+
/**
|
1412
|
+
* A hook that is called before the view's element is temporarily removed from
|
1413
|
+
* the DOM (e.g. before it is moved).
|
1414
|
+
*
|
1415
|
+
* The key difference between this hook and `willDestroyElement` is that the
|
1416
|
+
* removal here is temporary and the same element will be re-inserted into the
|
1417
|
+
* DOM at a later time. Because of that, you typically do not have to remove
|
1418
|
+
* event listeners on the element itself, but if you have setup any listeners
|
1419
|
+
* on the parent view/element, you should remove them here.
|
1420
|
+
*
|
1421
|
+
* @method willDetachElement
|
1422
|
+
*/
|
1423
|
+
willDetachElement: views$view$$NOOP,
|
1424
|
+
|
1425
|
+
/**
|
1426
|
+
* A hook that is called before a view's (previously detached) element is re-
|
1427
|
+
* inserted into the DOM (e.g. after it has been moved).
|
1428
|
+
*
|
1429
|
+
* @method willReattachElement
|
1430
|
+
*/
|
1431
|
+
willReattachElement: views$view$$NOOP,
|
1432
|
+
|
1433
|
+
/**
|
1434
|
+
* A hook that is called after a view's (previously detached) element is re-
|
1435
|
+
* inserted into the DOM (e.g. after it has been moved).
|
1436
|
+
*
|
1437
|
+
* If you removed any listeners in `willDetachElement`, this is the chance to
|
1438
|
+
* set them up again.
|
1439
|
+
*
|
1440
|
+
* @method didReattachElement
|
1441
|
+
*/
|
1442
|
+
didReattachElement: views$view$$NOOP,
|
1443
|
+
|
1444
|
+
/**
|
1445
|
+
* A hook that is called before the view's element is permanently removed from
|
1446
|
+
* the DOM.
|
1447
|
+
*
|
1448
|
+
* You should remove any listeners that you have set up on the element in
|
1449
|
+
* `didInsertElement`, otherwise it might cause a memory leak.
|
1450
|
+
*
|
1451
|
+
* @method willDestroyElement
|
1452
|
+
*/
|
1453
|
+
willDestroyElement: views$view$$NOOP,
|
1454
|
+
|
1455
|
+
deserialize: function() {
|
1456
|
+
if (this.options && this.options.serializer) {
|
1457
|
+
this.options.serializer.deserialize(this.element, this.options, this.data);
|
1458
|
+
}
|
1459
|
+
},
|
1460
|
+
|
1461
|
+
serialize: function() {
|
1462
|
+
if (this.options && this.options.serializer) {
|
1463
|
+
return this.options.serializer.serialize(this.element, this.options);
|
1464
|
+
}
|
1465
|
+
},
|
1466
|
+
|
1467
|
+
serializableChildren: function() {
|
1468
|
+
return this.childViews;
|
1469
|
+
},
|
1470
|
+
|
1471
|
+
toJSON: function() {
|
1472
|
+
var json = {};
|
1473
|
+
|
1474
|
+
if (typeof this.options.role === "string") {
|
1475
|
+
json.role = this.options.role;
|
1476
|
+
}
|
1477
|
+
|
1478
|
+
if (typeof this.options.type === "string") {
|
1479
|
+
json.type = this.options.type;
|
1480
|
+
}
|
1481
|
+
|
1482
|
+
if (typeof this.options.name === "string") {
|
1483
|
+
json.name = this.options.name;
|
1484
|
+
}
|
1485
|
+
|
1486
|
+
json.data = views$view$$NULL(this.serialize());
|
1487
|
+
|
1488
|
+
json.children = [];
|
1489
|
+
|
1490
|
+
this.serializableChildren().forEach(function(child) {
|
1491
|
+
json.children.push(child.toJSON());
|
1492
|
+
});
|
1493
|
+
|
1494
|
+
return json;
|
1495
|
+
}
|
1496
|
+
|
1497
|
+
}));
|
1498
|
+
|
1499
|
+
function views$container$view$$assertIdx(idx, length, insert) {
|
1500
|
+
var max = insert ? length + 1 : length;
|
1501
|
+
|
1502
|
+
if (idx < 0 || idx >= max) {
|
1503
|
+
throw "Index out of range: " + idx;
|
1504
|
+
}
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
var views$container$view$$default = views$view$$default.extend({
|
1508
|
+
|
1509
|
+
init: function(element, options, data) {
|
1510
|
+
this._super(element, options, data);
|
1511
|
+
this.containerElement = this.element;
|
1512
|
+
},
|
1513
|
+
|
1514
|
+
insertChildViewAt: function(view, idx) {
|
1515
|
+
idx = idx || 0;
|
1516
|
+
|
1517
|
+
views$container$view$$assertIdx(idx, this.childViews.length, true);
|
1518
|
+
|
1519
|
+
this.childViews.splice(idx, 0, view);
|
1520
|
+
view.parentView = this;
|
1521
|
+
|
1522
|
+
var referenceElement = this.containerElement.children[idx];
|
1523
|
+
|
1524
|
+
if (this.state === "inDOM") {
|
1525
|
+
view.insertElement(this.containerElement, referenceElement);
|
1526
|
+
} else {
|
1527
|
+
this.containerElement.insertBefore(view.element, referenceElement || null);
|
1528
|
+
}
|
1529
|
+
},
|
1530
|
+
|
1531
|
+
appendChildView: function(view) {
|
1532
|
+
this.insertChildViewAt(view, this.childViews.length);
|
1533
|
+
},
|
1534
|
+
|
1535
|
+
moveChildView: function(fromIdx, toIdx) {
|
1536
|
+
views$container$view$$assertIdx(fromIdx, this.childViews.length);
|
1537
|
+
views$container$view$$assertIdx(toIdx, this.childViews.length);
|
1538
|
+
|
1539
|
+
if (fromIdx === toIdx) {
|
1540
|
+
return;
|
1541
|
+
}
|
1542
|
+
|
1543
|
+
var view = this.childViews.splice(fromIdx, 1)[0];
|
1544
|
+
view.detachElement();
|
1545
|
+
|
1546
|
+
this.childViews.splice(toIdx, 0, view);
|
1547
|
+
view.reattachElement(this.containerElement, this.containerElement.children[toIdx]);
|
1548
|
+
},
|
1549
|
+
|
1550
|
+
removeChildViewAt: function(idx) {
|
1551
|
+
views$container$view$$assertIdx(idx, this.childViews.length);
|
1552
|
+
this.childViews.splice(idx, 1)[0].destroyElement();
|
1553
|
+
}
|
1554
|
+
|
1555
|
+
});
|
1556
|
+
|
1557
|
+
function builder$builder$$ownKeys(object) {
|
1558
|
+
var keys = [];
|
1559
|
+
|
1560
|
+
for (var key in object) {
|
1561
|
+
if (object.hasOwnProperty(key)) {
|
1562
|
+
keys.push(key);
|
1563
|
+
}
|
1564
|
+
}
|
1565
|
+
|
1566
|
+
return keys;
|
1567
|
+
}
|
1568
|
+
|
1569
|
+
function builder$builder$$buildView(element, options, data, lookupPaths, parentView) {
|
1570
|
+
if (!lookupPaths.shift) {
|
1571
|
+
lookupPaths = [lookupPaths];
|
1572
|
+
}
|
1573
|
+
|
1574
|
+
lookupPaths = lookupPaths.slice();
|
1575
|
+
|
1576
|
+
var ViewClass, path;
|
1577
|
+
|
1578
|
+
while (!ViewClass && lookupPaths.length) {
|
1579
|
+
var path = lookupPaths.shift();
|
1580
|
+
|
1581
|
+
if (typeof path === "function") {
|
1582
|
+
ViewClass = path;
|
1583
|
+
} else {
|
1584
|
+
ViewClass = core$$default.registry.lookup(path);
|
1585
|
+
}
|
1586
|
+
}
|
1587
|
+
|
1588
|
+
ViewClass = ViewClass || views$view$$default;
|
1589
|
+
|
1590
|
+
var placeholder;
|
1591
|
+
|
1592
|
+
// If element already has a parent, temporarily remove it so that the view
|
1593
|
+
// has a chance to wrap the element at `init`
|
1594
|
+
if (element.parentNode) {
|
1595
|
+
placeholder = element.cloneNode(false);
|
1596
|
+
element.parentNode.replaceChild(placeholder, element);
|
1597
|
+
}
|
1598
|
+
|
1599
|
+
var view = new ViewClass(element, options, data);
|
1600
|
+
|
1601
|
+
if (placeholder) {
|
1602
|
+
placeholder.parentNode.replaceChild(view.element, placeholder);
|
1603
|
+
}
|
1604
|
+
|
1605
|
+
if (parentView) {
|
1606
|
+
parentView.addChildView(view);
|
1607
|
+
}
|
1608
|
+
|
1609
|
+
return view;
|
1610
|
+
}
|
1611
|
+
|
1612
|
+
function builder$builder$$buildBlock(document, template, type, data, env, headless) {
|
1613
|
+
var factory = template.blocks[type];
|
1614
|
+
|
1615
|
+
if (typeof factory !== "function") {
|
1616
|
+
throw "The template does not define the block " + type;
|
1617
|
+
}
|
1618
|
+
|
1619
|
+
var block = template$block$$default( factory.call(template, new dom$dom$builder$$default(document), env) );
|
1620
|
+
|
1621
|
+
var view = builder$builder$$buildView(
|
1622
|
+
block.element,
|
1623
|
+
{
|
1624
|
+
role: "block",
|
1625
|
+
type: type
|
1626
|
+
},
|
1627
|
+
data && data.data,
|
1628
|
+
headless ? [] : ["view:block/" + type, "view:block"]
|
1629
|
+
);
|
1630
|
+
|
1631
|
+
builder$builder$$initializeEditors(block.editables, view, data, headless);
|
1632
|
+
|
1633
|
+
return view;
|
1634
|
+
}
|
1635
|
+
|
1636
|
+
function builder$builder$$findData(data, options) {
|
1637
|
+
if (data && data.children.length) {
|
1638
|
+
var entry;
|
1639
|
+
|
1640
|
+
for (var i=0; i<data.children.length; i++) {
|
1641
|
+
entry = data.children[i];
|
1642
|
+
|
1643
|
+
if (typeof options.role === "string" && entry.role != options.role) {
|
1644
|
+
continue;
|
1645
|
+
}
|
1646
|
+
|
1647
|
+
if (typeof options.type === "string" && entry.type != options.type) {
|
1648
|
+
continue;
|
1649
|
+
}
|
1650
|
+
|
1651
|
+
if (typeof options.name === "string" && entry.name != options.name) {
|
1652
|
+
continue;
|
1653
|
+
}
|
1654
|
+
|
1655
|
+
return entry;
|
1656
|
+
}
|
1657
|
+
}
|
1658
|
+
}
|
1659
|
+
|
1660
|
+
function builder$builder$$initializeEditors(editables, parentView, data, headless) {
|
1661
|
+
editables.forEach(function(editable) {
|
1662
|
+
var editable = template$editable$$default(editable);
|
1663
|
+
|
1664
|
+
var serializer = core$$default.registry.lookup("serializer:" + editable.type);
|
1665
|
+
|
1666
|
+
if (!serializer) {
|
1667
|
+
core$$default.logger.error("No serializer were registered to handle " + editable.type);
|
1668
|
+
return;
|
1669
|
+
}
|
1670
|
+
|
1671
|
+
var options = {};
|
1672
|
+
|
1673
|
+
for (var key in editable.options) {
|
1674
|
+
if (editable.options.hasOwnProperty(key)) {
|
1675
|
+
options[key] = editable.options[key];
|
1676
|
+
}
|
1677
|
+
}
|
1678
|
+
|
1679
|
+
options.role = "editable";
|
1680
|
+
options.type = editable.type;
|
1681
|
+
options.name = editable.name;
|
1682
|
+
options.serializer = serializer;
|
1683
|
+
|
1684
|
+
var editorData = builder$builder$$findData(data, options);
|
1685
|
+
|
1686
|
+
builder$builder$$buildView(editable.element, options, editorData && editorData.data, headless ? [] : ["view:editor/" + editable.type], parentView);
|
1687
|
+
});
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
function builder$builder$$initializeBlocks(builder, data) {
|
1691
|
+
if (data && data.children.length) {
|
1692
|
+
var entry;
|
1693
|
+
|
1694
|
+
for (var i=0; i<data.children.length; i++) {
|
1695
|
+
entry = data.children[i];
|
1696
|
+
|
1697
|
+
if (entry.role === "block") {
|
1698
|
+
builder.appendBlock(entry.type, entry);
|
1699
|
+
}
|
1700
|
+
}
|
1701
|
+
}
|
1702
|
+
}
|
1703
|
+
|
1704
|
+
/**
|
1705
|
+
* @class Builder
|
1706
|
+
* @namespace Bob
|
1707
|
+
* @param {String} [templateKey] The lookup key of the template to build from.
|
1708
|
+
* @param {Document} [document] The `Document` to build on. If not provided, a
|
1709
|
+
* fresh document will be created.
|
1710
|
+
*/
|
1711
|
+
var builder$builder$$Builder = utils$object$$default.extend({
|
1712
|
+
|
1713
|
+
init: function(template, window, data, env) {
|
1714
|
+
var templateKey;
|
1715
|
+
|
1716
|
+
if (typeof template === "string") {
|
1717
|
+
templateKey = template;
|
1718
|
+
template = core$$default.registry.lookup("template:" + templateKey);
|
1719
|
+
}
|
1720
|
+
|
1721
|
+
if (!template) {
|
1722
|
+
throw "Template not found: " + templateKey;
|
1723
|
+
}
|
1724
|
+
|
1725
|
+
if (window) {
|
1726
|
+
this.headless = false;
|
1727
|
+
this.contentWindow = window;
|
1728
|
+
this.contentDocument = dom$document$$prepareDocument(window.document);
|
1729
|
+
} else {
|
1730
|
+
this.headless = true;
|
1731
|
+
this.contentWindow = null;
|
1732
|
+
this.contentDocument = dom$document$$createDocument();
|
1733
|
+
}
|
1734
|
+
|
1735
|
+
if (env instanceof utils$hash$lookup$$default) {
|
1736
|
+
this.env = env;
|
1737
|
+
} else {
|
1738
|
+
this.env = new utils$hash$lookup$$default(env);
|
1739
|
+
}
|
1740
|
+
|
1741
|
+
/**
|
1742
|
+
* The block types supported by the template.
|
1743
|
+
*
|
1744
|
+
* @property supportedBlockTypes
|
1745
|
+
* @type String[]
|
1746
|
+
*/
|
1747
|
+
this.supportedBlockTypes = builder$builder$$ownKeys(template.blocks);
|
1748
|
+
|
1749
|
+
var doc = this.contentDocument;
|
1750
|
+
|
1751
|
+
var layout = template$layout$$default( template.layout( new dom$dom$builder$$default(doc), this.env ) );
|
1752
|
+
|
1753
|
+
var layoutData = builder$builder$$findData(data, { role: "layout" });
|
1754
|
+
|
1755
|
+
var layoutView = builder$builder$$buildView(
|
1756
|
+
layout.element,
|
1757
|
+
{ role: "layout" },
|
1758
|
+
layoutData && layout.data,
|
1759
|
+
this.headless ? [] : ["view:layout"]
|
1760
|
+
);
|
1761
|
+
|
1762
|
+
builder$builder$$initializeEditors(layout.editables, layoutView, layoutData, this.headless);
|
1763
|
+
|
1764
|
+
var container = template$container$$default( layout.container );
|
1765
|
+
|
1766
|
+
var containerData = builder$builder$$findData(layoutData, { role: "container" });
|
1767
|
+
|
1768
|
+
var containerView = builder$builder$$buildView(
|
1769
|
+
container.element,
|
1770
|
+
{ role: "container" },
|
1771
|
+
containerData && containerData.data,
|
1772
|
+
this.headless ? views$container$view$$default : ["view:container", views$container$view$$default],
|
1773
|
+
layoutView
|
1774
|
+
);
|
1775
|
+
|
1776
|
+
this.template = template;
|
1777
|
+
this.layoutView = layoutView;
|
1778
|
+
this.containerView = containerView;
|
1779
|
+
|
1780
|
+
builder$builder$$initializeBlocks(this, containerData);
|
1781
|
+
|
1782
|
+
layoutView.insertElement(doc);
|
1783
|
+
},
|
1784
|
+
|
1785
|
+
blocks: utils$object$$LAZY(Array),
|
1786
|
+
|
1787
|
+
/**
|
1788
|
+
* Insert a new block of *type* to the main container at the specific index.
|
1789
|
+
* If the given index is out-of-range an error will be thrown.
|
1790
|
+
*
|
1791
|
+
* @method insertBlock
|
1792
|
+
* @param {String} [type] The block type.
|
1793
|
+
* @param {Integer} [idx=0] The index to insert at.
|
1794
|
+
*/
|
1795
|
+
insertBlock: function(type, idx, data) {
|
1796
|
+
var block = builder$builder$$buildBlock(this.contentDocument, this.template, type, data, this.env, this.headless);
|
1797
|
+
this.containerView.insertChildViewAt(block, idx);
|
1798
|
+
},
|
1799
|
+
|
1800
|
+
/**
|
1801
|
+
* Append a new block of *type* to the end of the main container.
|
1802
|
+
*
|
1803
|
+
* @method appendBlock
|
1804
|
+
* @param {String} [type] The block type.
|
1805
|
+
*/
|
1806
|
+
appendBlock: function(type, data) {
|
1807
|
+
var block = builder$builder$$buildBlock(this.contentDocument, this.template, type, data, this.env, this.headless);
|
1808
|
+
this.containerView.appendChildView(block);
|
1809
|
+
},
|
1810
|
+
|
1811
|
+
/**
|
1812
|
+
* Move an existing block within the main container. If either of the indices
|
1813
|
+
* are out-of-range, an error will be thrown.
|
1814
|
+
*
|
1815
|
+
* @method moveBlock
|
1816
|
+
* @param {Integer} [fromIdx] The current index of the block.
|
1817
|
+
* @param {Integer} [toIdx] The new index of the block.
|
1818
|
+
*/
|
1819
|
+
moveBlock: function(fromIdx, toIdx) {
|
1820
|
+
this.containerView.moveChildView(fromIdx, toIdx);
|
1821
|
+
},
|
1822
|
+
|
1823
|
+
/**
|
1824
|
+
* Remove an existing block from the main container. Any views and
|
1825
|
+
* editors associated with the block will be deactivated and then destroyed.
|
1826
|
+
* If the given index is out-of-range an error will be thrown.
|
1827
|
+
*
|
1828
|
+
* @method removeBlock
|
1829
|
+
* @param {Integer} [idx] The index of the block.
|
1830
|
+
*/
|
1831
|
+
removeBlock: function(idx) {
|
1832
|
+
this.containerView.removeChildViewAt(idx);
|
1833
|
+
},
|
1834
|
+
|
1835
|
+
/**
|
1836
|
+
* Teardown the builder.
|
1837
|
+
*
|
1838
|
+
* @method destroy
|
1839
|
+
*/
|
1840
|
+
destroy: function() {
|
1841
|
+
this.layoutView.destroyElement();
|
1842
|
+
|
1843
|
+
dom$document$$prepareDocument(this.contentDocument);
|
1844
|
+
|
1845
|
+
this.contentWindow = null;
|
1846
|
+
this.contentDocument = null;
|
1847
|
+
this.layoutView = null;
|
1848
|
+
this.containerView = null;
|
1849
|
+
},
|
1850
|
+
|
1851
|
+
/**
|
1852
|
+
* Refresh the builder with an updated env hash.
|
1853
|
+
*
|
1854
|
+
* @method refresh
|
1855
|
+
* @params {Object} [env] The updated env hash.
|
1856
|
+
*/
|
1857
|
+
refresh: function(env) {
|
1858
|
+
var template = this.template,
|
1859
|
+
window = this.contentWindow,
|
1860
|
+
data = this.toJSON(),
|
1861
|
+
env = env || this.env;
|
1862
|
+
|
1863
|
+
this.destroy();
|
1864
|
+
|
1865
|
+
this.init(template, window, data, env);
|
1866
|
+
},
|
1867
|
+
|
1868
|
+
toJSON: function() {
|
1869
|
+
return {
|
1870
|
+
data: { version: 0 },
|
1871
|
+
children: [
|
1872
|
+
this.layoutView.toJSON()
|
1873
|
+
]
|
1874
|
+
};
|
1875
|
+
},
|
1876
|
+
|
1877
|
+
toHTML: function() {
|
1878
|
+
var headless = new builder$builder$$Builder(this.template, null, this.toJSON(), this.env);
|
1879
|
+
var root = headless.contentDocument.documentElement;
|
1880
|
+
|
1881
|
+
if (this.template.doctype) {
|
1882
|
+
return this.template.doctype + "\n" + dom$serialize$$default(root);
|
1883
|
+
} else {
|
1884
|
+
return dom$serialize$$default(root);
|
1885
|
+
}
|
1886
|
+
}
|
1887
|
+
|
1888
|
+
});
|
1889
|
+
|
1890
|
+
var builder$builder$$default = builder$builder$$Builder;
|
1891
|
+
|
1892
|
+
/**
|
1893
|
+
* Describes a template.
|
1894
|
+
*
|
1895
|
+
* @class Template
|
1896
|
+
* @namespace Interface
|
1897
|
+
*/
|
1898
|
+
var template$template$$Template = utils$interface$$default("Template", {
|
1899
|
+
|
1900
|
+
/**
|
1901
|
+
* The doctype of the template.
|
1902
|
+
*
|
1903
|
+
* @property doctype
|
1904
|
+
* @type String
|
1905
|
+
* @default null
|
1906
|
+
*/
|
1907
|
+
doctype: null,
|
1908
|
+
|
1909
|
+
/**
|
1910
|
+
* A display name for the template.
|
1911
|
+
*
|
1912
|
+
* @property name
|
1913
|
+
* @type String
|
1914
|
+
* @required
|
1915
|
+
*/
|
1916
|
+
name: utils$object$$REQUIRED,
|
1917
|
+
|
1918
|
+
/**
|
1919
|
+
* A factory function to build the template's layout.
|
1920
|
+
*
|
1921
|
+
* @method layout
|
1922
|
+
* @param {Document} [document] The `document` object to use.
|
1923
|
+
* @return {Layout} The layout that was built.
|
1924
|
+
* @required
|
1925
|
+
*/
|
1926
|
+
layout: utils$object$$REQUIRED,
|
1927
|
+
|
1928
|
+
/**
|
1929
|
+
* An object containing the blocks supported by the template keyed by their
|
1930
|
+
* types. The functions should take a `Document` object as argument and return
|
1931
|
+
* a `Block`.
|
1932
|
+
*
|
1933
|
+
* @property blocks
|
1934
|
+
* @type Object
|
1935
|
+
* @default {}
|
1936
|
+
*/
|
1937
|
+
blocks: utils$object$$LAZY(Object)
|
1938
|
+
|
1939
|
+
});
|
1940
|
+
|
1941
|
+
var template$template$$default = template$template$$Template;
|
1942
|
+
function template$template$$registerTemplate(key, template) {
|
1943
|
+
key = "template:" + key;
|
1944
|
+
template = template$template$$Template(template);
|
1945
|
+
|
1946
|
+
core$$default.register(key, template);
|
1947
|
+
}
|
1948
|
+
|
1949
|
+
/**
|
1950
|
+
* Exports all public classes and functions.
|
1951
|
+
*/
|
1952
|
+
|
1953
|
+
function bob$$exportAs(name, value) {
|
1954
|
+
core$$default[name] = value;
|
1955
|
+
|
1956
|
+
if(value.__class__) {
|
1957
|
+
value.__name__ = "Bob." + name;
|
1958
|
+
}
|
1959
|
+
}
|
1960
|
+
|
1961
|
+
bob$$exportAs("Logger", utils$logger$$default);
|
1962
|
+
|
1963
|
+
bob$$exportAs("Object", utils$object$$default);
|
1964
|
+
bob$$exportAs("REQUIRED", utils$object$$REQUIRED);
|
1965
|
+
bob$$exportAs("LAZY", utils$object$$LAZY);
|
1966
|
+
|
1967
|
+
bob$$exportAs("Builder", builder$builder$$default);
|
1968
|
+
|
1969
|
+
bob$$exportAs("registerTemplate", template$template$$registerTemplate);
|
1970
|
+
|
1971
|
+
bob$$exportAs("View", views$view$$default);
|
1972
|
+
|
1973
|
+
bob$$exportAs("ContainerView", views$container$view$$default);
|
1974
|
+
|
1975
|
+
bob$$exportAs("DomBuilder", dom$dom$builder$$default);
|
1976
|
+
|
1977
|
+
bob$$exportAs("HashLookup", utils$hash$lookup$$default);
|
1978
|
+
|
1979
|
+
// Global export
|
1980
|
+
this.Bob = core$$default;
|
1981
|
+
|
1982
|
+
var bob$$default = core$$default;
|
1983
|
+
|
1984
|
+
var utils$required$$default = {
|
1985
|
+
toString: function() {
|
1986
|
+
return "(Required Property)";
|
1987
|
+
}
|
1988
|
+
};
|
1989
|
+
}).call(this);
|