Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ 19e01943

History | View | Annotate | Download (73.6 kB)

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

    
40

    
41
var error_timeout = 20000;
42
$.ajaxSetup({
43
    'beforeSend': function(xhr) {
44
          xhr.setRequestHeader("X-Auth-Token", $.cookie("X-Auth-Token"));
45
    },
46

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

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

    
66

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
396
        return false;
397
    }
398

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
898
    var serverID = serverIDs.pop();
899

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

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

    
960
    var serverID = serverIDs.pop();
961

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

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

    
1002
    var serverID = serverIDs.pop();
1003

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

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

    
1046
    var serverID = serverIDs.pop();
1047

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

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

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

    
1091
    vd.close();
1092
}
1093

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

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

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

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

    
1126
    var serverID = serverIDs.pop();
1127

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

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

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

    
1174
    if (!vm) return false;
1175

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

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

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

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

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

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

    
1226

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

    
1231
    return false;
1232
}
1233

    
1234

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1776
function get_private_ips(server) {
1777

    
1778
}
1779

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1890
        });
1891
    }
1892

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1999

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

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

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

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

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

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

    
2034
}
2035

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

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

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

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

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

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

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

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

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

    
2091

    
2092
// generic info box
2093

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

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

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

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

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

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

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

    
2157
                    if (data.title)
2158
                        sel("h3 span.header-box").text(data.title);
2159

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

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

    
2178

    
2179
function show_invitations() {
2180

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