19
function start_app_login() {
20
app = new Sammy.Application(function () {
21
this.put('#/login', function() {
22
username = this.params['username'];
23
password = this.params['password'];
24
var b64 = b64_encode_utf8(username + ':' + password);
25
document.cookie = 'auth=' + encodeURIComponent(b64);
30
if (get_cookie('auth') != '') {
35
function check_login() {
36
var user = JSON.parse(sync_get('/whoami'));
38
document.cookie = 'auth=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
39
replace_content('login-status', '<p>Login failed</p>');
42
replace_content('outer', format('layout', {}));
43
setup_global_vars(user);
44
setup_constant_events();
22
51
function start_app() {
23
app = $.sammy(dispatcher);
53
// Oh boy. Sammy uses various different methods to determine if
54
// the URL hash has changed. Unsurprisingly this is a native event
55
// in modern browsers, and falls back to an icky polling function
56
// in MSIE. But it looks like there's a bug. The polling function
57
// should get installed when the app is started. But it's guarded
58
// behind if (Sammy.HashLocationProxy._interval != null). And of
59
// course that's not specific to the application; it's pretty
60
// global. So we need to manually clear that in order for links to
62
// Filed as https://github.com/quirkey/sammy/issues/171
64
// Note for when we upgrade: HashLocationProxy has become
65
// DefaultLocationProxy in later versions, but otherwise the issue
67
Sammy.HashLocationProxy._interval = null;
68
app = new Sammy.Application(dispatcher);
25
70
var url = this.location.toString();
26
71
if (url.indexOf('#') == -1) {
71
116
function setup_extensions() {
72
117
var extensions = JSON.parse(sync_get('/extensions'));
118
extension_count = extensions.length;
73
119
for (var i in extensions) {
74
120
var extension = extensions[i];
75
121
dynamic_load(extension.javascript);
77
extension_count = extensions.length;
80
125
function dynamic_load(filename) {
170
function update_manual(div, query) {
173
if (query == 'memory') {
174
path = current_reqs['node'] + '?memory=true';
177
var data = JSON.parse(sync_get(path));
179
replace_content(div, format(template, data));
180
postprocess_partial();
125
183
function render(reqs, template, highlight) {
126
184
current_template = template;
127
185
current_reqs = reqs;
226
function update_navigation() {
231
for (var k in NAVIGATION) {
232
var val = NAVIGATION[k];
234
while (!leaf(path)) {
235
path = path[keys(path)[0]];
237
var selected = false;
238
if (contains_current_highlight(val)) {
245
l1 += '<li><a href="' + nav(path) + '"' +
246
(selected ? ' class="selected"' : '') + '>' + k + '</a></li>';
251
l2 = obj_to_ul(descend);
252
$('#main').addClass('with-rhs');
255
$('#main').removeClass('with-rhs');
258
replace_content('tabs', l1);
259
replace_content('rhs', l2);
266
function show(pair) {
267
return !pair[1] || user_administrator;
270
function leaf(pair) {
271
return typeof(nav(pair)) == 'string';
274
function contains_current_highlight(val) {
276
return current_highlight == nav(val);
281
b |= contains_current_highlight(val[k]);
287
function obj_to_ul(val) {
292
if (leaf(obj) && show(obj)) {
293
res += '<a href="' + nav(obj) + '"' +
294
(current_highlight == nav(obj) ? ' class="selected"' : '') +
298
res += obj_to_ul(nav(obj));
302
return res + '</ul>';
167
305
function full_refresh() {
168
306
store_pref('position', x_position() + ',' + y_position());
169
307
location.reload();
367
function vhost_query(req) {
368
for (i in VHOST_QUERIES) {
369
var query = VHOST_QUERIES[i];
370
if (req.match(query)) return true;
229
375
function show_popup(type, text) {
230
376
var cssClass = '.form-popup-' + type;
231
377
function hide() {
267
411
setTimeout('app.run()');
414
$('.update-manual').click(function() {
415
update_manual($(this).attr('for'), $(this).attr('query'));
270
417
$('input, select').die();
271
418
$('.multifield input').live('blur', function() {
272
419
update_multifields();
333
480
if (!empty_found) {
334
$(this).append('<p><input type="text" name="' + name + '_' +
481
var prefix = name + '_' + (largest_id + 1);
483
if ($(this).hasClass('string-only')) {
484
type_part = '<input type="hidden" name="' + prefix +
485
'_mftype" value="string"/>';
487
type_part = '<select name="' + prefix +
489
'<option value="string">String</option>' +
490
'<option value="number">Number</option>' +
491
'<option value="boolean">Boolean</option>' +
494
$(this).append('<p><input type="text" name="' + prefix +
336
495
'_mfkey" value=""/> = ' +
337
'<input type="text" name="' + name + '_' +
339
'_mfvalue" value=""/></p>');
496
'<input type="text" name="' + prefix +
497
'_mfvalue" value=""/> ' + type_part + '</p>');
470
628
replace_content('status', html);
631
function auth_header() {
632
return "Basic " + decodeURIComponent(get_cookie('auth'));
473
635
function with_req(method, path, body, fun) {
475
637
var req = xmlHttpRequest();
476
638
req.open(method, 'api' + path, true );
639
req.setRequestHeader('authorization', auth_header());
477
640
req.onreadystatechange = function () {
478
641
if (req.readyState == 4) {
479
642
if (check_bad_response(req, true)) {
514
677
var req = xmlHttpRequest();
515
678
req.open(type, 'api' + path, false);
516
679
req.setRequestHeader('content-type', 'application/json');
680
req.setRequestHeader('authorization', auth_header());
518
682
if (type == 'GET')
598
762
for (key in params0) {
599
763
var match = key.match(/([a-z]*)_([0-9]*)_mfkey/);
600
764
var match2 = key.match(/[a-z]*_[0-9]*_mfvalue/);
601
if (match == null && match2 == null) {
765
var match3 = key.match(/[a-z]*_[0-9]*_mftype/);
766
if (match == null && match2 == null && match3 == null) {
602
767
params[key] = params0[key];
604
769
else if (match == null) {
613
778
if (params0[key] != "") {
614
779
var k = params0[key];
615
780
var v = params0[name + '_' + id + '_mfvalue'];
781
var t = params0[name + '_' + id + '_mftype'];
782
if (t == 'boolean') {
783
if (v != 'true' && v != 'false')
784
throw(k + ' must be "true" or "false"; got ' + v);
785
params[name][k] = (v == 'true');
787
else if (t == 'number') {
788
var n = parseFloat(v);
790
throw(k + ' must be a number; got ' + v);
848
function put_parameter(sammy, mandatory_keys, num_keys, bool_keys) {
849
for (var i in sammy.params) {
850
if (i === 'length' || !sammy.params.hasOwnProperty(i)) continue;
851
if (sammy.params[i] == '' && mandatory_keys.indexOf(i) == -1) {
852
delete sammy.params[i];
854
else if (num_keys.indexOf(i) != -1) {
855
sammy.params[i] = parseInt(sammy.params[i]);
857
else if (bool_keys.indexOf(i) != -1) {
858
sammy.params[i] = sammy.params[i] == 'true';
861
var params = {"component": sammy.params.component,
862
"vhost": sammy.params.vhost,
863
"name": sammy.params.name,
864
"value": params_magic(sammy.params)};
865
delete params.value.vhost;
866
delete params.value.component;
867
delete params.value.name;
868
sammy.params = params;
869
if (sync_put(sammy, '/parameters/:component/:vhost/:name')) update();
872
function put_policy(sammy, mandatory_keys, num_keys, bool_keys) {
873
for (var i in sammy.params) {
874
if (i === 'length' || !sammy.params.hasOwnProperty(i)) continue;
875
if (sammy.params[i] == '' && mandatory_keys.indexOf(i) == -1) {
876
delete sammy.params[i];
878
else if (num_keys.indexOf(i) != -1) {
879
sammy.params[i] = parseInt(sammy.params[i]);
881
else if (bool_keys.indexOf(i) != -1) {
882
sammy.params[i] = sammy.params[i] == 'true';
885
if (sync_put(sammy, '/policies/:vhost/:name')) update();
669
888
function debug(str) {
670
889
$('<p>' + str + '</p>').appendTo('#debug');
913
// Our base64 library takes a string that is really a byte sequence,
914
// and will throw if given a string with chars > 255 (and hence not
915
// DTRT for chars > 127). So encode a unicode string as a UTF-8
916
// sequence of "bytes".
917
function b64_encode_utf8(str) {
918
return base64.encode(encode_utf8(str));
921
// encodeURIComponent handles utf-8, unescape does not. Neat!
922
function encode_utf8(str) {
923
return unescape(encodeURIComponent(str));
696
928
center: function () {