mindreframer-riemann-dash 0.2.3
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/.gitignore +8 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +52 -0
- data/LICENSE +21 -0
- data/README.markdown +52 -0
- data/Rakefile.rb +11 -0
- data/bin/riemann-dash +7 -0
- data/example/config.rb +17 -0
- data/lib/riemann/dash.rb +5 -0
- data/lib/riemann/dash/app.rb +32 -0
- data/lib/riemann/dash/config.rb +154 -0
- data/lib/riemann/dash/controller/css.rb +5 -0
- data/lib/riemann/dash/controller/index.rb +20 -0
- data/lib/riemann/dash/public/clock.js +45 -0
- data/lib/riemann/dash/public/dash.js +287 -0
- data/lib/riemann/dash/public/format.js +24 -0
- data/lib/riemann/dash/public/jquery-1.7.2.min.js +4 -0
- data/lib/riemann/dash/public/jquery-ui-1.9.0.custom.min.js +6 -0
- data/lib/riemann/dash/public/jquery.json-2.2.min.js +31 -0
- data/lib/riemann/dash/public/jquery.quickfit.js +144 -0
- data/lib/riemann/dash/public/jquery.simplemodal.1.4.3.min.js +26 -0
- data/lib/riemann/dash/public/keys.js +46 -0
- data/lib/riemann/dash/public/mustache.js +597 -0
- data/lib/riemann/dash/public/persistence.js +30 -0
- data/lib/riemann/dash/public/profile.js +33 -0
- data/lib/riemann/dash/public/subs.js +164 -0
- data/lib/riemann/dash/public/toastr.css +174 -0
- data/lib/riemann/dash/public/toastr.js +207 -0
- data/lib/riemann/dash/public/toolbar.js +217 -0
- data/lib/riemann/dash/public/underscore-min.js +5 -0
- data/lib/riemann/dash/public/util.js +34 -0
- data/lib/riemann/dash/public/vendor/smoothie.js +374 -0
- data/lib/riemann/dash/public/view.js +704 -0
- data/lib/riemann/dash/public/views/gauge.js +76 -0
- data/lib/riemann/dash/public/views/grid.js +279 -0
- data/lib/riemann/dash/public/views/help.js +28 -0
- data/lib/riemann/dash/public/views/timeseries.js +107 -0
- data/lib/riemann/dash/public/views/title.js +35 -0
- data/lib/riemann/dash/public/x.png +0 -0
- data/lib/riemann/dash/rack/static.rb +16 -0
- data/lib/riemann/dash/version.rb +4 -0
- data/lib/riemann/dash/views/css.scss +393 -0
- data/lib/riemann/dash/views/index.erubis +203 -0
- data/lib/riemann/dash/views/layout.erubis +21 -0
- data/riemann-dash.gemspec +28 -0
- data/sh/c +1 -0
- data/sh/env.rb +2 -0
- data/sh/test +1 -0
- data/test/config_test.rb +106 -0
- data/test/fixtures/config/basic_config.rb +2 -0
- data/test/fixtures/config/ws_config.rb +1 -0
- data/test/fixtures/ws_config/dummy_config.json +1 -0
- data/test/fixtures/ws_config/pretty_printed_config.json +6 -0
- data/test/test_helper.rb +10 -0
- metadata +202 -0
@@ -0,0 +1,704 @@
|
|
1
|
+
var view = (function() {
|
2
|
+
var types = {};
|
3
|
+
var focused = null;
|
4
|
+
var focusOverlay = $('<div class="focusOverlay"></div>');
|
5
|
+
$('body').append(focusOverlay);
|
6
|
+
|
7
|
+
// Unfocus all views.
|
8
|
+
var unfocus = function() {
|
9
|
+
if (focused) {
|
10
|
+
focused.unfocus();
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
function createObject(parent) {
|
15
|
+
function TempClass() {}
|
16
|
+
TempClass.prototype = parent;
|
17
|
+
var child = new TempClass();
|
18
|
+
return child;
|
19
|
+
}
|
20
|
+
|
21
|
+
function inherit(sup, sub) {
|
22
|
+
var newSubPrototype = createObject(sup.prototype);
|
23
|
+
newSubPrototype.constructor = sub;
|
24
|
+
sub.prototype = newSubPrototype;
|
25
|
+
}
|
26
|
+
|
27
|
+
// Create *some* type of view from json
|
28
|
+
var reify = function(json) {
|
29
|
+
var t = types[json.type];
|
30
|
+
return(new t(json));
|
31
|
+
}
|
32
|
+
|
33
|
+
// Initialize keybindings
|
34
|
+
function setKeyBindings() {
|
35
|
+
var focusedBindings = {
|
36
|
+
// left
|
37
|
+
37: function(ev) {
|
38
|
+
if (ev.ctrlKey === true) {
|
39
|
+
focused.split('HStack', -1);
|
40
|
+
} else {
|
41
|
+
focused.moveHorizontal(-1);
|
42
|
+
}
|
43
|
+
},
|
44
|
+
|
45
|
+
// up
|
46
|
+
38: function(ev) {
|
47
|
+
if (ev.ctrlKey === true) {
|
48
|
+
focused.split('VStack', -1);
|
49
|
+
} else {
|
50
|
+
focused.moveVertical(-1);
|
51
|
+
}
|
52
|
+
},
|
53
|
+
|
54
|
+
// right
|
55
|
+
39: function(ev) {
|
56
|
+
if (ev.ctrlKey === true) {
|
57
|
+
focused.split('HStack', 1);
|
58
|
+
} else {
|
59
|
+
focused.moveHorizontal(1);
|
60
|
+
}
|
61
|
+
},
|
62
|
+
|
63
|
+
// down
|
64
|
+
40: function(ev) {
|
65
|
+
if (ev.ctrlKey === true) {
|
66
|
+
focused.split('VStack', 1);
|
67
|
+
} else {
|
68
|
+
focused.moveVertical(1);
|
69
|
+
}
|
70
|
+
},
|
71
|
+
|
72
|
+
27: function() { focused.unfocus() }, // escape
|
73
|
+
33: function() { if (focused.parent) { // pgup
|
74
|
+
focused.parent.focus();
|
75
|
+
} },
|
76
|
+
46: function() { focused.delete() }, // delete
|
77
|
+
68: function() { focused.delete() }, // d
|
78
|
+
|
79
|
+
69: function() { focused.edit() }, // e
|
80
|
+
86: function() { focused.split('VStack', 1) }, // v
|
81
|
+
72: function() { focused.split('HStack', 1) }, // h
|
82
|
+
|
83
|
+
187: function() { focused.grow(); }, // +
|
84
|
+
189: function() { focused.shrink(); } // -
|
85
|
+
|
86
|
+
};
|
87
|
+
|
88
|
+
var bindings = {};
|
89
|
+
|
90
|
+
// Set up focused bindings.
|
91
|
+
for (code in focusedBindings) {
|
92
|
+
(function(f) {
|
93
|
+
keys.bind(code, function(ev) {
|
94
|
+
if (focused) { f(ev) }
|
95
|
+
});
|
96
|
+
})(focusedBindings[code]);
|
97
|
+
}
|
98
|
+
|
99
|
+
// Set up unfocused bindings.
|
100
|
+
for (code in bindings) {
|
101
|
+
(function(f) {
|
102
|
+
keys.bind(code, function(ev) {
|
103
|
+
if (! focused) { f(ev) }
|
104
|
+
});
|
105
|
+
})(bindings[code]);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
setKeyBindings()
|
109
|
+
|
110
|
+
// View ////////////////////////////////////////////////////////////////////
|
111
|
+
|
112
|
+
var View = function(json) {
|
113
|
+
this.type = json.type;
|
114
|
+
this.el = $('<div class="view">');
|
115
|
+
this.weight = json.weight || 1;
|
116
|
+
// this.el.css('background', 'rgb(' +
|
117
|
+
// Math.floor(Math.random() * 256) + ',' +
|
118
|
+
// Math.floor(Math.random() * 256) + ',' +
|
119
|
+
// Math.floor(Math.random() * 256) + ')');
|
120
|
+
|
121
|
+
var self = this;
|
122
|
+
this.clickFocusable = true;
|
123
|
+
this.el.click(function() {
|
124
|
+
if (self.clickFocusable) {
|
125
|
+
self.focus();
|
126
|
+
}
|
127
|
+
});
|
128
|
+
};
|
129
|
+
types.View = View;
|
130
|
+
|
131
|
+
View.prototype.width = function(w) {
|
132
|
+
if (w !== undefined) {
|
133
|
+
return this.el.width(w);
|
134
|
+
} else {
|
135
|
+
return this.el.width();
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
View.prototype.height = function(h) {
|
140
|
+
if (h !== undefined) {
|
141
|
+
return this.el.height(h);
|
142
|
+
} else {
|
143
|
+
return this.el.height();
|
144
|
+
}
|
145
|
+
};
|
146
|
+
|
147
|
+
View.prototype.top = function(t) {
|
148
|
+
if(t !== undefined) {
|
149
|
+
return this.el.css("top", t);
|
150
|
+
} else {
|
151
|
+
return this.el.css("top");
|
152
|
+
}
|
153
|
+
};
|
154
|
+
|
155
|
+
View.prototype.left = function(l) {
|
156
|
+
if (l !== undefined) {
|
157
|
+
return this.el.css("left", l);
|
158
|
+
} else {
|
159
|
+
return this.el.css("left");
|
160
|
+
}
|
161
|
+
};
|
162
|
+
|
163
|
+
View.prototype.reflow = function() {
|
164
|
+
};
|
165
|
+
|
166
|
+
View.prototype.grow = function() {
|
167
|
+
this.weight *= 2;
|
168
|
+
this.parent.reflow();
|
169
|
+
focused.refocus();
|
170
|
+
};
|
171
|
+
|
172
|
+
View.prototype.shrink = function() {
|
173
|
+
this.weight *= 0.5;
|
174
|
+
this.parent.reflow();
|
175
|
+
focused.refocus();
|
176
|
+
};
|
177
|
+
|
178
|
+
// Replace this view with a different one. Returns replacement.
|
179
|
+
View.prototype.replace = function(replacement) {
|
180
|
+
console.log("Replacing", this, "with", replacement);
|
181
|
+
console.log("Parent is", this.parent);
|
182
|
+
var p = this.parent;
|
183
|
+
|
184
|
+
if (p == null) {
|
185
|
+
throw "Sorry, can't replace top-level views.";
|
186
|
+
}
|
187
|
+
|
188
|
+
if (p.replaceChild == null) {
|
189
|
+
throw "Sorry, can't replace unless parent can replace child.";
|
190
|
+
}
|
191
|
+
|
192
|
+
p.replaceChild(this, replacement);
|
193
|
+
|
194
|
+
return replacement;
|
195
|
+
}
|
196
|
+
|
197
|
+
// Unfocus this view and delete it permanently.
|
198
|
+
View.prototype.delete = function() {
|
199
|
+
this.unfocus();
|
200
|
+
var p = this.parent;
|
201
|
+
if (p) {
|
202
|
+
if (p.removeChild) {
|
203
|
+
p.removeChild(this);
|
204
|
+
}
|
205
|
+
p.reflow();
|
206
|
+
}
|
207
|
+
if (this.el) {
|
208
|
+
this.el.remove();
|
209
|
+
this.el = null;
|
210
|
+
}
|
211
|
+
}
|
212
|
+
|
213
|
+
// Remove us from our parent, and have them reflow.
|
214
|
+
View.prototype.removeFromParent = function() {
|
215
|
+
this.unfocus();
|
216
|
+
var oldParent = this.parent;
|
217
|
+
if (oldParent && oldParent.removeChild) {
|
218
|
+
oldParent.removeChild(this);
|
219
|
+
oldParent.reflow();
|
220
|
+
}
|
221
|
+
}
|
222
|
+
|
223
|
+
// Split in a parent stack that already exists. i is either -1 (place the
|
224
|
+
// new view before us) or +1 (place the new view after us).
|
225
|
+
View.prototype.splitParentStack = function(i) {
|
226
|
+
console.log("Split parent");
|
227
|
+
if (i === null) { i = 0 }
|
228
|
+
var index = this.parent.indexOf(this) - Math.min(i, 0);
|
229
|
+
console.log(this.parent.indexOf(this), index);
|
230
|
+
this.parent.insertChild(
|
231
|
+
index,
|
232
|
+
reify({type: 'View'})
|
233
|
+
);
|
234
|
+
this.parent.reflow();
|
235
|
+
this.refocus();
|
236
|
+
}
|
237
|
+
|
238
|
+
// Split into a stackType. i is either -1 (place the new view before us) or
|
239
|
+
// +1 (place the new view after us.
|
240
|
+
View.prototype.split = function(stackType, i) {
|
241
|
+
var parent = this.parent;
|
242
|
+
if (parent) {
|
243
|
+
if (parent.type === stackType) {
|
244
|
+
this.splitParentStack(i);
|
245
|
+
} else if (parent.replaceChild) {
|
246
|
+
// Replace self with stack
|
247
|
+
var stack = reify({
|
248
|
+
type: stackType,
|
249
|
+
weight: this.weight
|
250
|
+
});
|
251
|
+
parent.replaceChild(this, stack);
|
252
|
+
|
253
|
+
// Add self to stack
|
254
|
+
this.weight = 1;
|
255
|
+
if (i === -1) {
|
256
|
+
stack.addChild(this);
|
257
|
+
stack.addChild(new View({type: 'View'}));
|
258
|
+
} else {
|
259
|
+
stack.addChild(new View({type: 'View'}));
|
260
|
+
stack.addChild(this);
|
261
|
+
}
|
262
|
+
|
263
|
+
// Redraw
|
264
|
+
parent.reflow();
|
265
|
+
this.refocus();
|
266
|
+
} else {
|
267
|
+
console.log("Can't split: parent can't replace child.");
|
268
|
+
}
|
269
|
+
} else {
|
270
|
+
console.log("Can't split: no parent");
|
271
|
+
}
|
272
|
+
}
|
273
|
+
|
274
|
+
// Redraw the focus indicator
|
275
|
+
View.prototype.refocus = function() {
|
276
|
+
focusOverlay.width(this.el.width());
|
277
|
+
focusOverlay.height(this.el.height());
|
278
|
+
focusOverlay.css('top', this.el.offset().top);
|
279
|
+
focusOverlay.css('left', this.el.offset().left);
|
280
|
+
focusOverlay.show();
|
281
|
+
}
|
282
|
+
|
283
|
+
// Focus this view
|
284
|
+
View.prototype.focus = function() {
|
285
|
+
if (focused !== null) {
|
286
|
+
focused.unfocus();
|
287
|
+
}
|
288
|
+
this.el.addClass("focused");
|
289
|
+
this.refocus();
|
290
|
+
focused = this;
|
291
|
+
}
|
292
|
+
|
293
|
+
// Unfocus this view
|
294
|
+
View.prototype.unfocus = function() {
|
295
|
+
focusOverlay.hide();
|
296
|
+
if (this.el) {
|
297
|
+
this.el.removeClass("focused");
|
298
|
+
}
|
299
|
+
if (focused === this) {
|
300
|
+
focused = null;
|
301
|
+
}
|
302
|
+
}
|
303
|
+
|
304
|
+
// Returns the nearest parent hstack
|
305
|
+
View.prototype.enclosingHStack = function() {
|
306
|
+
try {
|
307
|
+
if (this.parent.isHStack) {
|
308
|
+
return {
|
309
|
+
i: this.parent.indexOf(this),
|
310
|
+
stack: this.parent
|
311
|
+
};
|
312
|
+
} else {
|
313
|
+
return this.parent.enclosingHStack();
|
314
|
+
}
|
315
|
+
} catch(e) {
|
316
|
+
return null;
|
317
|
+
}
|
318
|
+
}
|
319
|
+
|
320
|
+
// Returns the nearest parent vstack
|
321
|
+
View.prototype.enclosingVStack = function() {
|
322
|
+
try {
|
323
|
+
if (this.parent.isVStack) {
|
324
|
+
return {
|
325
|
+
i: this.parent.indexOf(this),
|
326
|
+
stack: this.parent
|
327
|
+
};
|
328
|
+
} else {
|
329
|
+
return this.parent.enclosingVStack();
|
330
|
+
}
|
331
|
+
} catch(e) {
|
332
|
+
return null;
|
333
|
+
}
|
334
|
+
}
|
335
|
+
|
336
|
+
// Move a view horizontally, by delta -1 = left, +1 = right).
|
337
|
+
View.prototype.move = function(parentFinder, delta) {
|
338
|
+
var enclosing = this[parentFinder]();
|
339
|
+
|
340
|
+
if (enclosing) {
|
341
|
+
// Get the stack we'll move in to, and our (possibly our parent's) index
|
342
|
+
// in it.
|
343
|
+
var stack = enclosing.stack;
|
344
|
+
var i = enclosing.i;
|
345
|
+
console.log("I am", this);
|
346
|
+
console.log("Enclosing is", stack, i);
|
347
|
+
|
348
|
+
var newI = i + delta;
|
349
|
+
if (newI < 0) {
|
350
|
+
console.log("Sorry, at start.");
|
351
|
+
newI = 0;
|
352
|
+
} else if (newI >= stack.children.length) {
|
353
|
+
console.log("Sorry, at end.");
|
354
|
+
newI = stack.children.length;
|
355
|
+
} else {
|
356
|
+
// What's there now?
|
357
|
+
var neighbor = stack.children[newI];
|
358
|
+
if (neighbor && neighbor.addChild) {
|
359
|
+
// We can enter our neighbor
|
360
|
+
this.removeFromParent();
|
361
|
+
neighbor.addChild(this);
|
362
|
+
neighbor.reflow();
|
363
|
+
this.focus();
|
364
|
+
return;
|
365
|
+
}
|
366
|
+
}
|
367
|
+
|
368
|
+
if (this.parent === stack &&
|
369
|
+
stack.children.length === 1) {
|
370
|
+
// An special case: we can't leave our parent and then re-enter it,
|
371
|
+
// because removeFromParent() would *destroy* our parent after we
|
372
|
+
// left. Nothing *needs* to happen, so we return immediately.
|
373
|
+
return;
|
374
|
+
}
|
375
|
+
|
376
|
+
// We're moving to a new position inside the enclosing stack.
|
377
|
+
this.removeFromParent();
|
378
|
+
stack.insertChild(newI, this);
|
379
|
+
stack.reflow();
|
380
|
+
this.focus();
|
381
|
+
} else {
|
382
|
+
console.log("Sorry, not yet");
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
View.prototype.moveHorizontal = function(delta) {
|
387
|
+
this.move('enclosingHStack', delta);
|
388
|
+
}
|
389
|
+
|
390
|
+
View.prototype.moveVertical = function(delta) {
|
391
|
+
this.move('enclosingVStack', delta);
|
392
|
+
}
|
393
|
+
|
394
|
+
// A jquery node inserted into the edit modal, for changing the
|
395
|
+
// properties of a view.
|
396
|
+
View.prototype.editForm = function() {
|
397
|
+
}
|
398
|
+
|
399
|
+
// Show a dialog for changing this view.
|
400
|
+
View.prototype.edit = function() {
|
401
|
+
var dialog = $('<div><h1></h1><form>' +
|
402
|
+
'<select name="type" />' +
|
403
|
+
'<div class="edit-form"></div>' +
|
404
|
+
'<button name="apply">Apply</button>' +
|
405
|
+
'</form></div>');
|
406
|
+
dialog.find('h1').text("Edit " + this.type);
|
407
|
+
|
408
|
+
// Build type selector.
|
409
|
+
var typeSelector = dialog.find('select[name=type]');
|
410
|
+
var editForm = dialog.find('.edit-form');
|
411
|
+
var type;
|
412
|
+
for (type in types) {
|
413
|
+
if (type == this.json().type) {
|
414
|
+
typeSelector.append("<option selected>" + type + "</option>");
|
415
|
+
} else {
|
416
|
+
typeSelector.append("<option>" + type + "</option>");
|
417
|
+
}
|
418
|
+
}
|
419
|
+
|
420
|
+
// The serialized representation of a view that we're editing.
|
421
|
+
// Carried between various view types; when Apply is clicked, projected
|
422
|
+
// into an actual view.
|
423
|
+
var replacementJson = this.json();
|
424
|
+
|
425
|
+
// Update the replacement structure with the current values.
|
426
|
+
var mergeCurrentValues = function() {
|
427
|
+
dialog.find('form').first().serializeArray().forEach(function(input) {
|
428
|
+
replacementJson[input.name] = input.value;
|
429
|
+
});
|
430
|
+
}
|
431
|
+
|
432
|
+
// Add the edit form itself.
|
433
|
+
editForm.append(reify(replacementJson).editForm());
|
434
|
+
|
435
|
+
// Handle type changes.
|
436
|
+
typeSelector.change(function() {
|
437
|
+
// Read fields
|
438
|
+
mergeCurrentValues();
|
439
|
+
|
440
|
+
// Replace edit form
|
441
|
+
editForm.empty();
|
442
|
+
editForm.append(reify(replacementJson).editForm());
|
443
|
+
});
|
444
|
+
|
445
|
+
// Apply button.
|
446
|
+
var me = this;
|
447
|
+
dialog.find('button[name=apply]').click(function(e) {
|
448
|
+
// Don't submit the form.
|
449
|
+
e.preventDefault();
|
450
|
+
|
451
|
+
// Read fields
|
452
|
+
mergeCurrentValues();
|
453
|
+
|
454
|
+
// Replace view.
|
455
|
+
replacement = me.replace(reify(replacementJson));
|
456
|
+
replacement.parent.reflow();
|
457
|
+
me.delete();
|
458
|
+
replacement.focus();
|
459
|
+
|
460
|
+
// Close dialog.
|
461
|
+
$.modal.close();
|
462
|
+
});
|
463
|
+
|
464
|
+
// Show dialog.
|
465
|
+
keys.disable();
|
466
|
+
dialog.modal({onClose: function() {
|
467
|
+
keys.enable();
|
468
|
+
$.modal.close();
|
469
|
+
}});
|
470
|
+
}
|
471
|
+
|
472
|
+
// Serialize this view to JSON.
|
473
|
+
View.prototype.json = function() {
|
474
|
+
return {type: 'View', weight: this.weight};
|
475
|
+
}
|
476
|
+
|
477
|
+
// Balloon /////////////////////////////////////////////////////////////////
|
478
|
+
|
479
|
+
var Balloon = function(json) {
|
480
|
+
View.call(this, json);
|
481
|
+
this.container = json.container;
|
482
|
+
this.clickFocusable = false;
|
483
|
+
this.el.detach();
|
484
|
+
this.el.appendTo(this.container);
|
485
|
+
|
486
|
+
this.child = reify(json.child);
|
487
|
+
this.child.parent = this;
|
488
|
+
this.el.append(this.child.el);
|
489
|
+
}
|
490
|
+
inherit(View, Balloon);
|
491
|
+
types.Balloon = Balloon;
|
492
|
+
|
493
|
+
Balloon.prototype.json = function() {
|
494
|
+
return $.extend(View.prototype.json.call(this), {
|
495
|
+
type: 'Balloon',
|
496
|
+
child: this.child.json()
|
497
|
+
});
|
498
|
+
}
|
499
|
+
|
500
|
+
Balloon.prototype.replaceChild = function(v1, v2) {
|
501
|
+
this.child.parent = null;
|
502
|
+
this.child.el.detach();
|
503
|
+
|
504
|
+
this.child = v2;
|
505
|
+
v2.parent = this;
|
506
|
+
this.el.append(this.child.el);
|
507
|
+
}
|
508
|
+
|
509
|
+
Balloon.prototype.removeChild = function(c) {
|
510
|
+
this.child = null;
|
511
|
+
}
|
512
|
+
|
513
|
+
Balloon.prototype.reflow = function() {
|
514
|
+
var p = this.container;
|
515
|
+
this.width(p.width());
|
516
|
+
this.height(p.height());
|
517
|
+
if (this.child) {
|
518
|
+
this.child.width(p.width());
|
519
|
+
this.child.height(p.height());
|
520
|
+
this.child.reflow();
|
521
|
+
}
|
522
|
+
}
|
523
|
+
|
524
|
+
Balloon.prototype.delete = function() {
|
525
|
+
this.child.delete();
|
526
|
+
View.prototype.delete.call(this);
|
527
|
+
}
|
528
|
+
|
529
|
+
// Fullscreen //////////////////////////////////////////////////////////////
|
530
|
+
|
531
|
+
var Fullscreen = function(json) {
|
532
|
+
Balloon.call(this, json);
|
533
|
+
this.el.detach();
|
534
|
+
this.el.css('position', 'fixed');
|
535
|
+
this.el.appendTo($('body'));
|
536
|
+
this.parent = null;
|
537
|
+
}
|
538
|
+
inherit(Balloon, Fullscreen);
|
539
|
+
types.Fullscreen = Fullscreen;
|
540
|
+
|
541
|
+
Fullscreen.prototype.json = function() {
|
542
|
+
return $.extend(
|
543
|
+
Balloon.prototype.json.call(this),
|
544
|
+
{type: 'Fullscreen'});
|
545
|
+
}
|
546
|
+
|
547
|
+
Fullscreen.prototype.reflow = function() {
|
548
|
+
var p = $(window);
|
549
|
+
this.width(p.width());
|
550
|
+
this.height(p.height());
|
551
|
+
this.child.width(p.width());
|
552
|
+
this.child.height(p.height());
|
553
|
+
this.child.reflow();
|
554
|
+
}
|
555
|
+
|
556
|
+
// Stack ///////////////////////////////////////////////////////////////////
|
557
|
+
|
558
|
+
var Stack = function(json) {
|
559
|
+
View.call(this, json);
|
560
|
+
this.clickFocusable = false;
|
561
|
+
this.children = [];
|
562
|
+
var self = this;
|
563
|
+
if (json.children !== undefined) {
|
564
|
+
json.children.map(reify).forEach(function(c) {
|
565
|
+
self.addChild(c);
|
566
|
+
});
|
567
|
+
}
|
568
|
+
};
|
569
|
+
inherit(View, Stack);
|
570
|
+
|
571
|
+
Stack.prototype.json = function() {
|
572
|
+
return $.extend(View.prototype.json.call(this), {
|
573
|
+
type: 'Stack',
|
574
|
+
children: $.map(this.children, function(x) { return x.json(); })
|
575
|
+
});
|
576
|
+
}
|
577
|
+
|
578
|
+
Stack.prototype.addChild = function(view) {
|
579
|
+
view.parent = this;
|
580
|
+
this.children.push(view);
|
581
|
+
this.el.append(view.el);
|
582
|
+
}
|
583
|
+
|
584
|
+
Stack.prototype.insertChild = function(i, view) {
|
585
|
+
view.parent = this;
|
586
|
+
this.children.splice(i, 0, view);
|
587
|
+
this.el.append(view.el);
|
588
|
+
}
|
589
|
+
|
590
|
+
// Replace v1 with v2
|
591
|
+
Stack.prototype.replaceChild = function(v1, v2) {
|
592
|
+
v1.parent = null;
|
593
|
+
v2.parent = this;
|
594
|
+
v1.el.detach();
|
595
|
+
var i = this.children.indexOf(v1);
|
596
|
+
this.children[i] = v2;
|
597
|
+
this.el.append(v2.el);
|
598
|
+
}
|
599
|
+
|
600
|
+
Stack.prototype.removeChild = function(view) {
|
601
|
+
view.parent = null;
|
602
|
+
var i = this.children.indexOf(view);
|
603
|
+
view.el.detach();
|
604
|
+
this.children.splice(i, 1);
|
605
|
+
|
606
|
+
// Delete self if empty
|
607
|
+
if (this.children.length === 0) {
|
608
|
+
this.delete();
|
609
|
+
}
|
610
|
+
}
|
611
|
+
|
612
|
+
Stack.prototype.indexOf = function(child) {
|
613
|
+
return this.children.indexOf(child);
|
614
|
+
}
|
615
|
+
|
616
|
+
Stack.prototype.delete = function() {
|
617
|
+
this.children.slice().forEach(function(c) {
|
618
|
+
c.delete();
|
619
|
+
});
|
620
|
+
View.prototype.delete.call(this);
|
621
|
+
}
|
622
|
+
|
623
|
+
// HStack //////////////////////////////////////////////////////////////////
|
624
|
+
|
625
|
+
var HStack = function(json) {
|
626
|
+
Stack.call(this, json);
|
627
|
+
};
|
628
|
+
inherit(Stack, HStack);
|
629
|
+
types.HStack = HStack;
|
630
|
+
|
631
|
+
HStack.prototype.json = function() {
|
632
|
+
return $.extend(Stack.prototype.json.call(this), {type: 'HStack'});
|
633
|
+
}
|
634
|
+
|
635
|
+
HStack.prototype.isHStack = true;
|
636
|
+
|
637
|
+
HStack.prototype.reflow = function() {
|
638
|
+
if (this.el === null) {
|
639
|
+
// We're gone.
|
640
|
+
return;
|
641
|
+
}
|
642
|
+
|
643
|
+
var width = this.width();
|
644
|
+
var height = this.height();
|
645
|
+
var left = 0;
|
646
|
+
var weightSum = this.children.reduce(function(acc, c) {
|
647
|
+
return acc + c.weight;
|
648
|
+
}, 0);
|
649
|
+
|
650
|
+
this.children.forEach(function(c) {
|
651
|
+
c.height(height);
|
652
|
+
c.width(width * (c.weight / weightSum));
|
653
|
+
c.top(0);
|
654
|
+
c.left(left);
|
655
|
+
left = left + c.width();
|
656
|
+
c.reflow();
|
657
|
+
});
|
658
|
+
}
|
659
|
+
|
660
|
+
// VStack //////////////////////////////////////////////////////////////////
|
661
|
+
|
662
|
+
var VStack = function(json) {
|
663
|
+
Stack.call(this, json);
|
664
|
+
};
|
665
|
+
inherit(Stack, VStack);
|
666
|
+
types.VStack = VStack;
|
667
|
+
|
668
|
+
VStack.prototype.json = function() {
|
669
|
+
return $.extend(Stack.prototype.json.call(this), {type: 'VStack'});
|
670
|
+
}
|
671
|
+
|
672
|
+
VStack.prototype.isVStack = true;
|
673
|
+
|
674
|
+
VStack.prototype.reflow = function() {
|
675
|
+
if (this.el === null) {
|
676
|
+
// We're gone.
|
677
|
+
return;
|
678
|
+
}
|
679
|
+
|
680
|
+
var width = this.width();
|
681
|
+
var height = this.height();
|
682
|
+
var top = 0;
|
683
|
+
var weightSum = this.children.reduce(function(acc, c) {
|
684
|
+
return acc + c.weight;
|
685
|
+
}, 0);
|
686
|
+
|
687
|
+
this.children.forEach(function(c) {
|
688
|
+
c.width(width);
|
689
|
+
c.height(height * (c.weight / weightSum));
|
690
|
+
c.left(0);
|
691
|
+
c.top(top);
|
692
|
+
top = top + c.height();
|
693
|
+
c.reflow();
|
694
|
+
});
|
695
|
+
};
|
696
|
+
|
697
|
+
return $.extend({
|
698
|
+
types: types,
|
699
|
+
reify: reify,
|
700
|
+
inherit: inherit,
|
701
|
+
unfocus: unfocus,
|
702
|
+
focused: function() { return focused; }
|
703
|
+
}, types);
|
704
|
+
})();
|