Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ 9eefb3a2

History | View | Annotate | Download (72.2 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
var error_timeout = 20000;
42
$.ajaxSetup({
43
    'beforeSend': function(xhr) {
44
          xhr.setRequestHeader("X-Auth-Token", $.cookie("X-Auth-Token"));
45
    },
46

    
47
    // catch uncaught error requests
48
    // stop interaction and show only for the 5xx errors
49
    // refresh the page after 20secs
50
    error: function(jqXHR, textStatus, errorThrown) {
51
        // stop interaction for important (aka 500) error codes only
52
        if (jqXHR.status >= 500 && jqXHR.status < 600)
53
        {
54
            try {
55
                ajax_error(jqXHR.status, undefined, 'Unknown', jqXHR.responseText);
56
            } catch(err) {
57
                ajax_error(0, undefined, 'Unknown', jqXHR.responseText);
58
            }
59
        }
60

    
61
        // refresh after 10 seconds
62
        window.setTimeout("window.location.reload()", window.error_timeout);
63
    }
64
});
65

    
66

    
67
// jquery show/hide events
68
var _oldshow = $.fn.show;
69
$.fn.show = function(speed, callback) {
70
    $(this).trigger('show');
71
    return _oldshow.apply(this,arguments);
72
}
73
var _oldhide = $.fn.hide;
74
$.fn.hide = function(speed, callback) {
75
    $(this).trigger('hide');
76
    return _oldhide.apply(this,arguments);
77
}
78

    
79
function ISODateString(d){
80
    //return a date in an ISO 8601 format using UTC.
81
    //do not include time zone info (Z) at the end
82
    //taken from the Mozilla Developer Center
83
    function pad(n){ return n<10 ? '0'+n : n }
84
    return  d.getUTCFullYear()+ '-' +
85
            pad(d.getUTCMonth()+1) + '-' +
86
            pad(d.getUTCDate()) + 'T' +
87
            pad(d.getUTCHours()) + ':' +
88
            pad(d.getUTCMinutes()) + ':' +
89
            pad(d.getUTCSeconds()) +'Z'
90
}
91

    
92
function parse_error(responseText, errorCode){
93
    var errors = [];
94
    try {
95
        responseObj = JSON.parse(responseText);
96
    }
97
    catch(err) {
98
        errors[0] = {'code': errorCode};
99
        return errors;
100
    }
101
    for (var err in responseObj){
102
        errors[errors.length] = responseObj[err];
103
    }
104
    return errors;
105
}
106

    
107
// indexOf prototype for IE
108
if (!Array.prototype.indexOf) {
109
  Array.prototype.indexOf = function(elt /*, from*/) {
110
    var len = this.length;
111
    var from = Number(arguments[1]) || 0;
112
    from = (from < 0)
113
         ? Math.ceil(from)
114
         : Math.floor(from);
115
    if (from < 0)
116
      from += len;
117

    
118
    for (; from < len; from++) {
119
      if (from in this &&
120
          this[from] === elt)
121
        return from;
122
    }
123
    return -1;
124
  };
125
}
126

    
127
// trim prototype for IE
128
if(typeof String.prototype.trim !== 'function') {
129
    String.prototype.trim = function() {
130
        return this.replace(/^\s+|\s+$/g, '');
131
    }
132
}
133

    
134
function update_confirmations() {
135
    // hide all confirm boxes to begin with
136
    $('#machines-pane div.confirm_single').hide();
137
    $('#machines-pane div.confirm_multiple').hide();
138
    var action_type = [];
139
    // standard view or single view
140
    if ($.cookie("view") == '0' || $.cookie("view") == '2') {
141
        for (var i=0; i<pending_actions.length; i++) {
142
            // show single confirms
143
            if (pending_actions[i][0] == reboot) {
144
                action_type = "reboot";
145
            } else if (pending_actions[i][0] == shutdown) {
146
                action_type = "shutdown";
147
            } else if (pending_actions[i][0] == start) {
148
                action_type = "start";
149
            } else if (pending_actions[i][0] == open_console) {
150
                action_type = "console";
151
            } else {
152
                action_type = "destroy";
153
            }
154
            $("#machines-pane #" + pending_actions[i][1] +
155
            " div.action-container." + action_type + " div.confirm_single").show();
156
        }
157
    }
158
    // if more than one pending action show multiple confirm box
159
    if (pending_actions.length>1 || $.cookie("view") == '1' && pending_actions.length == 1){
160
        $('#machines-pane div.confirm_multiple span.actionLen').text(pending_actions.length);
161
        $('#machines-pane div.confirm_multiple').show();
162
    }
163
}
164

    
165
function update_network_confirmations(){
166
    // hide all confirm boxes to begin with
167
    $('#networks-pane div.confirm_multiple').hide();
168

    
169
    for (var i=0;i<pending_actions.length;i++){
170
        // show single confirms depending on the action
171
        if (pending_actions[i][0] == delete_network) {
172
            $("#networks-pane div.network#net-"+pending_actions[i][1]).children('.confirm_single').show();
173
        } else if (pending_actions[i][0] == remove_server_from_network) {
174
            $("#networks-pane div.network #net-"+pending_actions[i][1]+"-server-"+pending_actions[i][2]).children('.confirm_single').show();
175
        } // else {}
176
    }
177

    
178
    // if more than one pending action show multiple confirm box
179
    if (pending_actions.length > 1){
180
        $('#networks-pane div.confirm_multiple span.actionLen').text(pending_actions.length);
181
        $('#networks-pane div.confirm_multiple').show();
182
    }
183
}
184

    
185
function list_view() {
186
    changes_since = 0; // to reload full list
187
    pending_actions = []; // clear pending actions
188
    update_confirmations();
189
    clearTimeout(deferred);    // clear old deferred calls
190
    try {
191
        update_request.abort(); // cancel pending ajax updates
192
        load_request.abort();
193
    }catch(err){}
194
    $.cookie("view", '1'); // set list cookie
195
    uri = $("a#list").attr("href");
196
    load_request = $.ajax({
197
        url: uri,
198
        type: "GET",
199
        timeout: TIMEOUT,
200
        dataType: "html",
201
        error: function(jqXHR, textStatus, errorThrown) {
202
            return false;
203
        },
204
        success: function(data, textStatus, jqXHR) {
205
            $("a#list")[0].className += ' activelink';
206
            $("a#standard")[0].className = '';
207
            $("a#single")[0].className = '';
208
            $("div#machinesview").html(data);
209
        }
210
    });
211
    return false;
212
}
213

    
214
function single_view() {
215
    changes_since = 0; // to reload full list
216
    pending_actions = []; // clear pending actions
217
    update_confirmations();
218
    clearTimeout(deferred);    // clear old deferred calls
219
    try {
220
        update_request.abort(); // cancel pending ajax updates
221
        load_request.abort();
222
    }catch(err){}
223
    $.cookie("view", '2'); // set list cookie
224
    uri = $("a#single").attr("href");
225
    load_request = $.ajax({
226
        url: uri,
227
        type: "GET",
228
        timeout: TIMEOUT,
229
        dataType: "html",
230
        error: function(jqXHR, textStatus, errorThrown) {
231
            return false;
232
        },
233
        success: function(data, textStatus, jqXHR) {
234
            $("a#single")[0].className += ' activelink';
235
            $("a#standard")[0].className = '';
236
            $("a#list")[0].className = '';
237
            $("div#machinesview").html(data);
238
        }
239
    });
240
    return false;
241
}
242

    
243
function standard_view() {
244
    changes_since = 0; // to reload full list
245
    pending_actions = []; // clear pending actions
246
    update_confirmations();
247
    clearTimeout(deferred);    // clear old deferred calls
248
    try {
249
        update_request.abort() // cancel pending ajax updates
250
        load_request.abort();
251
    }catch(err){}
252
    $.cookie("view", '0');
253
    uri = $("a#standard").attr("href");
254
    load_request = $.ajax({
255
        url: uri,
256
        type: "GET",
257
        timeout: TIMEOUT,
258
        dataType: "html",
259
        error: function(jqXHR, textStatus, errorThrown) {
260
            return false;
261
        },
262
        success: function(data, textStatus, jqXHR) {
263
            $("a#standard")[0].className += ' activelink';
264
            $("a#list")[0].className = '';
265
            $("a#single")[0].className = '';
266
            $("div#machinesview").html(data);
267
        }
268
    });
269
    return false;
270
}
271

    
272
function choose_view() {
273
    if ($.cookie("view")=='1') {
274
        list_view();
275
    } else if ($.cookie("view")=='2'){
276
        single_view();
277
    } else {
278
        standard_view();
279
    }
280
}
281

    
282
// return value from metadata key "OS", if it exists
283
function os_icon(metadata) {
284
    if (!metadata) {
285
        return 'okeanos';
286
    }
287
    if (metadata.values.OS == undefined || metadata.values.OS == '') {
288
        return 'okeanos';
289
    } else {
290
        if (os_icons.indexOf(metadata.values.OS) == -1) {
291
            return 'okeanos';
292
        } else {
293
            return metadata.values.OS;
294
        }
295
    }
296
}
297

    
298
function os_icon_from_value(metadata) {
299
    if (!metadata) {
300
        return 'okeanos';
301
    }
302
if (metadata == undefined || metadata == '') {
303
        return 'okeanos';
304
    } else {
305
        if (os_icons.indexOf(metadata) == -1) {
306
            return 'okeanos';
307
        } else {
308
            return metadata;
309
        }
310
    }
311
}
312

    
313
// get and show a list of running and terminated machines
314
function update_vms(interval) {
315
    try{ console.info('updating machines'); } catch(err){}
316
    var uri= API_URL + '/servers/detail';
317

    
318
    if (changes_since != 0)
319
        uri+='?changes-since='+changes_since
320

    
321
    update_request = $.ajax({
322
        cache: false,
323
        url: uri,
324
        type: "GET",
325
        timeout: TIMEOUT,
326
        dataType: "json",
327
        error: function(jqXHR, textStatus, errorThrown) {
328
            // don't forget to try again later
329
            if (interval) {
330
                clearTimeout(deferred);    // clear old deferred calls
331
                deferred = setTimeout(function() {update_vms(interval);},interval,interval);
332
            }
333
            // as for now, just show an error message
334
            try { console.info('update_vms errback:' + jqXHR.status ) } catch(err) {}
335
            try {
336
                ajax_error(jqXHR.status, undefined, 'Update VMs', jqXHR.responseText);
337
            } catch(err) {
338
                ajax_error(0, undefined, 'Update VMs', jqXHR.responseText);
339
            }
340
            return false;
341
            },
342
        success: function(data, textStatus, jqXHR) {
343
            // create changes_since string if necessary
344
            if (jqXHR.getResponseHeader('Date') != null){
345
                changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
346
                changes_since = ISODateString(changes_since_date);
347
            }
348

    
349
            if (interval) {
350
                clearTimeout(deferred);    // clear old deferred calls
351
                deferred = setTimeout(function() {update_vms(interval);},interval,interval);
352
            }
353

    
354
            if (jqXHR.status == 200 || jqXHR.status == 203) {
355
                try {
356
                    //servers = data.servers.values;
357
                    update_servers_data(data.servers.values, data);
358
                    jQuery.parseJSON(data);
359
                    update_machines_view(data);
360
                } catch(err) { ajax_error('400', undefined, 'Update VMs', jqXHR.responseText);}
361
            } else if (jqXHR.status != 304){
362
                try { console.info('update_vms callback:' + jqXHR.status ) } catch(err) {}
363
                /*
364
                FIXME:  Here it should return the error, however Opera does not support 304.
365
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
366
                        304, which should be corrected (Bug #317).
367
                */
368
                //ajax_error(jqXHR.status, undefined, 'Update VMs', jqXHR.responseText);
369
            }
370
            return false;
371
        }
372
    });
373
    return false;
374
}
375

    
376
function update_servers_data(servers_update, data) {
377
    $(window).trigger("vm:update", servers_update, data);
378

    
379
    // first call
380
    if (!window.servers || window.servers.length == 0) {
381
        window.servers = servers_update;
382
        return;
383
    }
384
    
385
    // server exists helper
386
    server_exists = function(server) {
387
        var id = server.id;
388
        var found = false;
389
        var index = 0;
390
        $.each(servers, function(i, s) {
391
            if (s.id == id) { found = true, index = i };
392
        });
393
        if (found)
394
            return [found, index];
395

    
396
        return false;
397
    }
398

    
399
    // merge object properties
400
    merge = function() {
401
        var initial = arguments[0];
402
        var status_changed = undefined;
403
        $.each(arguments, function(index, el) {
404
            $.each(el, function(key,v) {
405
                // new attribute added
406
                var previous_value = initial[key];
407

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

    
457
// get a list of running and terminated machines, used in network view
458
function update_networks(interval) {
459
    try{ console.info('updating networks'); } catch(err){}
460
    var uri= API_URL + '/servers/detail';
461

    
462
    if (changes_since != 0)
463
        uri+='?changes-since='+changes_since
464

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

    
493
            if (interval) {
494
                clearTimeout(deferred);    // clear old deferred calls
495
                deferred = setTimeout(function() {update_networks(interval);},interval,interval);
496
            }
497

    
498
            if (jqXHR.status == 200 || jqXHR.status == 203) {
499
                try {
500
                    //servers = data.servers.values;
501
                    update_servers_data(data.servers.values, data);
502
                    jQuery.parseJSON(data);
503
                    update_network_names(data);
504
                } catch(err) { ajax_error('400', undefined, 'Update networks', jqXHR.responseText);}
505
            } else if (jqXHR.status == 304) {
506
                update_network_names();
507
            }
508
            else {
509
                try { console.info('update_networks callback:' + jqXHR.status ) } catch(err) {}
510
                /*
511
                FIXME:  Here it should return the error, however Opera does not support 304.
512
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
513
                        304, which should be corrected (Bug #317).
514
                */
515
                //ajax_error(jqXHR.status, undefined, 'Update networks', jqXHR.responseText);
516
                update_network_names();
517
            }
518
            return false;
519
        }
520
    });
521
    return false;
522
}
523

    
524
// get and show a list of public and private networks
525
function update_network_names(servers_data) {
526
    try{ console.info('updating network names'); } catch(err){}
527
    var uri= API_URL + '/networks/detail';
528

    
529
    if (networks_changes_since != 0)
530
        //FIXME: Comment out the following, until metadata do not 304 when changed
531
        uri+='?changes-since=' + networks_changes_since
532

    
533
    update_request = $.ajax({
534
        cache: false,
535
        url: uri,
536
        type: "GET",
537
        timeout: TIMEOUT,
538
        dataType: "json",
539
        error: function(jqXHR, textStatus, errorThrown) {
540
            // as for now, just show an error message
541
            try {
542
                console.info('update_network names errback:' + jqXHR.status )
543
            } catch(err) {}
544
            try {
545
                ajax_error(jqXHR.status, undefined, 'Update network names', jqXHR.responseText);
546
            } catch(err) {
547
                ajax_error(0, undefined, 'Update network names', jqXHR.responseText);
548
            }
549
            return false;
550
            },
551
        success: function(data, textStatus, jqXHR) {
552
            // create changes_since string if necessary
553
            if (jqXHR.getResponseHeader('Date') != null){
554
                changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
555
                networks_changes_since = ISODateString(changes_since_date);
556
            }
557

    
558
            if (jqXHR.status == 200 || jqXHR.status == 203) {
559
                try {
560
                    networks = data.networks.values;
561
                    jQuery.parseJSON(data);
562
                    update_networks_view(servers_data, data);
563
                } catch(err) {
564
                    ajax_error('400', undefined, 'Update network names', jqXHR.responseText);
565
                }
566
            } else if (jqXHR.status == 304) {
567
                update_networks_view(servers_data);
568
            } else if (jqXHR.status != 304){
569
                try { console.info('update_network_names callback:' + jqXHR.status ) } catch(err) {}
570
                /*
571
                FIXME:  Here it should return the error, however Opera does not support 304.
572
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
573
                        304, which should be corrected (Bug #317).
574
                */
575
                //ajax_error(jqXHR.status, undefined, 'Update network names', jqXHR.responseText);
576
                update_networks_view(servers_data);
577
            }
578
            return false;
579
        }
580
    });
581
    return false;
582
}
583

    
584
// get and show a list of available standard and custom images
585
function update_images() {
586
    $.ajax({
587
        url: API_URL + '/images/detail',
588
        type: "GET",
589
        //async: false,
590
        dataType: "json",
591
        timeout: TIMEOUT,
592
        error: function(jqXHR, textStatus, errorThrown) {
593
                    try {
594
                        ajax_error(jqXHR.status, undefined, 'Update Images', jqXHR.responseText);
595
                    } catch(err) {
596
                        ajax_error(0, undefined, 'Update Images', jqXHR.responseText);
597
                    }
598
                },
599
        success: function(data, textStatus, jqXHR) {
600
            try {
601
                images = data.images.values;
602
                jQuery.parseJSON(data);
603
                update_wizard_images();
604
            } catch(err){
605
                ajax_error("NO_IMAGES");
606
            }
607
        }
608
    });
609
    return false;
610
}
611

    
612
function update_wizard_images() {
613
    if ($("ul#standard-images li").toArray().length + $("ul#custom-images li").toArray().length == 0) {
614
        $.each(images, function(i,image){
615
            var img = $('#image-template').clone().attr("id","img-"+image.id).fadeIn("slow");
616
            img.find("label").attr('for',"img-radio-" + image.id);
617
            img.find(".image-title").text(image.name);
618
            if (image.metadata) {
619
                if (image.metadata.values.description != undefined) {
620
                    img.find(".description").text(image.metadata.values.description);
621
                }
622
                if (image.metadata.values.size != undefined) {
623
                    img.find("#size").text(image.metadata.values.size);
624
                }
625
            }
626
            img.find("input.radio").attr('id',"img-radio-" + image.id);
627
            if (i==0) img.find("input.radio").attr("checked","checked");
628
            var image_logo = os_icon(image.metadata);
629
            img.find("img.image-logo").attr('src','static/icons/os/'+image_logo+'.png');
630
            if (image.metadata) {
631
                if (image.metadata.values.serverId != undefined) {
632
                    img.appendTo("ul#custom-images");
633
                } else {
634
                    img.appendTo("ul#standard-images");
635
                }
636
            } else {
637
                img.appendTo("ul#standard-images");
638
            }
639
        });
640
    }
641
}
642

    
643
function update_wizard_flavors(){
644
    // sliders for selecting VM flavor
645
    $("#cpu:range").rangeinput({min:0,
646
                               value:0,
647
                               step:1,
648
                               progress: true,
649
                               max:cpus.length-1});
650

    
651
    $("#storage:range").rangeinput({min:0,
652
                               value:0,
653
                               step:1,
654
                               progress: true,
655
                               max:disks.length-1});
656

    
657
    $("#ram:range").rangeinput({min:0,
658
                               value:0,
659
                               step:1,
660
                               progress: true,
661
                               max:ram.length-1});
662
    $("#small").click();
663

    
664
    // update the indicators when sliding
665
    $("#cpu:range").data().rangeinput.onSlide(function(event,value){
666
        $("#cpu-indicator")[0].value = cpus[Number(value)];
667
        $("#cpu-indicator").addClass('selectedrange');
668
    });
669
    $("#cpu:range").data().rangeinput.change(function(event,value){
670
        $("#cpu-indicator")[0].value = cpus[Number(value)];
671
        $("#custom").click();
672
        $("#cpu-indicator").removeClass('selectedrange');
673
    });
674
    $("#ram:range").data().rangeinput.onSlide(function(event,value){
675
        $("#ram-indicator")[0].value = ram[Number(value)];
676
        $("#ram-indicator").addClass('selectedrange');
677
    });
678
    $("#ram:range").data().rangeinput.change(function(event,value){
679
        $("#ram-indicator")[0].value = ram[Number(value)];
680
        $("#custom").click();
681
        $("#ram-indicator").removeClass('selectedrange');
682
    });
683
    $("#storage:range").data().rangeinput.onSlide(function(event,value){
684
        $("#storage-indicator")[0].value = disks[Number(value)];
685
        $("#storage-indicator").addClass('selectedrange');
686
    });
687
    $("#storage:range").data().rangeinput.change(function(event,value){
688
        $("#storage-indicator")[0].value = disks[Number(value)];
689
        $("#custom").click();
690
        $("#storage-indicator").removeClass('selectedrange');
691
    });
692
}
693

    
694
Array.prototype.unique = function () {
695
    var r = new Array();
696
    o:for(var i = 0, n = this.length; i < n; i++)
697
    {
698
        for(var x = 0, y = r.length; x < y; x++)
699
        {
700
            if(r[x]==this[i])
701
            {
702
                continue o;
703
            }
704
        }
705
        r[r.length] = this[i];
706
    }
707
    return r;
708
}
709

    
710
// get and configure flavor selection
711
function update_flavors() {
712
    $.ajax({
713
        url: API_URL + '/flavors/detail',
714
        type: "GET",
715
        //async: false,
716
        dataType: "json",
717
        timeout: TIMEOUT,
718
        error: function(jqXHR, textStatus, errorThrown) {
719
            try {
720
                ajax_error(jqXHR.status, undefined, 'Update Flavors', jqXHR.responseText);
721
            } catch (err) {
722
                ajax_error(err);
723
            }
724
            // start updating vm list
725
            update_vms(UPDATE_INTERVAL);
726
        },
727
        success: function(data, textStatus, jqXHR) {
728

    
729
            try {
730
                flavors = data.flavors.values;
731
                jQuery.parseJSON(data);
732
                $.each(flavors, function(i, flavor) {
733
                    cpus[i] = flavor['cpu'];
734
                    disks[i] = flavor['disk'];
735
                    ram[i] = flavor['ram'];
736
                });
737
                cpus = cpus.unique();
738
                disks = disks.unique();
739
                ram = ram.unique();
740
                update_wizard_flavors();
741
            } catch(err){
742
                ajax_error("NO_FLAVORS");
743
            }
744
            // start updating vm list
745
            update_vms(UPDATE_INTERVAL);
746
        }
747
    });
748
    return false;
749
}
750

    
751
// return flavorRef from cpu, disk, ram values
752
function identify_flavor(cpu, disk, ram){
753
    for (i=0;i<flavors.length;i++){
754
        if (flavors[i]['cpu'] == cpu && flavors[i]['disk']==disk && flavors[i]['ram']==ram) {
755
            return flavors[i]['id']
756
        }
757
    }
758
    return 0;
759
}
760

    
761
// return image entry from imageRef
762
function get_image(imageRef) {
763
    for (i=0;i<images.length;i++){
764
        if (images[i]['id'] == imageRef) {
765
            return images[i];
766
        }
767
    }
768
    return 0;
769
}
770

    
771
// return machine entry from serverID
772
function get_machine(serverID) {
773
    for (i=0;i<servers.length;i++){
774
        if (servers[i]['id'] == serverID) {
775
            return servers[i];
776
        }
777
    }
778
    return 0;
779
}
780

    
781
// update the actions in icon view, per server
782
function update_iconview_actions(serverID, server_status) {
783
    if ($.cookie("view")=='2') {
784
        // remove .disable from all actions to begin with
785
        $('#machinesview-single #' + serverID + ' div.single-action').show();
786
        // decide which actions should be disabled
787
        for (current_action in actions) {
788
            if (actions[current_action].indexOf(server_status) == -1 ) {
789
                $('#machinesview-single #' + serverID + ' div.action-' + current_action).hide();
790
            }
791
        }
792
    } else {
793
        // remove .disable from all actions to begin with
794
        $('#machinesview-icon.standard #' + serverID + ' div.actions').find('a').removeClass('disabled');
795
        // decide which actions should be disabled
796
        for (current_action in actions) {
797
            if (actions[current_action].indexOf(server_status) == -1 ) {
798
                $('#machinesview-icon.standard #' + serverID + ' a.action-' + current_action).addClass('disabled');
799
            }
800
        }
801
    }
802
}
803

    
804
// update the actions in list view
805
function update_listview_actions() {
806
    var states = [];
807
    var on = [];
808
    var checked = $("table.list-machines tbody input[type='checkbox']:checked");
809
    // disable all actions to begin with
810
    $('#machinesview .list div.actions').children().removeClass('enabled');
811

    
812
    // are there multiple machines selected?
813
    if (checked.length>1)
814
        states[0] = 'multiple';
815

    
816
    // check the states of selected machines
817
    checked.each(function(i,checkbox) {
818
        states[states.length] = checkbox.className;
819
        var ip = $("#" + checkbox.id.replace('input-','') + ".ip span.public").text();
820
        if (ip.replace('undefined','').length)
821
            states[states.length] = 'network';
822
    });
823

    
824
    // decide which actions should be enabled
825
    for (a in actions) {
826
        var enabled = false;
827
        for (var s =0; s<states.length; s++) {
828
            if (actions[a].indexOf(states[s]) != -1 ) {
829
                enabled = true;
830
            } else {
831
                enabled = false;
832
                break;
833
            }
834
        }
835
        if (enabled)
836
            on[on.length]=a;
837
    }
838
    // enable those actions
839
    for (action in on) {
840
        $("#action-" + on[action]).addClass('enabled');
841
    }
842
}
843

    
844
//create server action
845
function create_vm(machineName, imageRef, flavorRef){
846
    var image_logo = os_icon(get_image(imageRef).metadata);
847
    var uri = API_URL + '/servers';
848
    var payload = {
849
        "server": {
850
            "name": machineName,
851
            "imageRef": imageRef,
852
            "flavorRef" : flavorRef,
853
            "metadata" : {
854
                "OS" : image_logo
855
            }
856
        }
857
    };
858

    
859
    $.ajax({
860
    url: uri,
861
    type: "POST",
862
    contentType: "application/json",
863
    dataType: "json",
864
    data: JSON.stringify(payload),
865
    timeout: TIMEOUT,
866
    error: function(jqXHR, textStatus, errorThrown) {
867
                // close wizard and show error box
868
                $('#machines-pane a#create').data('overlay').close();
869
                    try {
870
                        ajax_error(jqXHR.status, undefined, 'Create VM', jqXHR.responseText);
871
                    } catch(err) {
872
                        ajax_error(0, undefined, 'Create VM', jqXHR.responseText);
873
                    }
874
           },
875
    success: function(data, textStatus, jqXHR) {
876
                if ( jqXHR.status == '202') {
877
                    ajax_success("CREATE_VM_SUCCESS", data.server.adminPass);
878
                } else {
879
                    // close wizard and show error box
880
                    $('#machines-pane a#create').data('overlay').close();
881
                    ajax_error(jqXHR.status, undefined, 'Create VM', jqXHR.responseText);
882
                }
883
            }
884
    });
885
}
886

    
887
// reboot action
888
function reboot(serverIDs){
889
    if (!serverIDs.length){
890
        //ajax_success('DEFAULT');
891
        return false;
892
    }
893
    // ajax post reboot call
894
    var payload = {
895
        "reboot": {"type" : "HARD"}
896
    };
897

    
898
    var serverID = serverIDs.pop();
899

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

    
949
// shutdown action
950
function shutdown(serverIDs) {
951
    if (!serverIDs.length){
952
        //ajax_success('DEFAULT');
953
        return false;
954
    }
955
    // ajax post shutdown call
956
    var payload = {
957
        "shutdown": {}
958
    };
959

    
960
    var serverID = serverIDs.pop();
961

    
962
    $.ajax({
963
        url: API_URL + '/servers/' + serverID + '/action',
964
        type: "POST",
965
        contentType: "application/json",
966
        dataType: "json",
967
        data: JSON.stringify(payload),
968
        timeout: TIMEOUT,
969
        error: function(jqXHR, textStatus, errorThrown) {
970
                    try {
971
                        display_failure(jqXHR.status, serverID, 'Shutdown', jqXHR.responseText);
972
                    } catch(err) {
973
                        display_failure(0, serverID, 'Shutdown', jqXHR.responseText);
974
                    }
975
                },
976
        success: function(data, textStatus, jqXHR) {
977
                    if ( jqXHR.status == '202') {
978
                        try {
979
                            console.info('suspended ' + serverID);
980
                        } catch(err) {}
981
                        // indicate that the action succeeded
982
                        display_success(serverID);
983
                        // continue with the rest of the servers
984
                        shutdown(serverIDs);
985
                    } else {
986
                        ajax_error(jqXHR.status, serverID, 'Shutdown', jqXHR.responseText);
987
                    }
988
                }
989
    });
990
    return false;
991
}
992

    
993
// destroy action
994
function destroy(serverIDs) {
995
    if (!serverIDs.length){
996
        //ajax_success('DEFAULT');
997
        return false;
998
    }
999
    // ajax post destroy call can have an empty request body
1000
    var payload = {};
1001

    
1002
    var serverID = serverIDs.pop();
1003

    
1004
    $.ajax({
1005
        url: API_URL + '/servers/' + serverID,
1006
        type: "DELETE",
1007
        contentType: "application/json",
1008
        dataType: "json",
1009
        data: JSON.stringify(payload),
1010
        timeout: TIMEOUT,
1011
        error: function(jqXHR, textStatus, errorThrown) {
1012
                    try {
1013
                        display_failure(jqXHR.status, serverID, 'Destroy', jqXHR.responseText);
1014
                    } catch(err) {
1015
                        display_failure(0, serverID, 'Destroy', jqXHR.responseText);
1016
                    }
1017
                },
1018
        success: function(data, textStatus, jqXHR) {
1019
                    if ( jqXHR.status == '204') {
1020
                        try {
1021
                            console.info('destroyed ' + serverID);
1022
                        } catch (err) {}
1023
                        // indicate that the action succeeded
1024
                        display_success(serverID);
1025
                        // continue with the rest of the servers
1026
                        destroy(serverIDs);
1027
                    } else {
1028
                        ajax_error(jqXHR.status, serverID, 'Destroy', jqXHR.responseText);
1029
                    }
1030
                }
1031
    });
1032
    return false;
1033
}
1034

    
1035
// start action
1036
function start(serverIDs){
1037
    if (!serverIDs.length){
1038
        //ajax_success('DEFAULT');
1039
        return false;
1040
    }
1041
    // ajax post start call
1042
    var payload = {
1043
        "start": {}
1044
    };
1045

    
1046
    var serverID = serverIDs.pop();
1047

    
1048
    $.ajax({
1049
        url: API_URL + '/servers/' + serverID + '/action',
1050
        type: "POST",
1051
        contentType: "application/json",
1052
        dataType: "json",
1053
        data: JSON.stringify(payload),
1054
        timeout: TIMEOUT,
1055
        error: function(jqXHR, textStatus, errorThrown) {
1056
                    try {
1057
                        display_failure(jqXHR.status, serverID, 'Start', jqXHR.responseText);
1058
                    } catch(err) {
1059
                        display_failure(0, serverID, 'Start', jqXHR.responseText);
1060
                    }
1061
                },
1062
        success: function(data, textStatus, jqXHR) {
1063
                    if ( jqXHR.status == '202') {
1064
                        try {
1065
                            console.info('started ' + serverID);
1066
                        } catch(err) {}
1067
                        // indicate that the action succeeded
1068
                        display_success(serverID);
1069
                        // continue with the rest of the servers
1070
                        start(serverIDs);
1071
                    } else {
1072
                        ajax_error(jqXHR.status, serverID, 'Start', jqXHR.responseText);
1073
                    }
1074
                }
1075
    });
1076
    return false;
1077
}
1078

    
1079
// Show VNC console
1080
function vnc_attachment(host, port, password) {
1081
    // FIXME: Must be made into parameters, in settings.py
1082
    //vnc = open("", "displayWindow",
1083
    //    "status=yes,toolbar=yes,menubar=yes");
1084
    vd = document.open("application/x-vnc");
1085

    
1086
    vd.writeln("[connection]");
1087
    vd.writeln("host=" + host);
1088
    vd.writeln("port=" + port);
1089
    vd.writeln("password=" + password);
1090

    
1091
    vd.close();
1092
}
1093

    
1094
// Show VNC console
1095
function show_vnc_console(serverID, serverName, serverIP, host, port, password) {
1096
    var params_url = '?machine=' + serverName + '&host_ip=' + serverIP + '&host=' + host + '&port=' + port + '&password=' + password;
1097
    var params_window = 'scrollbars=no,' +
1098
                        'menubar=no,' +
1099
                        'toolbar=no,' +
1100
                        'status=no,' +
1101
                        'top=0,' +
1102
                        'left=0,' +
1103
                        'height=' + screen.height + ',' +
1104
                        'width=' + screen.width + ',' +
1105
                        'fullscreen=yes';
1106

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

    
1109
    // Restore os icon in list view
1110
    osIcon = $('#'+serverID).parent().parent().find('.list-logo');
1111
    osIcon.attr('src',osIcon.attr('os'));
1112
    return false;
1113
}
1114

    
1115
// console action
1116
function open_console(serverIDs){
1117
    if (!serverIDs.length){
1118
        //ajax_success('DEFAULT');
1119
        return false;
1120
    }
1121
    // ajax post start call
1122
    var payload = {
1123
        "console": {"type": "vnc"}
1124
    };
1125

    
1126
    var serverID = serverIDs.pop();
1127

    
1128
    var machine = get_machine(serverID);
1129
    var serverName = machine.name;
1130
    try {
1131
        var serverIP = machine.addresses.values[0].values[0].addr;
1132
    } catch(err) { var serverIP = 'undefined'; }
1133

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

    
1171
function vm_has_address(vmId) {
1172
    var vm = get_machine(vmId);
1173

    
1174
    if (!vm) return false;
1175

    
1176
    try {
1177
        var ip = vm.addresses.values[0].values[0].addr;
1178
    } catch (err) {
1179
        console.log(err);
1180
        return false;
1181
    }
1182
    return ip;
1183
}
1184

    
1185
// connect to machine action
1186
function machine_connect(serverIDs){
1187
    if (!serverIDs.length){
1188
        //ajax_success('DEFAULT');
1189
        return false;
1190
    }
1191
    var serverID = serverIDs.pop();
1192
    
1193
    var machine = get_machine(serverID);
1194
    var serverName = machine.name;
1195
    try {
1196
        var serverIP = machine.addresses.values[0].values[0].addr;
1197
    } catch(err) { var serverIP = 'undefined'; }
1198

    
1199
    try {
1200
        var os = machine.metadata.values.OS;
1201
    } catch(err) { var os = 'undefined'; }
1202

    
1203
    var params_url = '?ip_address=' + serverIP + '&os=' + os;
1204

    
1205
    //console.log(serverIP);
1206
    //console.log(machine.addresses);
1207
    //console.log(machine.addresses.values[0].values[0].addr);
1208
    
1209
    //show_connect_dialog(machine, ip);
1210
    try {
1211
        msg_box({title:'Connect to ' + serverName,content:'loading...',extra:'',
1212
        'ajax':'machines/connect' + params_url,
1213
        parse_data:function(data){
1214
            data.title = false;
1215
            data.content = data.info;
1216
            data.extra = "<a href='"+data.link.url+"'>"+data.link.title+"</a>";
1217
            return data;
1218
        }
1219
        });
1220
    } catch (error) {
1221
        console.log(error);
1222
    window.open('machines/connect' + params_url);
1223
    }
1224

    
1225

    
1226
    // Restore os icon in list view
1227
    osIcon = $('#'+serverID).parent().parent().find('.list-logo');
1228
    osIcon.attr('src',osIcon.attr('os'));
1229

    
1230
    return false;
1231
}
1232

    
1233

    
1234
// rename server
1235
function rename(serverID, serverName){
1236
    if (!serverID.length){
1237
        //ajax_success('DEFAULT');
1238
        return false;
1239
    }
1240
    // ajax post rename call
1241
    var payload = {
1242
        "server": {"name": serverName}
1243
    };
1244

    
1245
    $.ajax({
1246
        url: API_URL + '/servers/' + serverID,
1247
        type: "PUT",
1248
        contentType: "application/json",
1249
        dataType: "json",
1250
        data: JSON.stringify(payload),
1251
        timeout: TIMEOUT,
1252
        error: function(jqXHR, textStatus, errorThrown) {
1253
                    try {
1254
                        display_failure(jqXHR.status, serverID, 'Rename', jqXHR.responseText);
1255
                    } catch(err) {
1256
                        display_failure(0, serverID, 'Rename', jqXHR.responseText);
1257
                    }
1258
                },
1259
        success: function(data, textStatus, jqXHR) {
1260
                    if ( jqXHR.status == '204' || jqXHR.status == '1223') {
1261
                        try {
1262
                            console.info('renamed ' + serverID);
1263
                        } catch(err) {}
1264
                        // indicate that the action succeeded
1265
                        display_success(serverID);
1266
                    } else {
1267
                        ajax_error(jqXHR.status, serverID, 'Rename', jqXHR.responseText);
1268
                    }
1269
                }
1270
    });
1271
    return false;
1272
}
1273

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

    
1307
// delete metadata key-value pair
1308
function delete_metadata(serverID, meta_key) {
1309
    $.ajax({
1310
        url: API_URL + '/servers/' + serverID + '/meta/' + meta_key,
1311
        type: "DELETE",
1312
        //async: false,
1313
        dataType: "json",
1314
        timeout: TIMEOUT,
1315
        error: function(jqXHR, textStatus, errorThrown) {
1316
            try {
1317
                // close wizard and show error box
1318
                $("a#metadata-scrollable").data('overlay').close();
1319
                ajax_error(jqXHR.status, undefined, 'Delete metadata', jqXHR.responseText);
1320
            } catch (err) {
1321
                ajax_error(err);
1322
            }
1323
        },
1324
        success: function(data, textStatus, jqXHR) {
1325
                    // success: Do nothing, the UI is already updated
1326
        }
1327
    });
1328
    return false;
1329
}
1330

    
1331
// add metadata key-value pair
1332
function update_metadata(serverID, meta_key, meta_value) {
1333
    var payload = {
1334
        "meta": {
1335
        }
1336
    };
1337
    payload["meta"][meta_key] = meta_value;
1338

    
1339
    $.ajax({
1340
        url: API_URL + '/servers/' + serverID + '/meta/' + meta_key,
1341
        type: "PUT",
1342
        contentType: "application/json",
1343
        dataType: "json",
1344
        data: JSON.stringify(payload),
1345
        timeout: TIMEOUT,
1346
        error: function(jqXHR, textStatus, errorThrown) {
1347
            try {
1348
                // close wizard and show error box
1349
                $("a#metadata-scrollable").data('overlay').close();
1350
                ajax_error(jqXHR.status, undefined, 'add metadata', jqXHR.responseText);
1351
            } catch (err) {
1352
                ajax_error(err);
1353
            }
1354
        },
1355
        success: function(data, textStatus, jqXHR) {
1356
            // success: Update icons if meta key is OS
1357
            if (meta_key == "OS") {
1358
                $("#metadata-wizard .machine-icon").attr("src","static/icons/machines/small/" + os_icon_from_value(meta_value) + '-' + $("#metadata-wizard div#on-off").text() + '.png');
1359
                var machine_icon = $("#machinesview-icon").find("div#" + serverID);
1360
                var machine_single = $("#machinesview-single").find("div#" + serverID);
1361

    
1362
                var os = os_icon_from_value(meta_value);
1363
                var state = $("#metadata-wizard div#on-off").text()
1364
                var state_single = $(".state", machine_single).hasClass("terminated-state") ? "off" : "on";
1365
                set_machine_os_image(machine_icon, "icon", state, os);
1366
                set_machine_os_image(machine_single, "single", state_single, os);
1367
            }
1368
        }
1369
    });
1370
    return false;
1371
}
1372

    
1373
// get stats
1374
function get_server_stats(serverID) {
1375
    $.ajax({
1376
        url: API_URL + '/servers/' + serverID + '/stats',
1377
        cache: false,
1378
        type: "GET",
1379
        //async: false,
1380
        dataType: "json",
1381
        timeout: TIMEOUT,
1382
        error: function(jqXHR, textStatus, errorThrown) {
1383
                // report error as text inline
1384
                $('#' + serverID + ' img.busy').hide();
1385
                $('#' + serverID + ' div.stat-error').show();
1386
        },
1387
        success: function(data, textStatus, jqXHR) {
1388
            // in icon view
1389
            if ( $.cookie('view') == 0 ) {
1390
                $('#' + serverID + ' img.busy').removeClass('busy');
1391
                $('#' + serverID + ' img.cpu').attr("src", data.stats.cpuBar);
1392
                $('#' + serverID + ' img.net').attr("src", data.stats.netBar);
1393
            }
1394
            // in single view
1395
            else if ( $.cookie('view') == 2 ) {
1396
                $('#' + serverID + ' div.cpu-graph img.stats').attr("src", data.stats.cpuTimeSeries);
1397
                $('#' + serverID + ' div.network-graph img.stats').attr("src", data.stats.netTimeSeries);
1398
            }
1399
        }
1400
    });
1401
    return false;
1402
}
1403

    
1404
// create network
1405
function create_network(networkName){
1406
    // ajax post start call
1407
    var payload = {
1408
        "network": { "name": networkName }
1409
    };
1410

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

    
1448
// rename network
1449
function rename_network(networkID, networkName){
1450
    if (!networkID.length){
1451
        //ajax_success('DEFAULT');
1452
        return false;
1453
    }
1454
    // prepare payload
1455
    var payload = {
1456
        "network": {"name": networkName}
1457
    };
1458
    // ajax call
1459
    $.ajax({
1460
        url: API_URL + '/networks/' + networkID,
1461
        type: "PUT",
1462
        contentType: "application/json",
1463
        dataType: "json",
1464
        data: JSON.stringify(payload),
1465
        timeout: TIMEOUT,
1466
        error: function(jqXHR, textStatus, errorThrown) {
1467
            try {
1468
                ajax_error(jqXHR.status, undefined, 'Rename network', jqXHR.responseText);
1469
            } catch (err) {
1470
                ajax_error(0, undefined, 'Rename network', jqXHR.responseText);
1471
            }
1472
        },
1473
        success: function(data, textStatus, jqXHR) {
1474
            if ( jqXHR.status == '204') {
1475
                try {
1476
                    console.info('renamed network' + networkID);
1477
                } catch(err) {}
1478
            } else {
1479
                ajax_error(jqXHR.status, undefined, 'Rename network', jqXHR.responseText);
1480
            }
1481
        }
1482
    });
1483
    return false;
1484
}
1485

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

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

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

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

    
1670
// show the welcome screen
1671
function showWelcome() {
1672
    $("#view-select").fadeOut("fast");
1673
    $("#emptymachineslist").fadeIn("fast");
1674
    $("#machinesview").hide();
1675
}
1676

    
1677
// hide the welcome screen
1678
function hideWelcome() {
1679
    $("#emptymachineslist").fadeOut("fast");
1680
    $("#view-select").fadeIn("fast");
1681
    $("div#view-select").show();
1682
    $("#machinesview").show();
1683
}
1684

    
1685
function log_server_status_change(server_entry, new_status) {
1686
    // firebug console logging
1687
    try {
1688
        if ($("#machinesview-single").length > 0) {
1689
            console.info(server_entry.find("div.machine-details div.name").text() +
1690
                        ' from ' + server_entry.find(".state-label").text() +
1691
                        ' to ' + STATUSES[new_status]);
1692
        } else {
1693
            console.info(server_entry.find("div.name span.name").text() +
1694
                        ' from ' + server_entry.find(".status").text() +
1695
                        ' to ' + STATUSES[new_status]);
1696
        }
1697
    } catch(err) {}
1698
}
1699

    
1700
function get_flavor_params(flavorRef) {
1701
    var cpus, ram, disk;
1702
    if ( flavors.length > 0 ) {
1703
        var current_flavor = '';
1704
        for (i=0; i<flavors.length; i++) {
1705
            if (flavors[i]['id'] == flavorRef) {
1706
                current_flavor = flavors[i];
1707
            }
1708
        }
1709
        cpus = current_flavor['cpu'];
1710
        ram = current_flavor['ram'];
1711
        disk = current_flavor['disk'];
1712
    } else {
1713
        cpus = 'undefined';
1714
        ram = 'undefined';
1715
        disk = 'undefined';
1716
    }
1717
    return {'cpus': cpus, 'ram': ram, 'disk': disk};
1718
}
1719

    
1720
function get_image_params(imageRef) {
1721
    var image_name, image_size;
1722
    if ( images.length > 0 ) {
1723
        var current_image = '';
1724
        for (i=0; i<images.length; i++) {
1725
            if (images[i]['id'] == imageRef) {
1726
                current_image = images[i];
1727
            }
1728
        }
1729
        try {
1730
            image_name = current_image['name'];
1731
        } catch(err) { image_name = 'undefined'; }
1732
        try{
1733
            image_size = current_image['metadata']['values']['size'];
1734
        } catch(err) { image_size = 'undefined'; }
1735
    } else {
1736
        image_name = 'undefined';
1737
        image_size = 'undefined';
1738
    }
1739
    return {'name': image_name,'size': image_size};
1740
}
1741

    
1742
function get_public_ips(server) {
1743
    var ip4, ip6;
1744
    try {
1745
        if (server.addresses.values) {
1746
            $.each (server.addresses.values, function(i, value) {
1747
                if (value.id == 'public') {
1748
                    try {
1749
                        $.each (value.values, function(i, ip) {
1750
                            if (ip.version == '4') {
1751
                                ip4 = ip.addr;
1752
                            } else if (ip.version == '6') {
1753
                                ip6 = ip.addr;
1754
                            } else {
1755
                                ip4 = 'pending';
1756
                                ip6 = 'pending';
1757
                            }
1758
                        });
1759
                    } catch (err){
1760
                        try{console.info('Server ' + server.id + ' has invalid ips')}catch(err){};
1761
                        ip4 = 'pending';
1762
                        ip6 = 'pending';
1763
                    }
1764
                }
1765
            });
1766
        }
1767
    } catch (err) {
1768
        try{console.info('Server ' + server.id + ' has no network addresses')}catch(err){};
1769
        ip4 = 'pending';
1770
        ip6 = 'pending';
1771
    }
1772
    return {'ip4': ip4, 'ip6': ip6};
1773
}
1774

    
1775
function get_private_ips(server) {
1776

    
1777
}
1778

    
1779
function close_all_overlays() {
1780
        try {
1781
                $("a#networkscreate").overlay().close();
1782
        } catch(err) {}
1783
        try {
1784
                $('a#create').overlay().close();
1785
        } catch(err) {}
1786
        try {
1787
                $("a#add-machines-overlay").overlay().close();
1788
        } catch(err) {}
1789
        try {
1790
                $("a#metadata-scrollable").overlay().close();
1791
        } catch(err) {}
1792
}
1793

    
1794
// logout
1795
function user_session_logout() {
1796
    $.cookie("X-Auth-Token", null);
1797
    if (window.LOGOUT_REDIRECT !== undefined)
1798
    {
1799
        window.location = window.LOGOUT_REDIRECT;
1800
    } else {
1801
        window.location.reload();
1802
    }
1803
}
1804

    
1805
// action indicators
1806
function init_action_indicator_handlers(machines_view)
1807
{
1808
    // init once for each view
1809
    if (window.ACTION_ICON_HANDLERS == undefined)
1810
    {
1811
        window.ACTION_ICON_HANDLERS = {};
1812
    }
1813

    
1814
    if (machines_view in window.ACTION_ICON_HANDLERS)
1815
    {
1816
        return;
1817
    }
1818
    window.ACTION_ICON_HANDLERS[machines_view] = 1;
1819

    
1820
    if (machines_view == "list")
1821
    {
1822
        // totally different logic for list view
1823
        init_action_indicator_list_handlers();
1824
        return;
1825
    }
1826

    
1827
    function update_action_icon_indicators(force)
1828
    {
1829
        function show(el, action) {
1830
            $(".action-indicator", $(el)).attr("class", "action-indicator " + action);
1831
            $(".action-indicator", $(el)).show();
1832
        }
1833

    
1834
        function hide(el) {
1835
            $(".action-indicator", $(el)).hide();
1836
        }
1837

    
1838
        function get_pending_actions(el) {
1839
            return $(".confirm_single:visible", $(el));
1840
        }
1841

    
1842
        function other_indicators(el) {
1843
           return $("img.wave:visible, img.spinner:visible", $(el))
1844
        }
1845

    
1846
        $("div.machine:visible, div.single-container").each(function(index, el){
1847
            var el = $(el);
1848
            var pending = get_pending_actions(el);
1849
            var other = other_indicators(el);
1850
            var action = undefined;
1851
            var force_action = force;
1852
            var visible = $(el).css("display") == "block";
1853

    
1854
            if (force_action !==undefined && force_action.el !== el[0]) {
1855
                // force action for other vm
1856
                // skipping force action
1857
                force_action = undefined;
1858
            }
1859

    
1860
            if (force_action !==undefined && force_action.el === el[0]) {
1861
                action = force_action.action;
1862
            }
1863

    
1864
            if (other.length >= 1) {
1865
                return;
1866
            }
1867

    
1868
            if (pending.length >= 1 && force_action === undefined) {
1869
                action = $(pending.parent()).attr("class").replace("action-container","");
1870
            }
1871

    
1872
            if (action in {'console':''}) {
1873
                return;
1874
            }
1875

    
1876
            if (action !== undefined) {
1877
                show(el, action);
1878
            } else {
1879
                try {
1880
                    if (el.attr('id') == pending_actions[0][1])
1881
                    {
1882
                        return;
1883
                    }
1884
                } catch (err) {
1885
                }
1886
                hide(el);
1887
            }
1888

    
1889
        });
1890
    }
1891

    
1892
    // action indicators
1893
    $(".action-container").live('mouseover', function(evn) {
1894
        force_action = {'el': $(evn.currentTarget).parent().parent()[0], 'action':$(evn.currentTarget).attr("class").replace("action-container","")};
1895
        // single view case
1896
        if ($(force_action.el).attr("class") == "upper")
1897
        {
1898
            force_action.el = $(evn.currentTarget).parent().parent().parent()[0]
1899
        };
1900
        update_action_icon_indicators(force_action);
1901
    });
1902

    
1903
    $("img.spinner, img.wave").live('hide', function(){
1904
        update_action_icon_indicators();
1905
    });
1906
    // register events where icons should get updated
1907

    
1908
    // hide action indicator image on mouse out, spinner appear, wave appear
1909
    $(".action-container").live("mouseout", function(evn){
1910
        update_action_icon_indicators();
1911
    });
1912

    
1913
    $(".confirm_single").live("click", function(evn){
1914
        update_action_icon_indicators();
1915
    });
1916

    
1917
    $("img.spinner, img.wave").live('show', function(){
1918
        $("div.action-indicator").hide();
1919
    });
1920

    
1921
    $(".confirm_single button.no").live('click', function(evn){
1922
        $("div.action-indicator", $(evn.currentTarget).parent().parent()).hide();
1923
    });
1924

    
1925
    $(".confirm_multiple button.no").click(function(){
1926
        $("div.action-indicator").hide();
1927
    });
1928

    
1929
    $(".confirm_multiple button.yes").click(function(){
1930
        $("div.action-indicator").hide();
1931
    });
1932
}
1933

    
1934
function init_action_indicator_list_handlers()
1935
{
1936
    var skip_actions = { 'console':'','connect':'','details':'' };
1937

    
1938
    var has_pending_confirmation = function()
1939
    {
1940
        return $(".confirm_multiple:visible").length >= 1
1941
    }
1942

    
1943
    function update_action_indicator_icons(force_action, skip_pending)
1944
    {
1945
        // pending action based on the element class
1946
        var pending_action = $(".selected", $(".actions"))[0];
1947
        var selected = get_list_view_selected_machine_rows();
1948

    
1949
        // reset previous state
1950
        list_view_hide_action_indicators();
1951

    
1952
        if (pending_action == undefined && !force_action)
1953
        {
1954
            // no action selected
1955
            return;
1956
        }
1957

    
1958
        if (force_action != undefined)
1959
        {
1960
            // user forced action choice
1961
            var action_class = force_action;
1962
        } else {
1963
            // retrieve action name (reboot, stop, etc..)
1964
            var action_class = $(pending_action).attr("id").replace("action-","");
1965
        }
1966

    
1967
        selected.each(function(index, el) {
1968
            if (has_pending_confirmation() && skip_pending)
1969
            {
1970
                return;
1971
            }
1972
            var el = $(el);
1973
            var logo = $("img.list-logo", el);
1974
            $(".action-indicator", el).remove();
1975
            var cls = "action-indicator " + action_class;
1976
            // add icon div
1977
            logo.after('<div class="' + cls + '"></div>');
1978
            // hide os logo
1979
            $("img.list-logo", el).hide();
1980
        });
1981
    }
1982

    
1983
    // on mouseover we force the images to the hovered action
1984
    $(".actions a").live("mouseover", function(evn) {
1985
        var el = $(evn.currentTarget);
1986
        if (!el.hasClass("enabled"))
1987
        {
1988
            return;
1989
        }
1990
        var action_class = el.attr("id").replace("action-","");
1991
        if (action_class in skip_actions)
1992
        {
1993
            return;
1994
        }
1995
        update_action_indicator_icons(action_class, false);
1996
    });
1997

    
1998

    
1999
    // register events where icons should get updated
2000
    $(".actions a.enabled").live("click", function(evn) {
2001
        // clear previous selections
2002
        $("a.selected").removeClass("selected");
2003

    
2004
        var el = $(evn.currentTarget);
2005
        el.addClass("selected");
2006
        update_action_indicator_icons(undefined, false);
2007
    });
2008

    
2009
    $(".actions a").live("mouseout", function(evn) {
2010
        update_action_indicator_icons(undefined, false);
2011
    });
2012

    
2013
    $(".confirm_multiple button.no").click(function(){
2014
        list_view_hide_action_indicators();
2015
    });
2016

    
2017
    $(".confirm_multiple button.yes").click(function(){
2018
        list_view_hide_action_indicators();
2019
    });
2020

    
2021
    $("input[type=checkbox]").live('change', function(){
2022
        // pending_actions will become empty on every checkbox click/change
2023
        // line 154 machines_list.html
2024
        pending_actions = [];
2025
        if (pending_actions.length == 0)
2026
        {
2027
            $(".confirm_multiple").hide();
2028
            $("a.selected").each(function(index, el){$(el).removeClass("selected")});
2029
        }
2030
        update_action_indicator_icons(undefined, false);
2031
    });
2032

    
2033
}
2034

    
2035
function list_view_hide_action_indicators()
2036
{
2037
    $("tr td .action-indicator").remove();
2038
    $("tr td img.list-logo").show();
2039
}
2040

    
2041
function get_list_view_selected_machine_rows()
2042
{
2043
    var table = $("table.list-machines");
2044
    var rows = $("tr:has(input[type=checkbox]:checked)",table);
2045
    return rows;
2046
}
2047

    
2048
// machines images utils
2049
function set_machine_os_image(machine, machines_view, state, os, skip_reset_states, remove_state) {
2050
    var views_map = {'single': '.single-image', 'icon': '.logo'};
2051
    var states_map = {'on': 'state1', 'off': 'state3', 'hover': 'state4', 'click': 'state2'}
2052
    var sizes_map = {'single': 'large', 'icon': 'medium'}
2053

    
2054
    var size = sizes_map[machines_view];
2055
    var img_selector = views_map[machines_view];
2056
    var cls = states_map[state];
2057

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

    
2061
    var el = $(img_selector, machine);
2062
    var current_img = el.css("backgroundImage");
2063
    if (os == undefined){
2064
        new_img = current_img;
2065
    }
2066

    
2067
    // os changed
2068
    el.css("backgroundImage", new_img);
2069

    
2070
    // reset current state
2071
    if (skip_reset_states === undefined)
2072
    {
2073
        el.removeClass("single-image-state1");
2074
        el.removeClass("single-image-state2");
2075
        el.removeClass("single-image-state3");
2076
        el.removeClass("single-image-state4");
2077
    }
2078

    
2079
    if (remove_state !== undefined)
2080
    {
2081
        remove_state = "single-image-" + states_map[remove_state];
2082
        el.removeClass(remove_state);
2083
        return;
2084
    }
2085
    
2086
    // set proper state
2087
    el.addClass("single-image-" + cls);
2088
}
2089

    
2090

    
2091
// generic info box
2092

    
2093
function msg_box(config) {
2094
    var config = $.extend({'title':'Info message', 'content': 'this is an info message', 'ajax': false, 'extra':false}, config);
2095
    // prepare the error message
2096
    // bring up success notification
2097

    
2098
    var box = $("#notification-box");
2099
    box.addClass('success');
2100
    box.removeClass('error');
2101

    
2102
    var sel = function(s){return $(s, box)};
2103

    
2104
    sel("h3 span.header-box").text(config.title);
2105
    sel("div.machine-now-building").html(config.content);
2106
    sel(".popup-header").removeClass("popup-header-error");
2107
    box.removeClass("popup-border-error");
2108
    sel(".popup-details").removeClass("popup-details-error");
2109
    sel(".popup-separator").removeClass("popup-separator-error");
2110
    
2111
    sel(".password-container").hide();
2112
    if (config.extra) {
2113
        sel(".password-container .password").html(config.extra);
2114
        sel(".password-container").show();
2115
    }
2116

    
2117
    var triggers = $("a#msgbox").overlay({
2118
        // some mask tweaks suitable for modal dialogs
2119
        mask: '#666',
2120
        top: 'center',
2121
        closeOnClick: false,
2122
        oneInstance: false,
2123
        load: false,
2124
        onClose: function () {
2125
            // With partial refresh working properly,
2126
            // it is no longer necessary to refresh the whole page
2127
            // choose_view();
2128
        }
2129
    });
2130
    $("a#msgbox").data('overlay').load();
2131
    
2132
    var parse_data = config.parse_data || false;
2133
    if (config.ajax) {
2134
        $.ajax({ 
2135
            url:config.ajax, 
2136
            success: function(data){
2137
                if (parse_data) {
2138
                    data = parse_data(data);
2139
                }
2140

    
2141
                if (data.title)
2142
                    sel("h3 span.header-box").text(data.title);
2143

    
2144
                if (data.content)
2145
                    sel("div.machine-now-building").html(data.content);
2146

    
2147
                if (data.extra) {
2148
                    sel(".password-container .password").html(data.extra);
2149
                    sel(".password-container").show();
2150
                }
2151
            }
2152
        });
2153
    }
2154
    return false;
2155
}