Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ fdde4b4d

History | View | Annotate | Download (73.5 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
            }
444
        } else {
445
            servers.push(server);
446
            $(window).trigger("vm:add", server);
447
        }
448
        if (remove.indexOf(server.id) > -1) {
449
            var remove_exists = server_exists(server);
450
            servers.splice(remove_exists[1], 1);
451
            $(window).trigger("vm:remove", server);
452
        }
453
    });
454
}
455

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
897
    var serverID = serverIDs.pop();
898

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

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

    
959
    var serverID = serverIDs.pop();
960

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

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

    
1001
    var serverID = serverIDs.pop();
1002

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

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

    
1045
    var serverID = serverIDs.pop();
1046

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

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

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

    
1090
    vd.close();
1091
}
1092

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

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

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

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

    
1125
    var serverID = serverIDs.pop();
1126

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

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

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

    
1173
    if (!vm) return false;
1174

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

    
1183
// connect to machine action
1184
function machine_connect(serverIDs){
1185
    if (!serverIDs.length){
1186
        //ajax_success('DEFAULT');
1187
        return false;
1188
    }
1189

    
1190
    var serverID = serverIDs.pop();
1191
    var machine = get_machine(serverID);
1192
    var serverName = machine.name;
1193
    
1194
    try {
1195
        var serverIP = machine.addresses.values[0].values[0].addr;
1196
    } catch(err) { var serverIP = 'undefined'; }
1197

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

    
1202
    var params_url = '?ip_address=' + serverIP + '&os=' + os + "&host_os=" + $.client.os;
1203
    
1204
    if ($.client.os == "Windows" && os == "windows") {
1205
        window.open('machines/connect' + params_url + "&rdp=1");
1206
        return;
1207
    }
1208

    
1209
    try {
1210
        msg_box({title:'Connect to ' + serverName,content:'loading...',extra:'',
1211
        'ajax':'machines/connect' + params_url,
1212
        parse_data:function(data){
1213
            data.title = false;
1214
            data.content = data.info;
1215
            data.extra = "<a href='"+data.link.url+"'>"+data.link.title+"</a>";
1216
            return data;
1217
        }
1218
        });
1219
    } catch (error) {
1220
        window.open('machines/connect' + params_url);
1221
    }
1222

    
1223

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

    
1228
    return false;
1229
}
1230

    
1231

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1773
function get_private_ips(server) {
1774

    
1775
}
1776

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

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

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

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

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

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

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

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

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

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

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

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

    
1862
            if (other.length >= 1) {
1863
                return;
1864
            }
1865

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

    
1870
            if (action in {'console':''}) {
1871
                return;
1872
            }
1873

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

    
1887
        });
1888
    }
1889

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

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

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

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

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

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

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

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

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

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

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

    
1947
        // reset previous state
1948
        list_view_hide_action_indicators();
1949

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

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

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

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

    
1996

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

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

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

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

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

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

    
2031
}
2032

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

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

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

    
2052
    var size = sizes_map[machines_view];
2053
    var img_selector = views_map[machines_view];
2054
    var cls = states_map[state];
2055

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

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

    
2065
    // os changed
2066
    el.css("backgroundImage", new_img);
2067

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

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

    
2088

    
2089
// generic info box
2090

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

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

    
2100
    var sel = function(s){return $(s, box)};
2101

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

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

    
2135
    // requested to show remote data in msg_box
2136
    // 
2137
    if (config.ajax) {
2138
        $.ajax($.extend({ 
2139
            url:config.ajax, 
2140
            success: function(data){
2141
                // we want to get our data parsed before
2142
                // placing them in content
2143
                if (parse_data) {
2144
                    data = parse_data(data);
2145
                }
2146

    
2147
                // no json response
2148
                // load html body
2149
                if (load_html) {
2150
                    sel("div.machine-now-building").html(data);
2151
                    sel("div.machine-now-building").html(data);
2152
                } else {
2153

    
2154
                    if (data.title)
2155
                        sel("h3 span.header-box").text(data.title);
2156

    
2157
                    if (data.content) {
2158
                        sel("div.machine-now-building").html(data.content);
2159
                    }
2160
                    if (data.extra) {
2161
                        sel(".password-container .password").html(data.extra);
2162
                        sel(".password-container").show();
2163
                    }
2164
                }
2165

    
2166
                if (user_success) {
2167
                    user_success($("div.machine-now-building"));
2168
                }
2169
            },
2170
        }, config.ajax_config));
2171
    }
2172
    return false;
2173
}
2174

    
2175

    
2176
function show_invitations() {
2177

    
2178
    handle_invitations = function(el) {
2179
        el.addClass("invitations");
2180
        var cont = el;
2181
        var form = $(el).find("form");
2182
        $("#invform #removable-name-container-1").dynamicField();
2183
        form.submit(function(evn){
2184
            evn.preventDefault();
2185
            $.post(form.attr("action"), form.serialize(), function(data) {$(cont).html(data); handle_invitations(cont)});
2186
            return false;
2187
        });
2188
    }
2189
    msg_box({title:window.INVITATIONS_TITLE, content:'', ajax:INVITATIONS_URL, html:true, success: function(el){ 
2190
        handle_invitations(el)}
2191
    });
2192
}