Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ b687587e

History | View | Annotate | Download (71.9 kB)

1
//
2
// Copyright 2011 GRNET S.A. All rights reserved.
3
//
4
// Redistribution and use in source and binary forms, with or
5
// without modification, are permitted provided that the following
6
// conditions are met:
7
//
8
//   1. Redistributions of source code must retain the above
9
//      copyright notice, this list of conditions and the following
10
//      disclaimer.
11
//
12
//   2. Redistributions in binary form must reproduce the above
13
//      copyright notice, this list of conditions and the following
14
//      disclaimer in the documentation and/or other materials
15
//      provided with the distribution.
16
//
17
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
// POSSIBILITY OF SUCH DAMAGE.
29
//
30
// The views and conclusions contained in the software and
31
// documentation are those of the authors and should not be
32
// interpreted as representing official policies, either expressed
33
// or implied, of GRNET S.A.
34
//
35
var API_URL = "/api/v1.1";
36
var changes_since = 0, deferred = 0, update_request = false, load_request = false, pending_actions = [];
37
var flavors = [], images = [], servers = [], disks = [], cpus = [], ram = [];
38
var networks = [], networks_changes_since = 0;
39

    
40

    
41
//FIXME: authentication
42
//if cookie with value X-Auth-Token exists, set the value on the headers.
43
    $.ajaxSetup({
44
        'beforeSend': function(xhr) {
45
            //if ($.cookie("X-Auth-Token") != null) {
46
              xhr.setRequestHeader("X-Auth-Token", $.cookie("X-Auth-Token"));
47
            //} else {
48
            //    $.cookie("X-Auth-Token", "46e427d657b20defe352804f0eb6f8a2"); // set X-Auth-Token cookie
49
            //}
50
        }
51
    });
52

    
53

    
54
// jquery show/hide events
55
var _oldshow = $.fn.show;
56
$.fn.show = function(speed, callback) {
57
    $(this).trigger('show');
58
    return _oldshow.apply(this,arguments);
59
}
60
var _oldhide = $.fn.hide;
61
$.fn.hide = function(speed, callback) {
62
    $(this).trigger('hide');
63
    return _oldhide.apply(this,arguments);
64
}
65

    
66
function ISODateString(d){
67
    //return a date in an ISO 8601 format using UTC.
68
    //do not include time zone info (Z) at the end
69
    //taken from the Mozilla Developer Center
70
    function pad(n){ return n<10 ? '0'+n : n }
71
    return  d.getUTCFullYear()+ '-' +
72
            pad(d.getUTCMonth()+1) + '-' +
73
            pad(d.getUTCDate()) + 'T' +
74
            pad(d.getUTCHours()) + ':' +
75
            pad(d.getUTCMinutes()) + ':' +
76
            pad(d.getUTCSeconds()) +'Z'
77
}
78

    
79
function parse_error(responseText, errorCode){
80
    var errors = [];
81
    try {
82
        responseObj = JSON.parse(responseText);
83
    }
84
    catch(err) {
85
        errors[0] = {'code': errorCode};
86
        return errors;
87
    }
88
    for (var err in responseObj){
89
        errors[errors.length] = responseObj[err];
90
    }
91
    return errors;
92
}
93

    
94
// indexOf prototype for IE
95
if (!Array.prototype.indexOf) {
96
  Array.prototype.indexOf = function(elt /*, from*/) {
97
    var len = this.length;
98
    var from = Number(arguments[1]) || 0;
99
    from = (from < 0)
100
         ? Math.ceil(from)
101
         : Math.floor(from);
102
    if (from < 0)
103
      from += len;
104

    
105
    for (; from < len; from++) {
106
      if (from in this &&
107
          this[from] === elt)
108
        return from;
109
    }
110
    return -1;
111
  };
112
}
113

    
114
// trim prototype for IE
115
if(typeof String.prototype.trim !== 'function') {
116
    String.prototype.trim = function() {
117
        return this.replace(/^\s+|\s+$/g, '');
118
    }
119
}
120

    
121
function update_confirmations() {
122
    // hide all confirm boxes to begin with
123
    $('#machines-pane div.confirm_single').hide();
124
    $('#machines-pane div.confirm_multiple').hide();
125
    var action_type = [];
126
    // standard view or single view
127
    if ($.cookie("view") == '0' || $.cookie("view") == '2') {
128
        for (var i=0; i<pending_actions.length; i++) {
129
            // show single confirms
130
            if (pending_actions[i][0] == reboot) {
131
                action_type = "reboot";
132
            } else if (pending_actions[i][0] == shutdown) {
133
                action_type = "shutdown";
134
            } else if (pending_actions[i][0] == start) {
135
                action_type = "start";
136
            } else if (pending_actions[i][0] == open_console) {
137
                action_type = "console";
138
            } else {
139
                action_type = "destroy";
140
            }
141
            $("#machines-pane #" + pending_actions[i][1] +
142
            " div.action-container." + action_type + " div.confirm_single").show();
143
        }
144
    }
145
    // if more than one pending action show multiple confirm box
146
    if (pending_actions.length>1 || $.cookie("view") == '1' && pending_actions.length == 1){
147
        $('#machines-pane div.confirm_multiple span.actionLen').text(pending_actions.length);
148
        $('#machines-pane div.confirm_multiple').show();
149
    }
150
}
151

    
152
function update_network_confirmations(){
153
    // hide all confirm boxes to begin with
154
    $('#networks-pane div.confirm_multiple').hide();
155

    
156
    for (var i=0;i<pending_actions.length;i++){
157
        // show single confirms depending on the action
158
        if (pending_actions[i][0] == delete_network) {
159
            $("#networks-pane div.network#net-"+pending_actions[i][1]).children('.confirm_single').show();
160
        } else if (pending_actions[i][0] == remove_server_from_network) {
161
            $("#networks-pane div.network #net-"+pending_actions[i][1]+"-server-"+pending_actions[i][2]).children('.confirm_single').show();
162
        } // else {}
163
    }
164

    
165
    // if more than one pending action show multiple confirm box
166
    if (pending_actions.length > 1){
167
        $('#networks-pane div.confirm_multiple span.actionLen').text(pending_actions.length);
168
        $('#networks-pane div.confirm_multiple').show();
169
    }
170
}
171

    
172
function list_view() {
173
    changes_since = 0; // to reload full list
174
    pending_actions = []; // clear pending actions
175
    update_confirmations();
176
    clearTimeout(deferred);    // clear old deferred calls
177
    try {
178
        update_request.abort(); // cancel pending ajax updates
179
        load_request.abort();
180
    }catch(err){}
181
    $.cookie("view", '1'); // set list cookie
182
    uri = $("a#list").attr("href");
183
    load_request = $.ajax({
184
        url: uri,
185
        type: "GET",
186
        timeout: TIMEOUT,
187
        dataType: "html",
188
        error: function(jqXHR, textStatus, errorThrown) {
189
            return false;
190
        },
191
        success: function(data, textStatus, jqXHR) {
192
            $("a#list")[0].className += ' activelink';
193
            $("a#standard")[0].className = '';
194
            $("a#single")[0].className = '';
195
            $("div#machinesview").html(data);
196
        }
197
    });
198
    return false;
199
}
200

    
201
function single_view() {
202
    changes_since = 0; // to reload full list
203
    pending_actions = []; // clear pending actions
204
    update_confirmations();
205
    clearTimeout(deferred);    // clear old deferred calls
206
    try {
207
        update_request.abort(); // cancel pending ajax updates
208
        load_request.abort();
209
    }catch(err){}
210
    $.cookie("view", '2'); // set list cookie
211
    uri = $("a#single").attr("href");
212
    load_request = $.ajax({
213
        url: uri,
214
        type: "GET",
215
        timeout: TIMEOUT,
216
        dataType: "html",
217
        error: function(jqXHR, textStatus, errorThrown) {
218
            return false;
219
        },
220
        success: function(data, textStatus, jqXHR) {
221
            $("a#single")[0].className += ' activelink';
222
            $("a#standard")[0].className = '';
223
            $("a#list")[0].className = '';
224
            $("div#machinesview").html(data);
225
        }
226
    });
227
    return false;
228
}
229

    
230
function standard_view() {
231
    changes_since = 0; // to reload full list
232
    pending_actions = []; // clear pending actions
233
    update_confirmations();
234
    clearTimeout(deferred);    // clear old deferred calls
235
    try {
236
        update_request.abort() // cancel pending ajax updates
237
        load_request.abort();
238
    }catch(err){}
239
    $.cookie("view", '0');
240
    uri = $("a#standard").attr("href");
241
    load_request = $.ajax({
242
        url: uri,
243
        type: "GET",
244
        timeout: TIMEOUT,
245
        dataType: "html",
246
        error: function(jqXHR, textStatus, errorThrown) {
247
            return false;
248
        },
249
        success: function(data, textStatus, jqXHR) {
250
            $("a#standard")[0].className += ' activelink';
251
            $("a#list")[0].className = '';
252
            $("a#single")[0].className = '';
253
            $("div#machinesview").html(data);
254
        }
255
    });
256
    return false;
257
}
258

    
259
function choose_view() {
260
    if ($.cookie("view")=='1') {
261
        list_view();
262
    } else if ($.cookie("view")=='2'){
263
        single_view();
264
    } else {
265
        standard_view();
266
    }
267
}
268

    
269
// return value from metadata key "OS", if it exists
270
function os_icon(metadata) {
271
    if (!metadata) {
272
        return 'okeanos';
273
    }
274
    if (metadata.values.OS == undefined || metadata.values.OS == '') {
275
        return 'okeanos';
276
    } else {
277
        if (os_icons.indexOf(metadata.values.OS) == -1) {
278
            return 'okeanos';
279
        } else {
280
            return metadata.values.OS;
281
        }
282
    }
283
}
284

    
285
function os_icon_from_value(metadata) {
286
    if (!metadata) {
287
        return 'okeanos';
288
    }
289
if (metadata == undefined || metadata == '') {
290
        return 'okeanos';
291
    } else {
292
        if (os_icons.indexOf(metadata) == -1) {
293
            return 'okeanos';
294
        } else {
295
            return metadata;
296
        }
297
    }
298
}
299

    
300
// get and show a list of running and terminated machines
301
function update_vms(interval) {
302
    try{ console.info('updating machines'); } catch(err){}
303
    var uri= API_URL + '/servers/detail';
304

    
305
    if (changes_since != 0)
306
        uri+='?changes-since='+changes_since
307

    
308
    update_request = $.ajax({
309
        cache: false,
310
        url: uri,
311
        type: "GET",
312
        timeout: TIMEOUT,
313
        dataType: "json",
314
        error: function(jqXHR, textStatus, errorThrown) {
315
            // don't forget to try again later
316
            if (interval) {
317
                clearTimeout(deferred);    // clear old deferred calls
318
                deferred = setTimeout(function() {update_vms(interval);},interval,interval);
319
            }
320
            // as for now, just show an error message
321
            try { console.info('update_vms errback:' + jqXHR.status ) } catch(err) {}
322
            try {
323
                ajax_error(jqXHR.status, undefined, 'Update VMs', jqXHR.responseText);
324
            } catch(err) {
325
                ajax_error(0, undefined, 'Update VMs', jqXHR.responseText);
326
            }
327
            return false;
328
            },
329
        success: function(data, textStatus, jqXHR) {
330
            // create changes_since string if necessary
331
            if (jqXHR.getResponseHeader('Date') != null){
332
                changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
333
                changes_since = ISODateString(changes_since_date);
334
            }
335

    
336
            if (interval) {
337
                clearTimeout(deferred);    // clear old deferred calls
338
                deferred = setTimeout(function() {update_vms(interval);},interval,interval);
339
            }
340

    
341
            if (jqXHR.status == 200 || jqXHR.status == 203) {
342
                try {
343
                    //servers = data.servers.values;
344
                    update_servers_data(data.servers.values, data);
345
                    jQuery.parseJSON(data);
346
                    update_machines_view(data);
347
                } catch(err) { ajax_error('400', undefined, 'Update VMs', jqXHR.responseText);}
348
            } else if (jqXHR.status != 304){
349
                try { console.info('update_vms callback:' + jqXHR.status ) } catch(err) {}
350
                /*
351
                FIXME:  Here it should return the error, however Opera does not support 304.
352
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
353
                        304, which should be corrected (Bug #317).
354
                */
355
                //ajax_error(jqXHR.status, undefined, 'Update VMs', jqXHR.responseText);
356
            }
357
            return false;
358
        }
359
    });
360
    return false;
361
}
362

    
363
function update_servers_data(servers_update, data) {
364
    $(window).trigger("vm:update", servers_update, data);
365

    
366
    // first call
367
    if (!window.servers || window.servers.length == 0) {
368
        window.servers = servers_update;
369
        return;
370
    }
371
    
372
    // server exists helper
373
    server_exists = function(server) {
374
        var id = server.id;
375
        var found = false;
376
        var index = 0;
377
        $.each(servers, function(i, s) {
378
            console.log(index);
379
            if (s.id == id) { found = true, index = i };
380
        });
381
        if (found)
382
            return [found, index];
383

    
384
        return false;
385
    }
386

    
387
    // merge object properties
388
    merge = function() {
389
        var initial = arguments[0];
390
        var status_changed = undefined;
391
        $.each(arguments, function(index, el) {
392
            $.each(el, function(key,v) {
393
                // new attribute added
394
                var previous_value = initial[key];
395

    
396
                if (initial[key] == undefined) {
397
                    $(window).trigger("vm:attr:add", initial, key, v);
398
                } else {
399
                    // value changed
400
                    if (initial[key] != v) {
401
                        if (key == "status") {
402
                            status_changed = {'old': previous_value, 'new': v}; 
403
                        }
404
                        $(window).trigger("vm:attr:change", {'initial': initial, 'attr': key, 'newvalue': v});
405
                    }
406
                }
407
                initial[key] = v;
408
            });
409
        });
410
        if (status_changed !== undefined) {
411
            $(window).trigger('vm:status:change', {'vm': initial, 'old': status_changed['old'], 'new': status_changed['new']});
412
        }
413
        return initial;
414
    }
415
    
416
    // server removed
417
    var remove = [];
418
    $.each(servers_update, function(index, server) {
419
        if (server.status == "DELETED") {
420
            remove.push(server.id);
421
        }
422
    });
423
    
424
    // check server, if exists merge it with new values else add it
425
    $.each(servers_update, function(index, server) {
426
        var exists = server_exists(server);
427
        if (exists !== false) {
428
            try {
429
                servers[exists[1]] = merge(servers[exists[1]], server);
430
            } catch (err) {
431
                console.log("merge error", err);
432
            }
433
        } else {
434
            servers.push(server);
435
            $(window).trigger("vm:add", server);
436
        }
437
        if (remove.indexOf(server.id) > -1) {
438
            var remove_exists = server_exists(server);
439
            servers.splice(remove_exists[1], 1);
440
            $(window).trigger("vm:remove", server);
441
        }
442
    });
443
}
444

    
445
// get a list of running and terminated machines, used in network view
446
function update_networks(interval) {
447
    try{ console.info('updating networks'); } catch(err){}
448
    var uri= API_URL + '/servers/detail';
449

    
450
    if (changes_since != 0)
451
        uri+='?changes-since='+changes_since
452

    
453
    update_request = $.ajax({
454
        cache: false,
455
        url: uri,
456
        type: "GET",
457
        timeout: TIMEOUT,
458
        dataType: "json",
459
        error: function(jqXHR, textStatus, errorThrown) {
460
            // don't forget to try again later
461
            if (interval) {
462
                clearTimeout(deferred);    // clear old deferred calls
463
                deferred = setTimeout(function() {update_networks(interval);},interval,interval);
464
            }
465
            // as for now, just show an error message
466
            try { console.info('update_networks errback:' + jqXHR.status ) } catch(err) {}
467
            try {
468
                ajax_error(jqXHR.status, undefined, 'Update networks', jqXHR.responseText);
469
            } catch(err) {
470
                ajax_error(0, undefined, 'Update networks', jqXHR.responseText);
471
            }
472
            return false;
473
            },
474
        success: function(data, textStatus, jqXHR) {
475
            // create changes_since string if necessary
476
            if (jqXHR.getResponseHeader('Date') != null){
477
                changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
478
                changes_since = ISODateString(changes_since_date);
479
            }
480

    
481
            if (interval) {
482
                clearTimeout(deferred);    // clear old deferred calls
483
                deferred = setTimeout(function() {update_networks(interval);},interval,interval);
484
            }
485

    
486
            if (jqXHR.status == 200 || jqXHR.status == 203) {
487
                try {
488
                    //servers = data.servers.values;
489
                    update_servers_data(data.servers.values, data);
490
                    jQuery.parseJSON(data);
491
                    update_network_names(data);
492
                } catch(err) { ajax_error('400', undefined, 'Update networks', jqXHR.responseText);}
493
            } else if (jqXHR.status == 304) {
494
                update_network_names();
495
            }
496
            else {
497
                try { console.info('update_networks callback:' + jqXHR.status ) } catch(err) {}
498
                /*
499
                FIXME:  Here it should return the error, however Opera does not support 304.
500
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
501
                        304, which should be corrected (Bug #317).
502
                */
503
                //ajax_error(jqXHR.status, undefined, 'Update networks', jqXHR.responseText);
504
                update_network_names();
505
            }
506
            return false;
507
        }
508
    });
509
    return false;
510
}
511

    
512
// get and show a list of public and private networks
513
function update_network_names(servers_data) {
514
    try{ console.info('updating network names'); } catch(err){}
515
    var uri= API_URL + '/networks/detail';
516

    
517
    if (networks_changes_since != 0)
518
        //FIXME: Comment out the following, until metadata do not 304 when changed
519
        uri+='?changes-since=' + networks_changes_since
520

    
521
    update_request = $.ajax({
522
        cache: false,
523
        url: uri,
524
        type: "GET",
525
        timeout: TIMEOUT,
526
        dataType: "json",
527
        error: function(jqXHR, textStatus, errorThrown) {
528
            // as for now, just show an error message
529
            try {
530
                console.info('update_network names errback:' + jqXHR.status )
531
            } catch(err) {}
532
            try {
533
                ajax_error(jqXHR.status, undefined, 'Update network names', jqXHR.responseText);
534
            } catch(err) {
535
                ajax_error(0, undefined, 'Update network names', jqXHR.responseText);
536
            }
537
            return false;
538
            },
539
        success: function(data, textStatus, jqXHR) {
540
            // create changes_since string if necessary
541
            if (jqXHR.getResponseHeader('Date') != null){
542
                changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
543
                networks_changes_since = ISODateString(changes_since_date);
544
            }
545

    
546
            if (jqXHR.status == 200 || jqXHR.status == 203) {
547
                try {
548
                    networks = data.networks.values;
549
                    jQuery.parseJSON(data);
550
                    update_networks_view(servers_data, data);
551
                } catch(err) {
552
                    ajax_error('400', undefined, 'Update network names', jqXHR.responseText);
553
                }
554
            } else if (jqXHR.status == 304) {
555
                update_networks_view(servers_data);
556
            } else if (jqXHR.status != 304){
557
                try { console.info('update_network_names callback:' + jqXHR.status ) } catch(err) {}
558
                /*
559
                FIXME:  Here it should return the error, however Opera does not support 304.
560
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
561
                        304, which should be corrected (Bug #317).
562
                */
563
                //ajax_error(jqXHR.status, undefined, 'Update network names', jqXHR.responseText);
564
                update_networks_view(servers_data);
565
            }
566
            return false;
567
        }
568
    });
569
    return false;
570
}
571

    
572
// get and show a list of available standard and custom images
573
function update_images() {
574
    $.ajax({
575
        url: API_URL + '/images/detail',
576
        type: "GET",
577
        //async: false,
578
        dataType: "json",
579
        timeout: TIMEOUT,
580
        error: function(jqXHR, textStatus, errorThrown) {
581
                    try {
582
                        ajax_error(jqXHR.status, undefined, 'Update Images', jqXHR.responseText);
583
                    } catch(err) {
584
                        ajax_error(0, undefined, 'Update Images', jqXHR.responseText);
585
                    }
586
                },
587
        success: function(data, textStatus, jqXHR) {
588
            try {
589
                images = data.images.values;
590
                jQuery.parseJSON(data);
591
                update_wizard_images();
592
            } catch(err){
593
                ajax_error("NO_IMAGES");
594
            }
595
        }
596
    });
597
    return false;
598
}
599

    
600
function update_wizard_images() {
601
    if ($("ul#standard-images li").toArray().length + $("ul#custom-images li").toArray().length == 0) {
602
        $.each(images, function(i,image){
603
            var img = $('#image-template').clone().attr("id","img-"+image.id).fadeIn("slow");
604
            img.find("label").attr('for',"img-radio-" + image.id);
605
            img.find(".image-title").text(image.name);
606
            if (image.metadata) {
607
                if (image.metadata.values.description != undefined) {
608
                    img.find(".description").text(image.metadata.values.description);
609
                }
610
                if (image.metadata.values.size != undefined) {
611
                    img.find("#size").text(image.metadata.values.size);
612
                }
613
            }
614
            img.find("input.radio").attr('id',"img-radio-" + image.id);
615
            if (i==0) img.find("input.radio").attr("checked","checked");
616
            var image_logo = os_icon(image.metadata);
617
            img.find("img.image-logo").attr('src','static/icons/os/'+image_logo+'.png');
618
            if (image.metadata) {
619
                if (image.metadata.values.serverId != undefined) {
620
                    img.appendTo("ul#custom-images");
621
                } else {
622
                    img.appendTo("ul#standard-images");
623
                }
624
            } else {
625
                img.appendTo("ul#standard-images");
626
            }
627
        });
628
    }
629
}
630

    
631
function update_wizard_flavors(){
632
    // sliders for selecting VM flavor
633
    $("#cpu:range").rangeinput({min:0,
634
                               value:0,
635
                               step:1,
636
                               progress: true,
637
                               max:cpus.length-1});
638

    
639
    $("#storage:range").rangeinput({min:0,
640
                               value:0,
641
                               step:1,
642
                               progress: true,
643
                               max:disks.length-1});
644

    
645
    $("#ram:range").rangeinput({min:0,
646
                               value:0,
647
                               step:1,
648
                               progress: true,
649
                               max:ram.length-1});
650
    $("#small").click();
651

    
652
    // update the indicators when sliding
653
    $("#cpu:range").data().rangeinput.onSlide(function(event,value){
654
        $("#cpu-indicator")[0].value = cpus[Number(value)];
655
        $("#cpu-indicator").addClass('selectedrange');
656
    });
657
    $("#cpu:range").data().rangeinput.change(function(event,value){
658
        $("#cpu-indicator")[0].value = cpus[Number(value)];
659
        $("#custom").click();
660
        $("#cpu-indicator").removeClass('selectedrange');
661
    });
662
    $("#ram:range").data().rangeinput.onSlide(function(event,value){
663
        $("#ram-indicator")[0].value = ram[Number(value)];
664
        $("#ram-indicator").addClass('selectedrange');
665
    });
666
    $("#ram:range").data().rangeinput.change(function(event,value){
667
        $("#ram-indicator")[0].value = ram[Number(value)];
668
        $("#custom").click();
669
        $("#ram-indicator").removeClass('selectedrange');
670
    });
671
    $("#storage:range").data().rangeinput.onSlide(function(event,value){
672
        $("#storage-indicator")[0].value = disks[Number(value)];
673
        $("#storage-indicator").addClass('selectedrange');
674
    });
675
    $("#storage:range").data().rangeinput.change(function(event,value){
676
        $("#storage-indicator")[0].value = disks[Number(value)];
677
        $("#custom").click();
678
        $("#storage-indicator").removeClass('selectedrange');
679
    });
680
}
681

    
682
Array.prototype.unique = function () {
683
    var r = new Array();
684
    o:for(var i = 0, n = this.length; i < n; i++)
685
    {
686
        for(var x = 0, y = r.length; x < y; x++)
687
        {
688
            if(r[x]==this[i])
689
            {
690
                continue o;
691
            }
692
        }
693
        r[r.length] = this[i];
694
    }
695
    return r;
696
}
697

    
698
// get and configure flavor selection
699
function update_flavors() {
700
    $.ajax({
701
        url: API_URL + '/flavors/detail',
702
        type: "GET",
703
        //async: false,
704
        dataType: "json",
705
        timeout: TIMEOUT,
706
        error: function(jqXHR, textStatus, errorThrown) {
707
            try {
708
                ajax_error(jqXHR.status, undefined, 'Update Flavors', jqXHR.responseText);
709
            } catch (err) {
710
                ajax_error(err);
711
            }
712
            // start updating vm list
713
            update_vms(UPDATE_INTERVAL);
714
        },
715
        success: function(data, textStatus, jqXHR) {
716

    
717
            try {
718
                flavors = data.flavors.values;
719
                jQuery.parseJSON(data);
720
                $.each(flavors, function(i, flavor) {
721
                    cpus[i] = flavor['cpu'];
722
                    disks[i] = flavor['disk'];
723
                    ram[i] = flavor['ram'];
724
                });
725
                cpus = cpus.unique();
726
                disks = disks.unique();
727
                ram = ram.unique();
728
                update_wizard_flavors();
729
            } catch(err){
730
                ajax_error("NO_FLAVORS");
731
            }
732
            // start updating vm list
733
            update_vms(UPDATE_INTERVAL);
734
        }
735
    });
736
    return false;
737
}
738

    
739
// return flavorRef from cpu, disk, ram values
740
function identify_flavor(cpu, disk, ram){
741
    for (i=0;i<flavors.length;i++){
742
        if (flavors[i]['cpu'] == cpu && flavors[i]['disk']==disk && flavors[i]['ram']==ram) {
743
            return flavors[i]['id']
744
        }
745
    }
746
    return 0;
747
}
748

    
749
// return image entry from imageRef
750
function get_image(imageRef) {
751
    for (i=0;i<images.length;i++){
752
        if (images[i]['id'] == imageRef) {
753
            return images[i];
754
        }
755
    }
756
    return 0;
757
}
758

    
759
// return machine entry from serverID
760
function get_machine(serverID) {
761
    for (i=0;i<servers.length;i++){
762
        if (servers[i]['id'] == serverID) {
763
            return servers[i];
764
        }
765
    }
766
    return 0;
767
}
768

    
769
// update the actions in icon view, per server
770
function update_iconview_actions(serverID, server_status) {
771
    if ($.cookie("view")=='2') {
772
        // remove .disable from all actions to begin with
773
        $('#machinesview-single #' + serverID + ' div.single-action').show();
774
        // decide which actions should be disabled
775
        for (current_action in actions) {
776
            if (actions[current_action].indexOf(server_status) == -1 ) {
777
                $('#machinesview-single #' + serverID + ' div.action-' + current_action).hide();
778
            }
779
        }
780
    } else {
781
        // remove .disable from all actions to begin with
782
        $('#machinesview-icon.standard #' + serverID + ' div.actions').find('a').removeClass('disabled');
783
        // decide which actions should be disabled
784
        for (current_action in actions) {
785
            if (actions[current_action].indexOf(server_status) == -1 ) {
786
                $('#machinesview-icon.standard #' + serverID + ' a.action-' + current_action).addClass('disabled');
787
            }
788
        }
789
    }
790
}
791

    
792
// update the actions in list view
793
function update_listview_actions() {
794
    var states = [];
795
    var on = [];
796
    var checked = $("table.list-machines tbody input[type='checkbox']:checked");
797
    // disable all actions to begin with
798
    $('#machinesview .list div.actions').children().removeClass('enabled');
799

    
800
    // are there multiple machines selected?
801
    if (checked.length>1)
802
        states[0] = 'multiple';
803

    
804
    // check the states of selected machines
805
    checked.each(function(i,checkbox) {
806
        states[states.length] = checkbox.className;
807
        var ip = $("#" + checkbox.id.replace('input-','') + ".ip span.public").text();
808
        if (ip.replace('undefined','').length)
809
            states[states.length] = 'network';
810
    });
811

    
812
    // decide which actions should be enabled
813
    for (a in actions) {
814
        var enabled = false;
815
        for (var s =0; s<states.length; s++) {
816
            if (actions[a].indexOf(states[s]) != -1 ) {
817
                enabled = true;
818
            } else {
819
                enabled = false;
820
                break;
821
            }
822
        }
823
        if (enabled)
824
            on[on.length]=a;
825
    }
826
    // enable those actions
827
    for (action in on) {
828
        $("#action-" + on[action]).addClass('enabled');
829
    }
830
}
831

    
832
//create server action
833
function create_vm(machineName, imageRef, flavorRef){
834
    var image_logo = os_icon(get_image(imageRef).metadata);
835
    var uri = API_URL + '/servers';
836
    var payload = {
837
        "server": {
838
            "name": machineName,
839
            "imageRef": imageRef,
840
            "flavorRef" : flavorRef,
841
            "metadata" : {
842
                "OS" : image_logo
843
            }
844
        }
845
    };
846

    
847
    $.ajax({
848
    url: uri,
849
    type: "POST",
850
    contentType: "application/json",
851
    dataType: "json",
852
    data: JSON.stringify(payload),
853
    timeout: TIMEOUT,
854
    error: function(jqXHR, textStatus, errorThrown) {
855
                // close wizard and show error box
856
                $('#machines-pane a#create').data('overlay').close();
857
                    try {
858
                        ajax_error(jqXHR.status, undefined, 'Create VM', jqXHR.responseText);
859
                    } catch(err) {
860
                        ajax_error(0, undefined, 'Create VM', jqXHR.responseText);
861
                    }
862
           },
863
    success: function(data, textStatus, jqXHR) {
864
                if ( jqXHR.status == '202') {
865
                    ajax_success("CREATE_VM_SUCCESS", data.server.adminPass);
866
                } else {
867
                    // close wizard and show error box
868
                    $('#machines-pane a#create').data('overlay').close();
869
                    ajax_error(jqXHR.status, undefined, 'Create VM', jqXHR.responseText);
870
                }
871
            }
872
    });
873
}
874

    
875
// reboot action
876
function reboot(serverIDs){
877
    if (!serverIDs.length){
878
        //ajax_success('DEFAULT');
879
        return false;
880
    }
881
    // ajax post reboot call
882
    var payload = {
883
        "reboot": {"type" : "HARD"}
884
    };
885

    
886
    var serverID = serverIDs.pop();
887

    
888
    $.ajax({
889
        url: API_URL + '/servers/' + serverID + '/action',
890
        type: "POST",
891
        contentType: "application/json",
892
        dataType: "json",
893
        data: JSON.stringify(payload),
894
        timeout: TIMEOUT,
895
        error: function(jqXHR, textStatus, errorThrown) {
896
                    // in machine views
897
                    if ( $.cookie("pane") == 0) {
898
                        try {
899
                            display_failure(jqXHR.status, serverID, 'Reboot', jqXHR.responseText);
900
                        } catch (err) {
901
                            display_failure(0, serverID, 'Reboot', jqXHR.responseText);
902
                        }
903
                    }
904
                    // in network view
905
                    else {
906
                        try {
907
                            display_reboot_failure(jqXHR.status, serverID, jqXHR.responseText);
908
                        } catch (err) {
909
                            display_reboot_failure(0, serverID, jqXHR.responseText);
910
                        }
911
                    }
912
                },
913
        success: function(data, textStatus, jqXHR) {
914
                    if ( jqXHR.status == '202') {
915
                        try {
916
                            console.info('rebooted ' + serverID);
917
                        } catch(err) {}
918
                        // indicate that the action succeeded
919
                        // in machine views
920
                        if ( $.cookie("pane") == 0) {
921
                            display_success(serverID);
922
                        }
923
                        // in network view
924
                        else {
925
                            display_reboot_success(serverID);
926
                        }
927
                        // continue with the rest of the servers
928
                        reboot(serverIDs);
929
                    } else {
930
                        ajax_error(jqXHR.status, serverID, 'Reboot', jqXHR.responseText);
931
                    }
932
                }
933
    });
934
    return false;
935
}
936

    
937
// shutdown action
938
function shutdown(serverIDs) {
939
    if (!serverIDs.length){
940
        //ajax_success('DEFAULT');
941
        return false;
942
    }
943
    // ajax post shutdown call
944
    var payload = {
945
        "shutdown": {}
946
    };
947

    
948
    var serverID = serverIDs.pop();
949

    
950
    $.ajax({
951
        url: API_URL + '/servers/' + serverID + '/action',
952
        type: "POST",
953
        contentType: "application/json",
954
        dataType: "json",
955
        data: JSON.stringify(payload),
956
        timeout: TIMEOUT,
957
        error: function(jqXHR, textStatus, errorThrown) {
958
                    try {
959
                        display_failure(jqXHR.status, serverID, 'Shutdown', jqXHR.responseText);
960
                    } catch(err) {
961
                        display_failure(0, serverID, 'Shutdown', jqXHR.responseText);
962
                    }
963
                },
964
        success: function(data, textStatus, jqXHR) {
965
                    if ( jqXHR.status == '202') {
966
                        try {
967
                            console.info('suspended ' + serverID);
968
                        } catch(err) {}
969
                        // indicate that the action succeeded
970
                        display_success(serverID);
971
                        // continue with the rest of the servers
972
                        shutdown(serverIDs);
973
                    } else {
974
                        ajax_error(jqXHR.status, serverID, 'Shutdown', jqXHR.responseText);
975
                    }
976
                }
977
    });
978
    return false;
979
}
980

    
981
// destroy action
982
function destroy(serverIDs) {
983
    if (!serverIDs.length){
984
        //ajax_success('DEFAULT');
985
        return false;
986
    }
987
    // ajax post destroy call can have an empty request body
988
    var payload = {};
989

    
990
    var serverID = serverIDs.pop();
991

    
992
    $.ajax({
993
        url: API_URL + '/servers/' + serverID,
994
        type: "DELETE",
995
        contentType: "application/json",
996
        dataType: "json",
997
        data: JSON.stringify(payload),
998
        timeout: TIMEOUT,
999
        error: function(jqXHR, textStatus, errorThrown) {
1000
                    try {
1001
                        display_failure(jqXHR.status, serverID, 'Destroy', jqXHR.responseText);
1002
                    } catch(err) {
1003
                        display_failure(0, serverID, 'Destroy', jqXHR.responseText);
1004
                    }
1005
                },
1006
        success: function(data, textStatus, jqXHR) {
1007
                    if ( jqXHR.status == '204') {
1008
                        try {
1009
                            console.info('destroyed ' + serverID);
1010
                        } catch (err) {}
1011
                        // indicate that the action succeeded
1012
                        display_success(serverID);
1013
                        // continue with the rest of the servers
1014
                        destroy(serverIDs);
1015
                    } else {
1016
                        ajax_error(jqXHR.status, serverID, 'Destroy', jqXHR.responseText);
1017
                    }
1018
                }
1019
    });
1020
    return false;
1021
}
1022

    
1023
// start action
1024
function start(serverIDs){
1025
    if (!serverIDs.length){
1026
        //ajax_success('DEFAULT');
1027
        return false;
1028
    }
1029
    // ajax post start call
1030
    var payload = {
1031
        "start": {}
1032
    };
1033

    
1034
    var serverID = serverIDs.pop();
1035

    
1036
    $.ajax({
1037
        url: API_URL + '/servers/' + serverID + '/action',
1038
        type: "POST",
1039
        contentType: "application/json",
1040
        dataType: "json",
1041
        data: JSON.stringify(payload),
1042
        timeout: TIMEOUT,
1043
        error: function(jqXHR, textStatus, errorThrown) {
1044
                    try {
1045
                        display_failure(jqXHR.status, serverID, 'Start', jqXHR.responseText);
1046
                    } catch(err) {
1047
                        display_failure(0, serverID, 'Start', jqXHR.responseText);
1048
                    }
1049
                },
1050
        success: function(data, textStatus, jqXHR) {
1051
                    if ( jqXHR.status == '202') {
1052
                        try {
1053
                            console.info('started ' + serverID);
1054
                        } catch(err) {}
1055
                        // indicate that the action succeeded
1056
                        display_success(serverID);
1057
                        // continue with the rest of the servers
1058
                        start(serverIDs);
1059
                    } else {
1060
                        ajax_error(jqXHR.status, serverID, 'Start', jqXHR.responseText);
1061
                    }
1062
                }
1063
    });
1064
    return false;
1065
}
1066

    
1067
// Show VNC console
1068
function vnc_attachment(host, port, password) {
1069
    // FIXME: Must be made into parameters, in settings.py
1070
    //vnc = open("", "displayWindow",
1071
    //    "status=yes,toolbar=yes,menubar=yes");
1072
    vd = document.open("application/x-vnc");
1073

    
1074
    vd.writeln("[connection]");
1075
    vd.writeln("host=" + host);
1076
    vd.writeln("port=" + port);
1077
    vd.writeln("password=" + password);
1078

    
1079
    vd.close();
1080
}
1081

    
1082
// Show VNC console
1083
function show_vnc_console(serverID, serverName, serverIP, host, port, password) {
1084
    var params_url = '?machine=' + serverName + '&host_ip=' + serverIP + '&host=' + host + '&port=' + port + '&password=' + password;
1085
    var params_window = 'scrollbars=no,' +
1086
                        'menubar=no,' +
1087
                        'toolbar=no,' +
1088
                        'status=no,' +
1089
                        'top=0,' +
1090
                        'left=0,' +
1091
                        'height=' + screen.height + ',' +
1092
                        'width=' + screen.width + ',' +
1093
                        'fullscreen=yes';
1094

    
1095
    window.open('machines/console' + params_url, 'formresult' + serverID, params_window);
1096

    
1097
    // Restore os icon in list view
1098
    osIcon = $('#'+serverID).parent().parent().find('.list-logo');
1099
    osIcon.attr('src',osIcon.attr('os'));
1100
    return false;
1101
}
1102

    
1103
// console action
1104
function open_console(serverIDs){
1105
    if (!serverIDs.length){
1106
        //ajax_success('DEFAULT');
1107
        return false;
1108
    }
1109
    // ajax post start call
1110
    var payload = {
1111
        "console": {"type": "vnc"}
1112
    };
1113

    
1114
    var serverID = serverIDs.pop();
1115

    
1116
    var machine = get_machine(serverID);
1117
    var serverName = machine.name;
1118
    try {
1119
        var serverIP = machine.addresses.values[0].values[0].addr;
1120
    } catch(err) { var serverIP = 'undefined'; }
1121

    
1122
    $.ajax({
1123
        url: API_URL + '/servers/' + serverID + '/action',
1124
        type: "POST",
1125
        contentType: "application/json",
1126
        dataType: "json",
1127
        data: JSON.stringify(payload),
1128
        timeout: TIMEOUT,
1129
        error: function(jqXHR, textStatus, errorThrown) {
1130
                    try {
1131
                        display_failure(jqXHR.status, serverID, 'Console', jqXHR.responseText);
1132
                    } catch(err) {
1133
                        display_failure(0, serverID, 'Console', jqXHR.responseText);
1134
                    }
1135
                },
1136
        success: function(data, textStatus, jqXHR) {
1137
                    if ( jqXHR.status == '200') {
1138
                        try {
1139
                            console.info('got_console ' + serverID);
1140
                        } catch(err) {}
1141
                        // indicate that the action succeeded
1142
                        // show_vnc_console(serverID, serverName, serverIP,
1143
                        // data.console.host,data.console.port,data.console.password);
1144
                        show_vnc_console(serverID, serverName, serverIP,
1145
                                         data.console.host,data.console.port,data.console.password);
1146
                        display_success(serverID);
1147
                        // hide spinner
1148
                        $('#' + serverID + ' .spinner').hide();
1149
                        // continue with the rest of the servers
1150
                        open_console(serverIDs);
1151
                    } else {
1152
                        ajax_error(jqXHR.status, serverID, 'Console', jqXHR.responseText);
1153
                    }
1154
                }
1155
    });
1156
    return false;
1157
}
1158

    
1159
function vm_has_address(vmId) {
1160
    var vm = get_machine(vmId);
1161

    
1162
    if (!vm) return false;
1163

    
1164
    try {
1165
        var ip = vm.addresses.values[0].values[0].addr;
1166
    } catch (err) {
1167
        console.log(err);
1168
        return false;
1169
    }
1170
    return ip;
1171
}
1172

    
1173
// connect to machine action
1174
function machine_connect(serverIDs){
1175
    if (!serverIDs.length){
1176
        //ajax_success('DEFAULT');
1177
        return false;
1178
    }
1179
    var serverID = serverIDs.pop();
1180
    
1181
    var machine = get_machine(serverID);
1182
    var serverName = machine.name;
1183
    try {
1184
        var serverIP = machine.addresses.values[0].values[0].addr;
1185
    } catch(err) { var serverIP = 'undefined'; }
1186

    
1187
    try {
1188
        var os = machine.metadata.values.OS;
1189
    } catch(err) { var os = 'undefined'; }
1190

    
1191
    var params_url = '?ip_address=' + serverIP + '&os=' + os;
1192

    
1193
    //console.log(serverIP);
1194
    //console.log(machine.addresses);
1195
    //console.log(machine.addresses.values[0].values[0].addr);
1196
    
1197
    //show_connect_dialog(machine, ip);
1198
    try {
1199
        msg_box({title:'Connect to ' + serverName,content:'loading...',extra:'',
1200
        'ajax':'machines/connect' + params_url,
1201
        parse_data:function(data){
1202
            data.title = false;
1203
            data.content = data.info;
1204
            data.extra = "<a href='"+data.link.url+"'>"+data.link.title+"</a>";
1205
            return data;
1206
        }
1207
        });
1208
    } catch (error) {
1209
        console.log(error);
1210
    window.open('machines/connect' + params_url);
1211
    }
1212

    
1213

    
1214
    // Restore os icon in list view
1215
    osIcon = $('#'+serverID).parent().parent().find('.list-logo');
1216
    osIcon.attr('src',osIcon.attr('os'));
1217

    
1218
    return false;
1219
}
1220

    
1221

    
1222
// rename server
1223
function rename(serverID, serverName){
1224
    if (!serverID.length){
1225
        //ajax_success('DEFAULT');
1226
        return false;
1227
    }
1228
    // ajax post rename call
1229
    var payload = {
1230
        "server": {"name": serverName}
1231
    };
1232

    
1233
    $.ajax({
1234
        url: API_URL + '/servers/' + serverID,
1235
        type: "PUT",
1236
        contentType: "application/json",
1237
        dataType: "json",
1238
        data: JSON.stringify(payload),
1239
        timeout: TIMEOUT,
1240
        error: function(jqXHR, textStatus, errorThrown) {
1241
                    try {
1242
                        display_failure(jqXHR.status, serverID, 'Rename', jqXHR.responseText);
1243
                    } catch(err) {
1244
                        display_failure(0, serverID, 'Rename', jqXHR.responseText);
1245
                    }
1246
                },
1247
        success: function(data, textStatus, jqXHR) {
1248
                    if ( jqXHR.status == '204' || jqXHR.status == '1223') {
1249
                        try {
1250
                            console.info('renamed ' + serverID);
1251
                        } catch(err) {}
1252
                        // indicate that the action succeeded
1253
                        display_success(serverID);
1254
                    } else {
1255
                        ajax_error(jqXHR.status, serverID, 'Rename', jqXHR.responseText);
1256
                    }
1257
                }
1258
    });
1259
    return false;
1260
}
1261

    
1262
// get server metadata
1263
function get_metadata(serverID, keys_only) {
1264
    $.ajax({
1265
        url: API_URL + '/servers/' + serverID + '/meta',
1266
        cache: false,
1267
        type: "GET",
1268
        //async: false,
1269
        dataType: "json",
1270
        timeout: TIMEOUT,
1271
        error: function(jqXHR, textStatus, errorThrown) {
1272
            try {
1273
                // close wizard and show error box
1274
                $("a#metadata-scrollable").data('overlay').close();
1275
                ajax_error(jqXHR.status, undefined, 'Get metadata', jqXHR.responseText);
1276
            } catch (err) {
1277
                ajax_error(err);
1278
            }
1279
        },
1280
        success: function(data, textStatus, jqXHR) {
1281
            // to list the new results in the edit dialog
1282
            if (keys_only) {
1283
                list_metadata_keys(serverID, data.metadata.values);
1284
            } else {
1285
                list_metadata(data);
1286
                list_metadata_keys(serverID, data.metadata.values);
1287
            }
1288
            //hide spinner
1289
            $('#metadata-wizard .large-spinner').hide();
1290
        }
1291
    });
1292
    return false;
1293
}
1294

    
1295
// delete metadata key-value pair
1296
function delete_metadata(serverID, meta_key) {
1297
    $.ajax({
1298
        url: API_URL + '/servers/' + serverID + '/meta/' + meta_key,
1299
        type: "DELETE",
1300
        //async: false,
1301
        dataType: "json",
1302
        timeout: TIMEOUT,
1303
        error: function(jqXHR, textStatus, errorThrown) {
1304
            try {
1305
                // close wizard and show error box
1306
                $("a#metadata-scrollable").data('overlay').close();
1307
                ajax_error(jqXHR.status, undefined, 'Delete metadata', jqXHR.responseText);
1308
            } catch (err) {
1309
                ajax_error(err);
1310
            }
1311
        },
1312
        success: function(data, textStatus, jqXHR) {
1313
                    // success: Do nothing, the UI is already updated
1314
        }
1315
    });
1316
    return false;
1317
}
1318

    
1319
// add metadata key-value pair
1320
function update_metadata(serverID, meta_key, meta_value) {
1321
    var payload = {
1322
        "meta": {
1323
        }
1324
    };
1325
    payload["meta"][meta_key] = meta_value;
1326

    
1327
    $.ajax({
1328
        url: API_URL + '/servers/' + serverID + '/meta/' + meta_key,
1329
        type: "PUT",
1330
        contentType: "application/json",
1331
        dataType: "json",
1332
        data: JSON.stringify(payload),
1333
        timeout: TIMEOUT,
1334
        error: function(jqXHR, textStatus, errorThrown) {
1335
            try {
1336
                // close wizard and show error box
1337
                $("a#metadata-scrollable").data('overlay').close();
1338
                ajax_error(jqXHR.status, undefined, 'add metadata', jqXHR.responseText);
1339
            } catch (err) {
1340
                ajax_error(err);
1341
            }
1342
        },
1343
        success: function(data, textStatus, jqXHR) {
1344
            // success: Update icons if meta key is OS
1345
            if (meta_key == "OS") {
1346
                $("#metadata-wizard .machine-icon").attr("src","static/icons/machines/small/" + os_icon_from_value(meta_value) + '-' + $("#metadata-wizard div#on-off").text() + '.png');
1347
                var machine_icon = $("#machinesview-icon").find("div#" + serverID);
1348
                var machine_single = $("#machinesview-single").find("div#" + serverID);
1349

    
1350
                var os = os_icon_from_value(meta_value);
1351
                var state = $("#metadata-wizard div#on-off").text()
1352
                var state_single = $(".state", machine_single).hasClass("terminated-state") ? "off" : "on";
1353
                set_machine_os_image(machine_icon, "icon", state, os);
1354
                set_machine_os_image(machine_single, "single", state_single, os);
1355
            }
1356
        }
1357
    });
1358
    return false;
1359
}
1360

    
1361
// get stats
1362
function get_server_stats(serverID) {
1363
    $.ajax({
1364
        url: API_URL + '/servers/' + serverID + '/stats',
1365
        cache: false,
1366
        type: "GET",
1367
        //async: false,
1368
        dataType: "json",
1369
        timeout: TIMEOUT,
1370
        error: function(jqXHR, textStatus, errorThrown) {
1371
                // report error as text inline
1372
                $('#' + serverID + ' img.busy').hide();
1373
                $('#' + serverID + ' div.stat-error').show();
1374
        },
1375
        success: function(data, textStatus, jqXHR) {
1376
            // in icon view
1377
            if ( $.cookie('view') == 0 ) {
1378
                $('#' + serverID + ' img.busy').removeClass('busy');
1379
                $('#' + serverID + ' img.cpu').attr("src", data.stats.cpuBar);
1380
                $('#' + serverID + ' img.net').attr("src", data.stats.netBar);
1381
            }
1382
            // in single view
1383
            else if ( $.cookie('view') == 2 ) {
1384
                $('#' + serverID + ' div.cpu-graph img.stats').attr("src", data.stats.cpuTimeSeries);
1385
                $('#' + serverID + ' div.network-graph img.stats').attr("src", data.stats.netTimeSeries);
1386
            }
1387
        }
1388
    });
1389
    return false;
1390
}
1391

    
1392
// create network
1393
function create_network(networkName){
1394
    // ajax post start call
1395
    var payload = {
1396
        "network": { "name": networkName }
1397
    };
1398

    
1399
    $.ajax({
1400
        url: API_URL + '/networks',
1401
        type: "POST",
1402
        contentType: "application/json",
1403
        dataType: "json",
1404
        data: JSON.stringify(payload),
1405
        timeout: TIMEOUT,
1406
        error: function(jqXHR, textStatus, errorThrown) {
1407
            try {
1408
                // close wizard and show error box
1409
                $("a#networkscreate").overlay().close();
1410
                ajax_error(jqXHR.status, undefined, 'Create network', jqXHR.responseText);
1411
            } catch (err) {
1412
                ajax_error(err);
1413
            }
1414
        },
1415
        success: function(data, textStatus, jqXHR) {
1416
            if ( jqXHR.status == '202') {
1417
                try {
1418
                    console.info('created network ' + networkName);
1419
                } catch(err) {}
1420
                /*
1421
                On success of this call nothing happens.
1422
                When the UI gets the first update containing the created server,
1423
                the creation wizard is closed and the new network is inserted
1424
                to the DOM. This is done in update_networks_view()
1425
                */
1426
            } else {
1427
                // close wizard and show error box
1428
                $("a#networkscreate").overlay().close();
1429
                ajax_error(jqXHR.status, undefined, 'Create network', jqXHR.responseText);
1430
            }
1431
        }
1432
    });
1433
    return false;
1434
}
1435

    
1436
// rename network
1437
function rename_network(networkID, networkName){
1438
    if (!networkID.length){
1439
        //ajax_success('DEFAULT');
1440
        return false;
1441
    }
1442
    // prepare payload
1443
    var payload = {
1444
        "network": {"name": networkName}
1445
    };
1446
    // ajax call
1447
    $.ajax({
1448
        url: API_URL + '/networks/' + networkID,
1449
        type: "PUT",
1450
        contentType: "application/json",
1451
        dataType: "json",
1452
        data: JSON.stringify(payload),
1453
        timeout: TIMEOUT,
1454
        error: function(jqXHR, textStatus, errorThrown) {
1455
            try {
1456
                ajax_error(jqXHR.status, undefined, 'Rename network', jqXHR.responseText);
1457
            } catch (err) {
1458
                ajax_error(0, undefined, 'Rename network', jqXHR.responseText);
1459
            }
1460
        },
1461
        success: function(data, textStatus, jqXHR) {
1462
            if ( jqXHR.status == '204') {
1463
                try {
1464
                    console.info('renamed network' + networkID);
1465
                } catch(err) {}
1466
            } else {
1467
                ajax_error(jqXHR.status, undefined, 'Rename network', jqXHR.responseText);
1468
            }
1469
        }
1470
    });
1471
    return false;
1472
}
1473

    
1474
function delete_network(networkIDs){
1475
    if (!networkIDs.length){
1476
        //ajax_success('DEFAULT');
1477
        return false;
1478
    }
1479
    // get a network
1480
    var networkID = networkIDs.pop();
1481
    // ajax post destroy call can have an empty request body
1482
    var payload = {};
1483
    // ajax call
1484
    $.ajax({
1485
        url: API_URL + '/networks/' + networkID,
1486
        type: "DELETE",
1487
        contentType: "application/json",
1488
        dataType: "json",
1489
        data: JSON.stringify(payload),
1490
        timeout: TIMEOUT,
1491
        error: function(jqXHR, textStatus, errorThrown) {
1492
            try {
1493
                display_net_failure(jqXHR.status, networkID, 'Delete', jqXHR.responseText);
1494
            } catch (err) {
1495
                display_net_failure(0, networkID, 'Delete', jqXHR.responseText);
1496
            }
1497
        },
1498
        success: function(data, textStatus, jqXHR) {
1499
            if ( jqXHR.status == '204') {
1500
                try {
1501
                    console.info('deleted network ' + networkID);
1502
                } catch(err) {}
1503
                // continue with the rest of the servers
1504
                delete_network(networkIDs);
1505
            } else {
1506
                try {
1507
                    display_net_failure(jqXHR.status, networkID, 'Delete', jqXHR.responseText);
1508
                } catch (err) {
1509
                    display_net_failure(0, networkID, 'Delete', jqXHR.responseText);
1510
                }
1511
            }
1512
        }
1513
    });
1514
    return false;
1515
}
1516

    
1517
function add_server_to_network(networkID, serverIDs, serverNames, serverStates) {
1518
    if (!serverIDs.length){
1519
        // close the overlay when all the calls are made
1520
        $("a#add-machines-overlay").overlay().close();
1521
        return false;
1522
    }
1523
    // get a server
1524
    var serverID = serverIDs.pop();
1525
    var serverName = serverNames.pop();
1526
    var serverState = serverStates.pop();
1527
    // prepare payload
1528
    var payload = {
1529
            "add": { "serverRef": serverID }
1530
        };
1531
    // prepare ajax call
1532
    $.ajax({
1533
        url: API_URL + '/networks/' + networkID + '/action',
1534
        type: "POST",
1535
        contentType: "application/json",
1536
        dataType: "json",
1537
        data: JSON.stringify(payload),
1538
        timeout: TIMEOUT,
1539
        error: function(jqXHR, textStatus, errorThrown) {
1540
            try {
1541
                // close wizard and show error box
1542
                $("a#add-machines-overlay").data('overlay').close();
1543
                ajax_error(jqXHR.status, undefined, 'Add server to network', jqXHR.responseText);
1544
            } catch (err) {
1545
                ajax_error(0, undefined, 'Add server to network', jqXHR.responseText);
1546
            }
1547
        },
1548
        success: function(data, textStatus, jqXHR) {
1549
            if ( jqXHR.status == '202') {
1550
                try {
1551
                    console.info('added server ' + serverID + ' to network ' + networkID);
1552
                } catch(err) {}
1553
                // toggle the reboot dialog
1554
                display_reboot_dialog(networkID, serverID, serverName, serverState);
1555
                // continue with the rest of the servers
1556
                add_server_to_network(networkID, serverIDs, serverNames, serverStates);
1557
            } else {
1558
                // close wizard and show error box
1559
                $("a#add-machines-overlay").data('overlay').close();
1560
                ajax_error(jqXHR.status, undefined, 'Add server to network', jqXHR.responseText);
1561
            }
1562
        }
1563
    });
1564
    return false;
1565
}
1566

    
1567
function remove_server_from_network(networkIDs, serverIDs, serverNames, serverStates) {
1568
    if (!networkIDs.length){
1569
        //ajax_success('DEFAULT');
1570
        return false;
1571
    }
1572
    // get a network and a server
1573
    var networkID = networkIDs.pop();
1574
    var serverID = serverIDs.pop();
1575
    var serverName = serverNames.pop();
1576
    var serverState = serverStates.pop();
1577
    // prepare payload
1578
    var payload = {
1579
            "remove": { "serverRef": serverID }
1580
        };
1581
    // prepare ajax call
1582
    $.ajax({
1583
        url: API_URL + '/networks/' + networkID + '/action',
1584
        type: "POST",
1585
        contentType: "application/json",
1586
        dataType: "json",
1587
        data: JSON.stringify(payload),
1588
        timeout: TIMEOUT,
1589
        error: function(jqXHR, textStatus, errorThrown) {
1590
            try {
1591
                ajax_error(jqXHR.status, undefined, 'Remove server form network', jqXHR.responseText);
1592
            } catch (err) {
1593
                ajax_error(0, undefined, 'Remove server form network', jqXHR.responseText);
1594
            }
1595
        },
1596
        success: function(data, textStatus, jqXHR) {
1597
            if ( jqXHR.status == '202') {
1598
                try {
1599
                    console.info('deleted server ' + serverID + ' from network ' + networkID);
1600
                } catch(err) {}
1601
                // toggle the reboot dialog
1602
                display_reboot_dialog(networkID, serverID, serverName, serverState);
1603
                // continue with the rest of the servers
1604
                remove_server_form_network(networkIDs, serverIDs, serverNames, serverStates);
1605
            } else {
1606
                ajax_error(jqXHR.status, undefined, 'Remove server form network', jqXHR.responseText);
1607
            }
1608
        }
1609
    });
1610
    return false;
1611
}
1612

    
1613
function set_firewall(networkID, serverID, profile) {
1614
    if (!networkID.length || !serverID.length || !profile.length){
1615
        return false;
1616
    }
1617
    // prepare payload
1618
    var payload = {
1619
            "firewallProfile": { "profile": profile }
1620
        };
1621
    // prepare ajax call
1622
    $.ajax({
1623
        url: API_URL + '/servers/' + serverID + '/action',
1624
        type: "POST",
1625
        contentType: "application/json",
1626
        dataType: "json",
1627
        data: JSON.stringify(payload),
1628
        timeout: TIMEOUT,
1629
        error: function(jqXHR, textStatus, errorThrown) {
1630
            try {
1631
                ajax_error(jqXHR.status, undefined, 'Set firewall profile', jqXHR.responseText);
1632
            } catch (err) {
1633
                ajax_error(0, undefined, 'Set firewall profile', jqXHR.responseText);
1634
            }
1635
        },
1636
        success: function(data, textStatus, jqXHR) {
1637
            if ( jqXHR.status == '202') {
1638
                try {
1639
                    console.info('for server ' + serverID + ' set firewall profile to ' + profile);
1640
                } catch(err) {}
1641
                //remove progress gif and toggle the content
1642
                $('div#net-' + networkID + '-server-' + serverID + ' button.firewall-apply').html(VARIOUS["APPLY"]);
1643
                $('div#net-' + networkID + '-server-' + serverID + ' button.firewall-apply').attr("disabled", false);
1644
                $('div#net-' + networkID + '-server-' + serverID + ' div.firewall-header').click();
1645
                // toggle the reboot dialog
1646
                var serverName = $('div#net-' + networkID + '-server-' + serverID + ' div.machine-name-div span.name').text();
1647
                var serverState = $('div#net-' + networkID + '-server-' + serverID + ' img.logo').attr('src').split('-')[1];
1648
                serverState = serverState.split('.')[0];
1649
                display_reboot_dialog(networkID, serverID, serverName, serverState);
1650
            } else {
1651
                ajax_error(jqXHR.status, undefined, 'Set firewall profile', jqXHR.responseText);
1652
            }
1653
        }
1654
    });
1655
    return false;
1656
}
1657

    
1658
// show the welcome screen
1659
function showWelcome() {
1660
    $("#view-select").fadeOut("fast");
1661
    $("#emptymachineslist").fadeIn("fast");
1662
    $("#machinesview").hide();
1663
}
1664

    
1665
// hide the welcome screen
1666
function hideWelcome() {
1667
    $("#emptymachineslist").fadeOut("fast");
1668
    $("#view-select").fadeIn("fast");
1669
    $("div#view-select").show();
1670
    $("#machinesview").show();
1671
}
1672

    
1673
function log_server_status_change(server_entry, new_status) {
1674
    // firebug console logging
1675
    try {
1676
        if ($("#machinesview-single").length > 0) {
1677
            console.info(server_entry.find("div.machine-details div.name").text() +
1678
                        ' from ' + server_entry.find(".state-label").text() +
1679
                        ' to ' + STATUSES[new_status]);
1680
        } else {
1681
            console.info(server_entry.find("div.name span.name").text() +
1682
                        ' from ' + server_entry.find(".status").text() +
1683
                        ' to ' + STATUSES[new_status]);
1684
        }
1685
    } catch(err) {}
1686
}
1687

    
1688
function get_flavor_params(flavorRef) {
1689
    var cpus, ram, disk;
1690
    if ( flavors.length > 0 ) {
1691
        var current_flavor = '';
1692
        for (i=0; i<flavors.length; i++) {
1693
            if (flavors[i]['id'] == flavorRef) {
1694
                current_flavor = flavors[i];
1695
            }
1696
        }
1697
        cpus = current_flavor['cpu'];
1698
        ram = current_flavor['ram'];
1699
        disk = current_flavor['disk'];
1700
    } else {
1701
        cpus = 'undefined';
1702
        ram = 'undefined';
1703
        disk = 'undefined';
1704
    }
1705
    return {'cpus': cpus, 'ram': ram, 'disk': disk};
1706
}
1707

    
1708
function get_image_params(imageRef) {
1709
    var image_name, image_size;
1710
    if ( images.length > 0 ) {
1711
        var current_image = '';
1712
        for (i=0; i<images.length; i++) {
1713
            if (images[i]['id'] == imageRef) {
1714
                current_image = images[i];
1715
            }
1716
        }
1717
        try {
1718
            image_name = current_image['name'];
1719
        } catch(err) { image_name = 'undefined'; }
1720
        try{
1721
            image_size = current_image['metadata']['values']['size'];
1722
        } catch(err) { image_size = 'undefined'; }
1723
    } else {
1724
        image_name = 'undefined';
1725
        image_size = 'undefined';
1726
    }
1727
    return {'name': image_name,'size': image_size};
1728
}
1729

    
1730
function get_public_ips(server) {
1731
    var ip4, ip6;
1732
    try {
1733
        if (server.addresses.values) {
1734
            $.each (server.addresses.values, function(i, value) {
1735
                if (value.id == 'public') {
1736
                    try {
1737
                        $.each (value.values, function(i, ip) {
1738
                            if (ip.version == '4') {
1739
                                ip4 = ip.addr;
1740
                            } else if (ip.version == '6') {
1741
                                ip6 = ip.addr;
1742
                            } else {
1743
                                ip4 = 'pending';
1744
                                ip6 = 'pending';
1745
                            }
1746
                        });
1747
                    } catch (err){
1748
                        try{console.info('Server ' + server.id + ' has invalid ips')}catch(err){};
1749
                        ip4 = 'pending';
1750
                        ip6 = 'pending';
1751
                    }
1752
                }
1753
            });
1754
        }
1755
    } catch (err) {
1756
        try{console.info('Server ' + server.id + ' has no network addresses')}catch(err){};
1757
        ip4 = 'pending';
1758
        ip6 = 'pending';
1759
    }
1760
    return {'ip4': ip4, 'ip6': ip6};
1761
}
1762

    
1763
function get_private_ips(server) {
1764

    
1765
}
1766

    
1767
function close_all_overlays() {
1768
        try {
1769
                $("a#networkscreate").overlay().close();
1770
        } catch(err) {}
1771
        try {
1772
                $('a#create').overlay().close();
1773
        } catch(err) {}
1774
        try {
1775
                $("a#add-machines-overlay").overlay().close();
1776
        } catch(err) {}
1777
        try {
1778
                $("a#metadata-scrollable").overlay().close();
1779
        } catch(err) {}
1780
}
1781

    
1782
// logout
1783
function user_session_logout() {
1784
    $.cookie("X-Auth-Token", null);
1785
    if (window.LOGOUT_REDIRECT !== undefined)
1786
    {
1787
        window.location = window.LOGOUT_REDIRECT;
1788
    } else {
1789
        window.location.reload();
1790
    }
1791
}
1792

    
1793
// action indicators
1794
function init_action_indicator_handlers(machines_view)
1795
{
1796
    // init once for each view
1797
    if (window.ACTION_ICON_HANDLERS == undefined)
1798
    {
1799
        window.ACTION_ICON_HANDLERS = {};
1800
    }
1801

    
1802
    if (machines_view in window.ACTION_ICON_HANDLERS)
1803
    {
1804
        return;
1805
    }
1806
    window.ACTION_ICON_HANDLERS[machines_view] = 1;
1807

    
1808
    if (machines_view == "list")
1809
    {
1810
        // totally different logic for list view
1811
        init_action_indicator_list_handlers();
1812
        return;
1813
    }
1814

    
1815
    function update_action_icon_indicators(force)
1816
    {
1817
        function show(el, action) {
1818
            $(".action-indicator", $(el)).attr("class", "action-indicator " + action);
1819
            $(".action-indicator", $(el)).show();
1820
        }
1821

    
1822
        function hide(el) {
1823
            $(".action-indicator", $(el)).hide();
1824
        }
1825

    
1826
        function get_pending_actions(el) {
1827
            return $(".confirm_single:visible", $(el));
1828
        }
1829

    
1830
        function other_indicators(el) {
1831
           return $("img.wave:visible, img.spinner:visible", $(el))
1832
        }
1833

    
1834
        $("div.machine:visible, div.single-container").each(function(index, el){
1835
            var el = $(el);
1836
            var pending = get_pending_actions(el);
1837
            var other = other_indicators(el);
1838
            var action = undefined;
1839
            var force_action = force;
1840
            var visible = $(el).css("display") == "block";
1841

    
1842
            if (force_action !==undefined && force_action.el !== el[0]) {
1843
                // force action for other vm
1844
                // skipping force action
1845
                force_action = undefined;
1846
            }
1847

    
1848
            if (force_action !==undefined && force_action.el === el[0]) {
1849
                action = force_action.action;
1850
            }
1851

    
1852
            if (other.length >= 1) {
1853
                return;
1854
            }
1855

    
1856
            if (pending.length >= 1 && force_action === undefined) {
1857
                action = $(pending.parent()).attr("class").replace("action-container","");
1858
            }
1859

    
1860
            if (action in {'console':''}) {
1861
                return;
1862
            }
1863

    
1864
            if (action !== undefined) {
1865
                show(el, action);
1866
            } else {
1867
                try {
1868
                    if (el.attr('id') == pending_actions[0][1])
1869
                    {
1870
                        return;
1871
                    }
1872
                } catch (err) {
1873
                }
1874
                hide(el);
1875
            }
1876

    
1877
        });
1878
    }
1879

    
1880
    // action indicators
1881
    $(".action-container").live('mouseover', function(evn) {
1882
        force_action = {'el': $(evn.currentTarget).parent().parent()[0], 'action':$(evn.currentTarget).attr("class").replace("action-container","")};
1883
        // single view case
1884
        if ($(force_action.el).attr("class") == "upper")
1885
        {
1886
            force_action.el = $(evn.currentTarget).parent().parent().parent()[0]
1887
        };
1888
        update_action_icon_indicators(force_action);
1889
    });
1890

    
1891
    $("img.spinner, img.wave").live('hide', function(){
1892
        update_action_icon_indicators();
1893
    });
1894
    // register events where icons should get updated
1895

    
1896
    // hide action indicator image on mouse out, spinner appear, wave appear
1897
    $(".action-container").live("mouseout", function(evn){
1898
        update_action_icon_indicators();
1899
    });
1900

    
1901
    $(".confirm_single").live("click", function(evn){
1902
        update_action_icon_indicators();
1903
    });
1904

    
1905
    $("img.spinner, img.wave").live('show', function(){
1906
        $("div.action-indicator").hide();
1907
    });
1908

    
1909
    $(".confirm_single button.no").live('click', function(evn){
1910
        $("div.action-indicator", $(evn.currentTarget).parent().parent()).hide();
1911
    });
1912

    
1913
    $(".confirm_multiple button.no").click(function(){
1914
        $("div.action-indicator").hide();
1915
    });
1916

    
1917
    $(".confirm_multiple button.yes").click(function(){
1918
        $("div.action-indicator").hide();
1919
    });
1920
}
1921

    
1922
function init_action_indicator_list_handlers()
1923
{
1924
    var skip_actions = { 'console':'','connect':'','details':'' };
1925

    
1926
    var has_pending_confirmation = function()
1927
    {
1928
        return $(".confirm_multiple:visible").length >= 1
1929
    }
1930

    
1931
    function update_action_indicator_icons(force_action, skip_pending)
1932
    {
1933
        // pending action based on the element class
1934
        var pending_action = $(".selected", $(".actions"))[0];
1935
        var selected = get_list_view_selected_machine_rows();
1936

    
1937
        // reset previous state
1938
        list_view_hide_action_indicators();
1939

    
1940
        if (pending_action == undefined && !force_action)
1941
        {
1942
            // no action selected
1943
            return;
1944
        }
1945

    
1946
        if (force_action != undefined)
1947
        {
1948
            // user forced action choice
1949
            var action_class = force_action;
1950
        } else {
1951
            // retrieve action name (reboot, stop, etc..)
1952
            var action_class = $(pending_action).attr("id").replace("action-","");
1953
        }
1954

    
1955
        selected.each(function(index, el) {
1956
            if (has_pending_confirmation() && skip_pending)
1957
            {
1958
                return;
1959
            }
1960
            var el = $(el);
1961
            var logo = $("img.list-logo", el);
1962
            $(".action-indicator", el).remove();
1963
            var cls = "action-indicator " + action_class;
1964
            // add icon div
1965
            logo.after('<div class="' + cls + '"></div>');
1966
            // hide os logo
1967
            $("img.list-logo", el).hide();
1968
        });
1969
    }
1970

    
1971
    // on mouseover we force the images to the hovered action
1972
    $(".actions a").live("mouseover", function(evn) {
1973
        var el = $(evn.currentTarget);
1974
        if (!el.hasClass("enabled"))
1975
        {
1976
            return;
1977
        }
1978
        var action_class = el.attr("id").replace("action-","");
1979
        if (action_class in skip_actions)
1980
        {
1981
            return;
1982
        }
1983
        update_action_indicator_icons(action_class, false);
1984
    });
1985

    
1986

    
1987
    // register events where icons should get updated
1988
    $(".actions a.enabled").live("click", function(evn) {
1989
        // clear previous selections
1990
        $("a.selected").removeClass("selected");
1991

    
1992
        var el = $(evn.currentTarget);
1993
        el.addClass("selected");
1994
        update_action_indicator_icons(undefined, false);
1995
    });
1996

    
1997
    $(".actions a").live("mouseout", function(evn) {
1998
        update_action_indicator_icons(undefined, false);
1999
    });
2000

    
2001
    $(".confirm_multiple button.no").click(function(){
2002
        list_view_hide_action_indicators();
2003
    });
2004

    
2005
    $(".confirm_multiple button.yes").click(function(){
2006
        list_view_hide_action_indicators();
2007
    });
2008

    
2009
    $("input[type=checkbox]").live('change', function(){
2010
        // pending_actions will become empty on every checkbox click/change
2011
        // line 154 machines_list.html
2012
        pending_actions = [];
2013
        if (pending_actions.length == 0)
2014
        {
2015
            $(".confirm_multiple").hide();
2016
            $("a.selected").each(function(index, el){$(el).removeClass("selected")});
2017
        }
2018
        update_action_indicator_icons(undefined, false);
2019
    });
2020

    
2021
}
2022

    
2023
function list_view_hide_action_indicators()
2024
{
2025
    $("tr td .action-indicator").remove();
2026
    $("tr td img.list-logo").show();
2027
}
2028

    
2029
function get_list_view_selected_machine_rows()
2030
{
2031
    var table = $("table.list-machines");
2032
    var rows = $("tr:has(input[type=checkbox]:checked)",table);
2033
    return rows;
2034
}
2035

    
2036
// machines images utils
2037
function set_machine_os_image(machine, machines_view, state, os, skip_reset_states, remove_state) {
2038
    var views_map = {'single': '.single-image', 'icon': '.logo'};
2039
    var states_map = {'on': 'state1', 'off': 'state3', 'hover': 'state4', 'click': 'state2'}
2040
    var sizes_map = {'single': 'large', 'icon': 'medium'}
2041

    
2042
    var size = sizes_map[machines_view];
2043
    var img_selector = views_map[machines_view];
2044
    var cls = states_map[state];
2045

    
2046
    if (os === "unknown") { os = "okeanos" } ;
2047
    var new_img = 'url("./static/icons/machines/' + size + '/' + os + '-sprite.png")';
2048

    
2049
    var el = $(img_selector, machine);
2050
    var current_img = el.css("backgroundImage");
2051
    if (os == undefined){
2052
        new_img = current_img;
2053
    }
2054

    
2055
    // os changed
2056
    el.css("backgroundImage", new_img);
2057

    
2058
    // reset current state
2059
    if (skip_reset_states === undefined)
2060
    {
2061
        el.removeClass("single-image-state1");
2062
        el.removeClass("single-image-state2");
2063
        el.removeClass("single-image-state3");
2064
        el.removeClass("single-image-state4");
2065
    }
2066

    
2067
    if (remove_state !== undefined)
2068
    {
2069
        remove_state = "single-image-" + states_map[remove_state];
2070
        el.removeClass(remove_state);
2071
        return;
2072
    }
2073
    
2074
    // set proper state
2075
    el.addClass("single-image-" + cls);
2076
}
2077

    
2078

    
2079
// generic info box
2080

    
2081
function msg_box(config) {
2082
    var config = $.extend({'title':'Info message', 'content': 'this is an info message', 'ajax': false, 'extra':false}, config);
2083
    // prepare the error message
2084
    // bring up success notification
2085

    
2086
    var box = $("#notification-box");
2087
    box.addClass('success');
2088
    box.removeClass('error');
2089

    
2090
    var sel = function(s){console.log(box); return $(s, box)};
2091

    
2092
    sel("h3 span.header-box").text(config.title);
2093
    sel("div.machine-now-building").html(config.content);
2094
    sel(".popup-header").removeClass("popup-header-error");
2095
    box.removeClass("popup-border-error");
2096
    sel(".popup-details").removeClass("popup-details-error");
2097
    sel(".popup-separator").removeClass("popup-separator-error");
2098
    
2099
    sel(".password-container").hide();
2100
    if (config.extra) {
2101
        sel(".password-container .password").html(config.extra);
2102
        sel(".password-container").show();
2103
    }
2104

    
2105
    var triggers = $("a#msgbox").overlay({
2106
        // some mask tweaks suitable for modal dialogs
2107
        mask: '#666',
2108
        top: 'center',
2109
        closeOnClick: false,
2110
        oneInstance: false,
2111
        load: false,
2112
        onClose: function () {
2113
            // With partial refresh working properly,
2114
            // it is no longer necessary to refresh the whole page
2115
            // choose_view();
2116
        }
2117
    });
2118
    $("a#msgbox").data('overlay').load();
2119
    
2120
    var parse_data = config.parse_data || false;
2121
    if (config.ajax) {
2122
        $.ajax({ 
2123
            url:config.ajax, 
2124
            success: function(data){
2125
                if (parse_data) {
2126
                    data = parse_data(data);
2127
                }
2128

    
2129
                if (data.title)
2130
                    sel("h3 span.header-box").text(data.title);
2131

    
2132
                if (data.content)
2133
                    sel("div.machine-now-building").html(data.content);
2134

    
2135
                if (data.extra) {
2136
                    sel(".password-container .password").html(data.extra);
2137
                    sel(".password-container").show();
2138
                }
2139
            }
2140
        });
2141
    }
2142
    return false;
2143
}