Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ 315528a2

History | View | Annotate | Download (74.7 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(-5, "UI Error", 'Unknown', err);
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(-5, "UI Error", 'Update VMs', err);
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
                    update_machines_view(data);
359
                } catch(err) { ajax_error(-5, "UI Error", 'Update VMs', err);}
360
            } else if (jqXHR.status != 304){
361
                try { console.info('update_vms callback:' + jqXHR.status ) } catch(err) {}
362
                /*
363
                FIXME:  Here it should return the error, however Opera does not support 304.
364
                        Instead 304 it returns 0. To dealt with this we treat 0 as an
365
                        304, which should be corrected (Bug #317).
366
                */
367
                //ajax_error(jqXHR.status, undefined, 'Update VMs', jqXHR.responseText);
368
            }
369
            return false;
370
        }
371
    });
372
    return false;
373
}
374

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

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

    
395
        return false;
396
    }
397

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

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

    
464
    if (changes_since != 0)
465
        uri+='?changes-since='+changes_since
466

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
900
    var serverID = serverIDs.pop();
901

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

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

    
962
    var serverID = serverIDs.pop();
963

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

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

    
1004
    var serverID = serverIDs.pop();
1005

    
1006
    $.ajax({
1007
        url: API_URL + '/servers/' + serverID,
1008
        type: "DELETE",
1009
        contentType: "application/json",
1010
        dataType: "json",
1011
        data: JSON.stringify(payload),
1012
        timeout: TIMEOUT,
1013
        error: function(jqXHR, textStatus, errorThrown) {
1014
                    try {
1015
                        display_failure(jqXHR.status, serverID, 'Destroy', jqXHR.responseText);
1016
                    } catch(err) {
1017
                        display_failure(0, serverID, 'Destroy', jqXHR.responseText);
1018
                    }
1019
                },
1020
        success: function(data, textStatus, jqXHR) {
1021
                    if ( jqXHR.status == '204') {
1022
                        try {
1023
                            console.info('destroyed ' + serverID);
1024
                        } catch (err) {}
1025

    
1026
                        // update status on local storage object
1027
                        vm = get_machine(serverID);
1028
                        vm.status = "DESTROY";
1029

    
1030
                        // indicate that the action succeeded
1031
                        display_success(serverID);
1032
                        // continue with the rest of the servers
1033
                        destroy(serverIDs);
1034
                    } else {
1035
                        ajax_error(jqXHR.status, serverID, 'Destroy', jqXHR.responseText);
1036
                    }
1037
                }
1038
    });
1039
    return false;
1040
}
1041

    
1042
// start action
1043
function start(serverIDs){
1044
    if (!serverIDs.length){
1045
        //ajax_success('DEFAULT');
1046
        return false;
1047
    }
1048
    // ajax post start call
1049
    var payload = {
1050
        "start": {}
1051
    };
1052

    
1053
    var serverID = serverIDs.pop();
1054

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

    
1086
// Show VNC console
1087
function vnc_attachment(host, port, password) {
1088
    // FIXME: Must be made into parameters, in settings.py
1089
    //vnc = open("", "displayWindow",
1090
    //    "status=yes,toolbar=yes,menubar=yes");
1091
    vd = document.open("application/x-vnc");
1092

    
1093
    vd.writeln("[connection]");
1094
    vd.writeln("host=" + host);
1095
    vd.writeln("port=" + port);
1096
    vd.writeln("password=" + password);
1097

    
1098
    vd.close();
1099
}
1100

    
1101
// Show VNC console
1102
function show_vnc_console(serverID, serverName, serverIP, host, port, password) {
1103
    var params_url = '?machine=' + serverName + '&host_ip=' + serverIP + '&host=' + host + '&port=' + port + '&password=' + password;
1104
    var params_window = 'scrollbars=no,' +
1105
                        'menubar=no,' +
1106
                        'toolbar=no,' +
1107
                        'status=no,' +
1108
                        'top=0,' +
1109
                        'left=0,' +
1110
                        'height=' + screen.height + ',' +
1111
                        'width=' + screen.width + ',' +
1112
                        'fullscreen=yes';
1113

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

    
1116
    // Restore os icon in list view
1117
    osIcon = $('#'+serverID).parent().parent().find('.list-logo');
1118
    osIcon.attr('src',osIcon.attr('os'));
1119
    return false;
1120
}
1121

    
1122
// console action
1123
function open_console(serverIDs){
1124
    if (!serverIDs.length){
1125
        //ajax_success('DEFAULT');
1126
        return false;
1127
    }
1128
    // ajax post start call
1129
    var payload = {
1130
        "console": {"type": "vnc"}
1131
    };
1132

    
1133
    var serverID = serverIDs.pop();
1134

    
1135
    var machine = get_machine(serverID);
1136
    var serverName = machine.name;
1137
    try {
1138
        var serverIP = machine.addresses.values[0].values[0].addr;
1139
    } catch(err) { var serverIP = 'undefined'; }
1140

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

    
1178
function vm_has_address(vmId) {
1179
    var vm = get_machine(vmId);
1180

    
1181
    if (!vm) return false;
1182

    
1183
    try {
1184
        var ip = vm.addresses.values[0].values[0].addr;
1185
    } catch (err) {
1186
        return false;
1187
    }
1188
    return ip;
1189
}
1190

    
1191
// connect to machine action
1192
function machine_connect(serverIDs){
1193
    if (!serverIDs.length){
1194
        //ajax_success('DEFAULT');
1195
        return false;
1196
    }
1197

    
1198
    var serverID = serverIDs.pop();
1199
    var machine = get_machine(serverID);
1200
    var serverName = machine.name;
1201
    
1202
    try {
1203
        var serverIP = machine.addresses.values[0].values[0].addr;
1204
    } catch(err) { var serverIP = 'undefined'; }
1205

    
1206
    try {
1207
        var os = machine.metadata.values.OS;
1208
    } catch(err) { var os = 'undefined'; }
1209

    
1210
    var params_url = '?ip_address=' + serverIP + '&os=' + os + "&host_os=" + $.client.os + "&srv=" + serverID;
1211
    
1212
    if ($.client.os == "Windows" && os == "windows") {
1213
        window.open('machines/connect' + params_url + "&rdp=1");
1214
        return;
1215
    }
1216
    
1217
    var title = 'Connect to: ' + '<span class="machine-title"><img src="static/icons/machines/small/'+os+'-on.png" /> '+serverName+'</span>';
1218

    
1219
    try {
1220
        msg_box({title:title, content:'loading...',extra:'',
1221
        'ajax':'machines/connect' + params_url,
1222
        parse_data:function(data){
1223
            var box_content = "<a href='"+data.link.url+"'>"+data.link.title+"</a>";
1224
            if (!data.link.url) {
1225
                box_content = "<span class='cmd'>"+data.link.title+"</span>";
1226
            }
1227
            data.title = false;
1228
            data.content = data.info;
1229
            data.extra = box_content;
1230
            return data;
1231
        }
1232
        });
1233
    } catch (error) {
1234
        window.open('machines/connect' + params_url);
1235
    }
1236

    
1237

    
1238
    // Restore os icon in list view
1239
    osIcon = $('#'+serverID).parent().parent().find('.list-logo');
1240
    osIcon.attr('src',osIcon.attr('os'));
1241

    
1242
    return false;
1243
}
1244

    
1245

    
1246
// rename server
1247
function rename(serverID, serverName){
1248
    if (!serverID.length){
1249
        //ajax_success('DEFAULT');
1250
        return false;
1251
    }
1252
    // ajax post rename call
1253
    var payload = {
1254
        "server": {"name": serverName}
1255
    };
1256

    
1257
    $.ajax({
1258
        url: API_URL + '/servers/' + serverID,
1259
        type: "PUT",
1260
        contentType: "application/json",
1261
        dataType: "json",
1262
        data: JSON.stringify(payload),
1263
        timeout: TIMEOUT,
1264
        error: function(jqXHR, textStatus, errorThrown) {
1265
                    try {
1266
                        display_failure(jqXHR.status, serverID, 'Rename', jqXHR.responseText);
1267
                    } catch(err) {
1268
                        display_failure(0, serverID, 'Rename', jqXHR.responseText);
1269
                    }
1270
                },
1271
        success: function(data, textStatus, jqXHR) {
1272
                    if ( jqXHR.status == '204' || jqXHR.status == '1223') {
1273
                        try {
1274
                            console.info('renamed ' + serverID);
1275
                        } catch(err) {}
1276
                        // indicate that the action succeeded
1277
                        display_success(serverID);
1278
                    } else {
1279
                        ajax_error(jqXHR.status, serverID, 'Rename', jqXHR.responseText);
1280
                    }
1281
                }
1282
    });
1283
    return false;
1284
}
1285

    
1286
// get server metadata
1287
function get_metadata(serverID, keys_only) {
1288
    $.ajax({
1289
        url: API_URL + '/servers/' + serverID + '/meta',
1290
        cache: false,
1291
        type: "GET",
1292
        //async: false,
1293
        dataType: "json",
1294
        timeout: TIMEOUT,
1295
        error: function(jqXHR, textStatus, errorThrown) {
1296
            try {
1297
                // close wizard and show error box
1298
                $("a#metadata-scrollable").data('overlay').close();
1299
                ajax_error(jqXHR.status, undefined, 'Get metadata', jqXHR.responseText);
1300
            } catch (err) {
1301
                ajax_error(-5, "UI Error", "Get metadata", err);
1302
            }
1303
        },
1304
        success: function(data, textStatus, jqXHR) {
1305
            // to list the new results in the edit dialog
1306
            if (keys_only) {
1307
                list_metadata_keys(serverID, data.metadata.values);
1308
            } else {
1309
                list_metadata(data);
1310
                list_metadata_keys(serverID, data.metadata.values);
1311
            }
1312
            //hide spinner
1313
            $('#metadata-wizard .large-spinner').hide();
1314
        }
1315
    });
1316
    return false;
1317
}
1318

    
1319
// delete metadata key-value pair
1320
function delete_metadata(serverID, meta_key) {
1321
    $.ajax({
1322
        url: API_URL + '/servers/' + serverID + '/meta/' + meta_key,
1323
        type: "DELETE",
1324
        //async: false,
1325
        dataType: "json",
1326
        timeout: TIMEOUT,
1327
        error: function(jqXHR, textStatus, errorThrown) {
1328
            try {
1329
                // close wizard and show error box
1330
                $("a#metadata-scrollable").data('overlay').close();
1331
                ajax_error(jqXHR.status, undefined, 'Delete metadata', jqXHR.responseText);
1332
            } catch (err) {
1333
                ajax_error(-5, "UI Error", "Delete metadata", err);
1334
            }
1335
        },
1336
        success: function(data, textStatus, jqXHR) {
1337
                    // success: Do nothing, the UI is already updated
1338
        }
1339
    });
1340
    return false;
1341
}
1342

    
1343
// add metadata key-value pair
1344
function update_metadata(serverID, meta_key, meta_value) {
1345
    var payload = {
1346
        "meta": {
1347
        }
1348
    };
1349
    payload["meta"][meta_key] = meta_value;
1350

    
1351
    $.ajax({
1352
        url: API_URL + '/servers/' + serverID + '/meta/' + meta_key,
1353
        type: "PUT",
1354
        contentType: "application/json",
1355
        dataType: "json",
1356
        data: JSON.stringify(payload),
1357
        timeout: TIMEOUT,
1358
        error: function(jqXHR, textStatus, errorThrown) {
1359
            try {
1360
                // close wizard and show error box
1361
                $("a#metadata-scrollable").data('overlay').close();
1362
                ajax_error(jqXHR.status, undefined, 'add metadata', jqXHR.responseText);
1363
            } catch (err) {
1364
                ajax_error(-5, "UI Error", "add metadata", err);
1365
            }
1366
        },
1367
        success: function(data, textStatus, jqXHR) {
1368
            // success: Update icons if meta key is OS
1369
            if (meta_key == "OS") {
1370
                $("#metadata-wizard .machine-icon").attr("src","static/icons/machines/small/" + os_icon_from_value(meta_value) + '-' + $("#metadata-wizard div#on-off").text() + '.png');
1371
                var machine_icon = $("#machinesview-icon").find("div#" + serverID);
1372
                var machine_single = $("#machinesview-single").find("div#" + serverID);
1373

    
1374
                var os = os_icon_from_value(meta_value);
1375
                var state = $("#metadata-wizard div#on-off").text()
1376
                var state_single = $(".state", machine_single).hasClass("terminated-state") ? "off" : "on";
1377
                set_machine_os_image(machine_icon, "icon", state, os);
1378
                set_machine_os_image(machine_single, "single", state_single, os);
1379
            }
1380
        }
1381
    });
1382
    return false;
1383
}
1384

    
1385
// get stats
1386
function get_server_stats(serverID) {
1387
    $.ajax({
1388
        url: API_URL + '/servers/' + serverID + '/stats',
1389
        cache: false,
1390
        type: "GET",
1391
        //async: false,
1392
        dataType: "json",
1393
        timeout: TIMEOUT,
1394
        error: function(jqXHR, textStatus, errorThrown) {
1395
                // report error as text inline
1396
                $('#' + serverID + ' img.busy').hide();
1397
                $('#' + serverID + ' div.stat-error').show();
1398
        },
1399
        success: function(data, textStatus, jqXHR) {
1400
            // in icon view
1401
            if ( $.cookie('view') == 0 ) {
1402
                $('#' + serverID + ' img.busy').removeClass('busy');
1403
                $('#' + serverID + ' img.cpu').attr("src", data.stats.cpuBar);
1404
                $('#' + serverID + ' img.net').attr("src", data.stats.netBar);
1405
            }
1406
            // in single view
1407
            else if ( $.cookie('view') == 2 ) {
1408
                $('#' + serverID + ' div.cpu-graph img.stats').attr("src", data.stats.cpuTimeSeries);
1409
                $('#' + serverID + ' div.network-graph img.stats').attr("src", data.stats.netTimeSeries);
1410
            }
1411
        }
1412
    });
1413
    return false;
1414
}
1415

    
1416
// create network
1417
function create_network(networkName){
1418
    // ajax post start call
1419
    var payload = {
1420
        "network": { "name": networkName }
1421
    };
1422

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

    
1460
// rename network
1461
function rename_network(networkID, networkName){
1462
    if (!networkID.length){
1463
        //ajax_success('DEFAULT');
1464
        return false;
1465
    }
1466
    // prepare payload
1467
    var payload = {
1468
        "network": {"name": networkName}
1469
    };
1470
    // ajax call
1471
    $.ajax({
1472
        url: API_URL + '/networks/' + networkID,
1473
        type: "PUT",
1474
        contentType: "application/json",
1475
        dataType: "json",
1476
        data: JSON.stringify(payload),
1477
        timeout: TIMEOUT,
1478
        error: function(jqXHR, textStatus, errorThrown) {
1479
            try {
1480
                ajax_error(jqXHR.status, undefined, 'Rename network', jqXHR.responseText);
1481
            } catch (err) {
1482
                ajax_error(-1, "UI Error", 'Rename network', err);
1483
            }
1484
        },
1485
        success: function(data, textStatus, jqXHR) {
1486
            if ( jqXHR.status == '204') {
1487
                try {
1488
                    console.info('renamed network' + networkID);
1489
                } catch(err) {}
1490
            } else {
1491
                ajax_error(jqXHR.status, undefined, 'Rename network', jqXHR.responseText);
1492
            }
1493
        }
1494
    });
1495
    return false;
1496
}
1497

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

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

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

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

    
1682
// show the welcome screen
1683
function showWelcome() {
1684
    $("#view-select").fadeOut("fast");
1685
    $("#emptymachineslist").fadeIn("fast");
1686
    $("#machinesview").hide();
1687
}
1688

    
1689
// hide the welcome screen
1690
function hideWelcome() {
1691
    $("#emptymachineslist").fadeOut("fast");
1692
    $("#view-select").fadeIn("fast");
1693
    $("div#view-select").show();
1694
    $("#machinesview").show();
1695
}
1696

    
1697
function log_server_status_change(server_entry, new_status) {
1698
    // firebug console logging
1699
    try {
1700
        if ($("#machinesview-single").length > 0) {
1701
            console.info(server_entry.find("div.machine-details div.name").text() +
1702
                        ' from ' + server_entry.find(".state-label").text() +
1703
                        ' to ' + STATUSES[new_status]);
1704
        } else {
1705
            console.info(server_entry.find("div.name span.name").text() +
1706
                        ' from ' + server_entry.find(".status").text() +
1707
                        ' to ' + STATUSES[new_status]);
1708
        }
1709
    } catch(err) {}
1710
}
1711

    
1712
function get_flavor_params(flavorRef) {
1713
    var cpus, ram, disk;
1714
    if ( flavors.length > 0 ) {
1715
        var current_flavor = '';
1716
        for (i=0; i<flavors.length; i++) {
1717
            if (flavors[i]['id'] == flavorRef) {
1718
                current_flavor = flavors[i];
1719
            }
1720
        }
1721
        cpus = current_flavor['cpu'];
1722
        ram = current_flavor['ram'];
1723
        disk = current_flavor['disk'];
1724
    } else {
1725
        cpus = 'undefined';
1726
        ram = 'undefined';
1727
        disk = 'undefined';
1728
    }
1729
    return {'cpus': cpus, 'ram': ram, 'disk': disk};
1730
}
1731

    
1732
function get_image_params(imageRef) {
1733
    var image_name, image_size;
1734
    if ( images.length > 0 ) {
1735
        var current_image = '';
1736
        for (i=0; i<images.length; i++) {
1737
            if (images[i]['id'] == imageRef) {
1738
                current_image = images[i];
1739
            }
1740
        }
1741
        try {
1742
            image_name = current_image['name'];
1743
        } catch(err) { image_name = 'undefined'; }
1744
        try{
1745
            image_size = current_image['metadata']['values']['size'];
1746
        } catch(err) { image_size = 'undefined'; }
1747
    } else {
1748
        image_name = 'undefined';
1749
        image_size = 'undefined';
1750
    }
1751
    return {'name': image_name,'size': image_size};
1752
}
1753

    
1754
function get_public_ips(server) {
1755
    var ip4, ip6;
1756
    try {
1757
        if (server.addresses.values) {
1758
            $.each (server.addresses.values, function(i, value) {
1759
                if (value.id == 'public') {
1760
                    try {
1761
                        $.each (value.values, function(i, ip) {
1762
                            if (ip.version == '4') {
1763
                                ip4 = ip.addr;
1764
                            } else if (ip.version == '6') {
1765
                                ip6 = ip.addr;
1766
                            } else {
1767
                                ip4 = 'pending';
1768
                                ip6 = 'pending';
1769
                            }
1770
                        });
1771
                    } catch (err){
1772
                        try{console.info('Server ' + server.id + ' has invalid ips')}catch(err){};
1773
                        ip4 = 'pending';
1774
                        ip6 = 'pending';
1775
                    }
1776
                }
1777
            });
1778
        }
1779
    } catch (err) {
1780
        try{console.info('Server ' + server.id + ' has no network addresses')}catch(err){};
1781
        ip4 = 'pending';
1782
        ip6 = 'pending';
1783
    }
1784
    return {'ip4': ip4, 'ip6': ip6};
1785
}
1786

    
1787
function get_private_ips(server) {
1788

    
1789
}
1790

    
1791
function close_all_overlays() {
1792
        try {
1793
                $("a#networkscreate").overlay().close();
1794
        } catch(err) {}
1795
        try {
1796
                $('a#create').overlay().close();
1797
        } catch(err) {}
1798
        try {
1799
                $("a#add-machines-overlay").overlay().close();
1800
        } catch(err) {}
1801
        try {
1802
                $("a#metadata-scrollable").overlay().close();
1803
        } catch(err) {}
1804
        try {
1805
                $("a#msgbox").overlay().close();
1806
        } catch(err) {}
1807
}
1808

    
1809
// logout
1810
function user_session_logout() {
1811
    $.cookie("X-Auth-Token", null);
1812
    if (window.LOGOUT_REDIRECT !== undefined)
1813
    {
1814
        window.location = window.LOGOUT_REDIRECT;
1815
    } else {
1816
        window.location.reload();
1817
    }
1818
}
1819

    
1820
// action indicators
1821
function init_action_indicator_handlers(machines_view)
1822
{
1823
    // init once for each view
1824
    if (window.ACTION_ICON_HANDLERS == undefined)
1825
    {
1826
        window.ACTION_ICON_HANDLERS = {};
1827
    }
1828

    
1829
    if (machines_view in window.ACTION_ICON_HANDLERS)
1830
    {
1831
        return;
1832
    }
1833
    window.ACTION_ICON_HANDLERS[machines_view] = 1;
1834

    
1835
    if (machines_view == "list")
1836
    {
1837
        // totally different logic for list view
1838
        init_action_indicator_list_handlers();
1839
        return;
1840
    }
1841

    
1842
    function update_action_icon_indicators(force)
1843
    {
1844
        function show(el, action) {
1845
            $(".action-indicator", $(el)).attr("class", "action-indicator " + action);
1846
            $(".action-indicator", $(el)).show();
1847
        }
1848

    
1849
        function hide(el) {
1850
            $(".action-indicator", $(el)).hide();
1851
        }
1852

    
1853
        function get_pending_actions(el) {
1854
            return $(".confirm_single:visible", $(el));
1855
        }
1856

    
1857
        function other_indicators(el) {
1858
           return $("img.wave:visible, img.spinner:visible", $(el))
1859
        }
1860

    
1861
        $("div.machine:visible, div.single-container").each(function(index, el){
1862
            var el = $(el);
1863
            var pending = get_pending_actions(el);
1864
            var other = other_indicators(el);
1865
            var action = undefined;
1866
            var force_action = force;
1867
            var visible = $(el).css("display") == "block";
1868

    
1869
            if (force_action !==undefined && force_action.el !== el[0]) {
1870
                // force action for other vm
1871
                // skipping force action
1872
                force_action = undefined;
1873
            }
1874

    
1875
            if (force_action !==undefined && force_action.el === el[0]) {
1876
                action = force_action.action;
1877
            }
1878

    
1879
            if (other.length >= 1) {
1880
                return;
1881
            }
1882

    
1883
            if (pending.length >= 1 && force_action === undefined) {
1884
                action = $(pending.parent()).attr("class").replace("action-container","");
1885
            }
1886

    
1887
            if (action in {'console':''}) {
1888
                return;
1889
            }
1890

    
1891
            if (action !== undefined) {
1892
                show(el, action);
1893
            } else {
1894
                try {
1895
                    if (el.attr('id') == pending_actions[0][1])
1896
                    {
1897
                        return;
1898
                    }
1899
                } catch (err) {
1900
                }
1901
                hide(el);
1902
            }
1903

    
1904
        });
1905
    }
1906

    
1907
    // action indicators
1908
    $(".action-container").live('mouseover', function(evn) {
1909
        force_action = {'el': $(evn.currentTarget).parent().parent()[0], 'action':$(evn.currentTarget).attr("class").replace("action-container","")};
1910
        // single view case
1911
        if ($(force_action.el).attr("class") == "upper")
1912
        {
1913
            force_action.el = $(evn.currentTarget).parent().parent().parent()[0]
1914
        };
1915
        update_action_icon_indicators(force_action);
1916
    });
1917

    
1918
    $("img.spinner, img.wave").live('hide', function(){
1919
        update_action_icon_indicators();
1920
    });
1921
    // register events where icons should get updated
1922

    
1923
    // hide action indicator image on mouse out, spinner appear, wave appear
1924
    $(".action-container").live("mouseout", function(evn){
1925
        update_action_icon_indicators();
1926
    });
1927

    
1928
    $(".confirm_single").live("click", function(evn){
1929
        update_action_icon_indicators();
1930
    });
1931

    
1932
    $("img.spinner, img.wave").live('show', function(){
1933
        $("div.action-indicator").hide();
1934
    });
1935

    
1936
    $(".confirm_single button.no").live('click', function(evn){
1937
        $("div.action-indicator", $(evn.currentTarget).parent().parent()).hide();
1938
    });
1939

    
1940
    $(".confirm_multiple button.no").click(function(){
1941
        $("div.action-indicator").hide();
1942
    });
1943

    
1944
    $(".confirm_multiple button.yes").click(function(){
1945
        $("div.action-indicator").hide();
1946
    });
1947
}
1948

    
1949
function init_action_indicator_list_handlers()
1950
{
1951
    var skip_actions = { 'console':'','connect':'','details':'' };
1952

    
1953
    var has_pending_confirmation = function()
1954
    {
1955
        return $(".confirm_multiple:visible").length >= 1
1956
    }
1957

    
1958
    function update_action_indicator_icons(force_action, skip_pending)
1959
    {
1960
        // pending action based on the element class
1961
        var pending_action = $(".selected", $(".actions"))[0];
1962
        var selected = get_list_view_selected_machine_rows();
1963

    
1964
        // reset previous state
1965
        list_view_hide_action_indicators();
1966

    
1967
        if (pending_action == undefined && !force_action)
1968
        {
1969
            // no action selected
1970
            return;
1971
        }
1972

    
1973
        if (force_action != undefined)
1974
        {
1975
            // user forced action choice
1976
            var action_class = force_action;
1977
        } else {
1978
            // retrieve action name (reboot, stop, etc..)
1979
            var action_class = $(pending_action).attr("id").replace("action-","");
1980
        }
1981

    
1982
        selected.each(function(index, el) {
1983
            if (has_pending_confirmation() && skip_pending)
1984
            {
1985
                return;
1986
            }
1987
            var el = $(el);
1988
            var logo = $("img.list-logo", el);
1989
            $(".action-indicator", el).remove();
1990
            var cls = "action-indicator " + action_class;
1991
            // add icon div
1992
            logo.after('<div class="' + cls + '"></div>');
1993
            // hide os logo
1994
            $("img.list-logo", el).hide();
1995
        });
1996
    }
1997

    
1998
    // on mouseover we force the images to the hovered action
1999
    $(".actions a").live("mouseover", function(evn) {
2000
        var el = $(evn.currentTarget);
2001
        if (!el.hasClass("enabled"))
2002
        {
2003
            return;
2004
        }
2005
        var action_class = el.attr("id").replace("action-","");
2006
        if (action_class in skip_actions)
2007
        {
2008
            return;
2009
        }
2010
        update_action_indicator_icons(action_class, false);
2011
    });
2012

    
2013

    
2014
    // register events where icons should get updated
2015
    $(".actions a.enabled").live("click", function(evn) {
2016
        // clear previous selections
2017
        $("a.selected").removeClass("selected");
2018

    
2019
        var el = $(evn.currentTarget);
2020
        el.addClass("selected");
2021
        update_action_indicator_icons(undefined, false);
2022
    });
2023

    
2024
    $(".actions a").live("mouseout", function(evn) {
2025
        update_action_indicator_icons(undefined, false);
2026
    });
2027

    
2028
    $(".confirm_multiple button.no").click(function(){
2029
        list_view_hide_action_indicators();
2030
    });
2031

    
2032
    $(".confirm_multiple button.yes").click(function(){
2033
        list_view_hide_action_indicators();
2034
    });
2035

    
2036
    $("input[type=checkbox]").live('change', function(){
2037
        // pending_actions will become empty on every checkbox click/change
2038
        // line 154 machines_list.html
2039
        pending_actions = [];
2040
        if (pending_actions.length == 0)
2041
        {
2042
            $(".confirm_multiple").hide();
2043
            $("a.selected").each(function(index, el){$(el).removeClass("selected")});
2044
        }
2045
        update_action_indicator_icons(undefined, false);
2046
    });
2047

    
2048
}
2049

    
2050
function list_view_hide_action_indicators()
2051
{
2052
    $("tr td .action-indicator").remove();
2053
    $("tr td img.list-logo").show();
2054
}
2055

    
2056
function get_list_view_selected_machine_rows()
2057
{
2058
    var table = $("table.list-machines");
2059
    var rows = $("tr:has(input[type=checkbox]:checked)",table);
2060
    return rows;
2061
}
2062

    
2063
// machines images utils
2064
function set_machine_os_image(machine, machines_view, state, os, skip_reset_states, remove_state) {
2065
    var views_map = {'single': '.single-image', 'icon': '.logo'};
2066
    var states_map = {'on': 'state1', 'off': 'state3', 'hover': 'state4', 'click': 'state2'}
2067
    var sizes_map = {'single': 'large', 'icon': 'medium'}
2068

    
2069
    var size = sizes_map[machines_view];
2070
    var img_selector = views_map[machines_view];
2071
    var cls = states_map[state];
2072

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

    
2076
    var el = $(img_selector, machine);
2077
    var current_img = el.css("backgroundImage");
2078
    if (os == undefined){
2079
        new_img = current_img;
2080
    }
2081

    
2082
    // os changed
2083
    el.css("backgroundImage", new_img);
2084

    
2085
    // reset current state
2086
    if (skip_reset_states === undefined)
2087
    {
2088
        el.removeClass("single-image-state1");
2089
        el.removeClass("single-image-state2");
2090
        el.removeClass("single-image-state3");
2091
        el.removeClass("single-image-state4");
2092
    }
2093

    
2094
    if (remove_state !== undefined)
2095
    {
2096
        remove_state = "single-image-" + states_map[remove_state];
2097
        el.removeClass(remove_state);
2098
        return;
2099
    }
2100
    
2101
    // set proper state
2102
    el.addClass("single-image-" + cls);
2103
}
2104

    
2105

    
2106
// generic info box
2107

    
2108
function msg_box(config) {
2109
    var config = $.extend({'title':'Info message', 'content': 'this is an info message', 'ajax': false, 'extra':false}, config);
2110
    // prepare the error message
2111
    // bring up success notification
2112

    
2113
    var box = $("#notification-box");
2114
    box.addClass('success');
2115
    box.removeClass('error');
2116

    
2117
    var sel = function(s){return $(s, box)};
2118

    
2119
    sel("h3 span.header-box").html(config.title);
2120
    sel("div.machine-now-building").html(config.content);
2121
    sel(".popup-header").removeClass("popup-header-error");
2122
    box.removeClass("popup-border-error");
2123
    sel(".popup-details").removeClass("popup-details-error");
2124
    sel(".popup-separator").removeClass("popup-separator-error");
2125
    
2126
    sel(".password-container").hide();
2127
    if (config.extra) {
2128
        sel(".password-container .password").html(config.extra);
2129
        sel(".password-container").show();
2130
    }
2131

    
2132
    var triggers = $("a#msgbox").overlay({
2133
        // some mask tweaks suitable for modal dialogs
2134
        mask: '#666',
2135
        top: 'center',
2136
        closeOnClick: false,
2137
        oneInstance: false,
2138
        load: false,
2139
        onClose: function () {
2140
            // With partial refresh working properly,
2141
            // it is no longer necessary to refresh the whole page
2142
            // choose_view();
2143
        }
2144
    });
2145
    $("a#msgbox").data('overlay').load();
2146
    
2147
    var parse_data = config.parse_data || false;
2148
    var load_html = config.html || false;
2149
    var user_success = config.success || false;
2150
    config.ajax = config.ajax || {};
2151

    
2152
    // requested to show remote data in msg_box
2153
    if (config.ajax) {
2154
        $.ajax($.extend({ 
2155
            url:config.ajax, 
2156
            success: function(data){
2157
                // we want to get our data parsed before
2158
                // placing them in content
2159
                if (parse_data) {
2160
                    data = parse_data(data);
2161
                }
2162

    
2163
                // no json response
2164
                // load html body
2165
                if (load_html) {
2166
                    sel("div.machine-now-building").html(data);
2167
                    sel("div.machine-now-building").html(data);
2168
                } else {
2169

    
2170
                    if (data.title)
2171
                        sel("h3 span.header-box").text(data.title);
2172

    
2173
                    if (data.content) {
2174
                        sel("div.machine-now-building").html(data.content);
2175
                    }
2176
                    if (data.extra) {
2177
                        sel(".password-container .password").html(data.extra);
2178
                        sel(".password-container").show();
2179
                    }
2180
                    if (data.subinfo) {
2181
                        sel(".sub-text").html(data.subinfo);
2182
                    } else {
2183
                        sel(".sub-text").html("");
2184
                    }
2185
                }
2186

    
2187
                if (user_success) {
2188
                    user_success($("div.machine-now-building"));
2189
                }
2190
            }
2191
        }, config.ajax_config));
2192
    }
2193
    return false;
2194
}
2195

    
2196

    
2197
function show_invitations() {
2198

    
2199
    handle_invitations = function(el) {
2200
        el.addClass("invitations");
2201
        var cont = el;
2202
        var form = $(el).find("form");
2203

    
2204
        // remove garbage rows that stay in DOM between requests
2205
        $(".removable-field-row:hidden").remove();
2206
        $("#invform #removable-name-container-1").dynamicField();
2207
        
2208
        $(".invitations-left").hide();
2209
        $(".header-box").html("");
2210
        $(".header-box").html("Invitations " + $($(".invitations-left")[0]).text());
2211

    
2212
        form.submit(function(evn){
2213
            evn.preventDefault();
2214
            $.post(form.attr("action"), form.serialize(), function(data) {
2215
                $(cont).html(data); 
2216
                handle_invitations(cont);
2217
            });
2218
            return false;
2219
        });
2220
    }
2221
    msg_box({title:window.INVITATIONS_TITLE, content:'', ajax:INVITATIONS_URL, html:true, success: function(el){ 
2222
        handle_invitations(el)}
2223
    });
2224
}
2225