Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ 17ee954a

History | View | Annotate | Download (42 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

    
36
{% load i18n %}
37

    
38
<div id="machines" class="separator"></div>
39

    
40
<!-- the create button -->
41
<div id="ie-fix">
42
    <div id="createcontainer">
43
        <div id="beforecreate" style="display:inline;"></div>
44
        <a id="create" rel="#wizard" href="#">{% trans "Create New +" %}</a>
45
    </div>
46
</div>
47

    
48
<!-- changing between standard/list view -->
49
<div id="ie-fix-view-select">
50
    <div id="view-select">
51
        <a id="standard" href="{% url machines-standard %}"></a>
52
        <a id="list" href="{% url machines-list %}"></a>
53
        <a id="single" href="{% url machines-single %}"></a>
54
    </div>
55
</div>
56

    
57
<div id="emptymachineslist">
58
    <h1 id="welcomeheader">{% trans "Welcome to ~okeanos !" %}</h1>
59
    <br />
60
    <span class="welcomebody">{% trans "From this panel you will be able to manage your Virtual Machines (VMs). If you don't know what a VM is: " %}<br /><a href="#">{% trans "take the tour" %}</a>.</span>
61
    <br />
62
    <br />
63
    <span class="welcomebody">{% trans "The panel is currently empty, because you don't have any VMs yet. Start by clicking the orange button on the top left. The wizard will guide you through the whole process." %}</span>
64
    <br />
65
    <br />
66
    <span class="welcomefooter">{% trans "For more information or help, click " %}<a href="#">{% trans "here" %}</a>.</span>
67
</div>
68

    
69
<!-- the form -->
70
<form action="#">
71
    <!-- scrollable root element -->
72
    <div class="modal" id="wizard">
73
        <!-- status bar -->
74
        <ul id="status">
75
            <li class="active li-0">
76
                <span class="headernumber" class="first">1</span>
77
                <div class="headerbody first">{% trans "Image" %}</div>
78
                <img src="static/check.png" class="img-check" style="visibility:hidden;" />
79
            </li>
80
            <li class="li-1">
81
                <span class="headernumber">2</span>
82
                <div class="headerbody">{% trans "Flavor" %}</div>
83
                <img src="static/check.png" class="img-check" style="visibility:hidden;" />
84
            </li>
85
            <li class="li-2">
86
                <span class="headernumber">3</span>
87
                <div class="headerbody">{% trans "Name" %}</div>
88
            </li>
89
        </ul>
90
        <!-- scrollable items -->
91
        <div class="items">
92
            <!-- pages -->
93
            <div class="page page1">
94
                <h2>{% trans "Select an OS" %}</h2>
95
                <hr class="topruler" />
96
                <div id="tabscontainer">
97
                    <ul class="tabs">
98
                        <li><a href="#">{% trans "system images" %}</a></li>
99
                        <li><a href="#">{% trans "custom images" %}</a></li>
100
                    </ul>
101
                </div>
102
                <div class="panes">
103
                    <li id="image-template" style="display:none;">
104
                        <label for="image.id">
105
                            <a>
106
                                <div class="image-container">
107
                                    <div class="image">
108
                                        <input class="radio" type="radio" name="image-id" id="image-id" />
109
                                        <img src="" class="image-logo"/>
110
                                        <strong class="image-title">image.title</strong>
111
                                        <br />
112
                                        <div class="description-container">
113
                                            <span class="description">image.description</span>
114
                                            <span id="size" class="size">?? MB</span><span class="size"> MB</span>
115
                                        </div>
116
                                    </div>
117
                                </div>
118
                            </a>
119
                        </label>
120
                    </li>
121
                    <ul class="pane" id="standard-images">
122
                        <!-- standard images -->
123
                    </ul>
124
                    <ul class="pane" id="custom-images">
125
                        <!-- custom images -->
126
                    </ul>
127
                </div>
128
                <hr class="bottomruler" />
129
                <button type="button" class="prev" id="cancel">{% trans "Cancel" %}</button>
130
                <button type="button" class="next right">{% trans "Next" %}<img src="static/next.png" class="img-next" /></button>
131
            </div>
132
            <div class="page page2">
133
                <h2>{% trans "Select CPUs, RAM and Disk Size" %}</h2>
134
                <hr class="topruler" />
135
                <ul>
136
                    <li id="machinetype">
137
                        <div class="machine-type">
138
                            <label for="small" id="small">
139
                                <input type="radio" id="small" name="machine-type" value="small" checked="true" />
140
                                <span class="typebody" id="small-body">{% trans "small" %}</span>
141
                            </label>
142
                        </div>
143
                        <div class="machine-type">
144
                            <label for="medium" id="medium">
145
                                <input type="radio" id="medium" name="machine-type" value="medium" />
146
                                <span class="typebody" id="medium-body">{% trans "medium" %}</span>
147
                            </label>
148
                        </div>
149
                        <div class="machine-type">
150
                            <label for="large" id="large">
151
                                <input type="radio" id="large" name="machine-type" value="large" />
152
                                <span class="typebody" id="large-body">{% trans "large" %}</span>
153
                            </label>
154
                        </div>
155
                        <div class="machine-type">
156
                            <label for="custom" id="custom">
157
                                <input type="radio" name="machine-type" id="custom" value="large" />
158
                                <span class="typebody" id="custom-body">{% trans "custom" %}</span>
159
                            </label>
160
                        </div>
161
                    </li>
162
                    <div id="page2-container">
163
                        <li class="slider-container">
164
                            <label><strong class="sliders">{% trans "CPUs" %}</strong></label>
165
                            <input type="range" id="cpu" style="display:none" />
166
                            <input type="text" class="range" id="cpu-indicator" />
167
                            <span class="units">{% trans "cores" %}</span>
168
                        </li>
169
                        <li class="slider-container">
170
                            <label><strong class="sliders">{% trans "RAM" %}</strong></label>
171
                            <input type="range" id="ram" style="display:none" />
172
                            <input type="text" class="range" id="ram-indicator" />
173
                            <span class="units">MB</span>
174
                        </li>
175
                        <li class="slider-container">
176
                            <label><strong class="sliders">{% trans "Size" %}</strong></label>
177
                            <input type="range" id="storage" style="display:none" />
178
                            <input type="text" class="range" id="storage-indicator" />
179
                            <span class="units">GB</span>
180
                        </li>
181
                        <li>
182
                            <div class="cost">
183
                                <span> {% trans "Your wallet:" %} 10,000 {% trans "Credits" %} </span> | <span>{% trans "This setup will cost you:" %}<input type="text" id="credits-indicator" value="0" class="range" disabled="disabled" /> {% trans "C/hour" %}</span>
184
                            </div>
185
                        </li>
186
                    </div>
187
                </ul>
188
                <hr class="bottomruler" />
189
                <button type="button" class="prev"><img src="static/prev.png" class="img-prev" />{% trans "Back" %}</button>
190
                <button type="button" class="next right">{% trans "Next" %}<img src="static/next.png" class="img-next" /></button>
191
            </div>
192
            <div class="page page3">
193
                <h2>{% trans "Confirm your settings" %}</h2>
194
                <hr class="topruler" />
195
                <ul id="page3-container">
196
                    <li class="required" id="label-name">
197
                        <label>
198
                            <strong>{% trans "Name" %}:</strong>
199
                            <input type="text" class="text" name="machine_name" id="name" value="My Ubuntu 10.04 x86_64 server"/>
200
                        </label>
201
                    </li>
202
                    <li>
203
                        <span>{% trans "Image:" %}</span> <span id="machine_image-label">Ubuntu 10.04 x86_64 server</span>
204
                    </li>
205
                    <li>
206
                        <span>{% trans "CPUs:" %}</span> <span id="machine_cpu-label">2</span> <span>{% trans "cores" %}</span>
207
                    </li>
208
                    <li>
209
                        <span>{% trans "RAM:" %}</span> <span id="machine_ram-label">1024</span><span>MB</span>
210
                    </li>
211
                    <li>
212
                        <span>{% trans "System Disk:" %}</span> <span id="machine_storage-label">10</span><span>GB</span>
213
                    </li>
214
                    <li>
215
                        <span>{% trans "Cost per Hour:" %}</span> <span>40 {% trans "credits" %}</span>
216
                    </li>
217
                    <li>
218
                        <span>{% trans "Credits in Wallet:" %}</span> <span>10.000</span>
219
                    </li>
220
                </ul>
221
                <hr class="bottomruler" />
222
                <button type="button" class="prev"><img src="static/prev.png" class="img-prev" />{% trans "Back" %}</button>
223
                <button type="button" class="next right" id="start">{% trans "Create VM" %}</button>
224
            </div>
225
        </div>
226
        <div class="separator-end"></div>
227
    </div>
228
</form>
229

    
230
<!-- metadata overlay -->
231
<div>
232
    <div id="metadata-wizard" class="modal">
233
        <h3 class="popup-header">{% trans "Manage Tags" %}</h3>
234
        <p style='display:none;'>hidden server id</p>
235
        <div id="on-off" style='display:none;'>hidden server id</div>
236
        <div class="popup-body">
237
            <div class="popup-body-inner">
238
                <div class="popup-title">{% trans "Create, edit and delete Tags for machine:" %}</div>
239
                <div class="name-container">
240
                    <img src="" class="machine-icon" />
241
                    <div class="machine-name"></div>
242
                </div>
243
                <div class="popup-separator"></div>
244
                <div class="large-spinner" style="display:none;"></div>
245
                <div class="metadata-container">
246
                    <!-- append metadata entries here -->
247
                </div>
248
                <div class="metadata-add-template" style="display:none;">
249
                    <input type="text" id="add-meta-key" maxlength="15"></input>
250
                    <ul style="display:none;" class="dropdown-container">
251
                        {% for o in default_keywords %}
252
                            <li><span class="dropdownitem">{{o}}</span></li>
253
                        {% endfor %}
254
                    </ul>
255
                    <input type="text" id="add-meta-value" maxlength="150" value="{% trans 'max 150 characters' %}"></input>
256
                    <div class="addbuttons">
257
                        <div class="save"></div>
258
                        <div class="cancel"></div>
259
                    </div>
260
                </div>
261
                <div class="metadata-pair-template" style="display:none;">
262
                    <div class="metadata-key">{% trans "OS" %}</div>
263
                    <div class="vertical-separator"></div>
264
                    <div class="metadata-value">{% trans "Debian" %}</div>
265
                    <div class="metadata-full-value" style="display:none;"></div>
266
                    <div class="metadata-edit">
267
                        <div class="edit"></div>
268
                        <div class="remove"></div>
269
                    </div>
270
                    <div class="editbuttons" style="display:none;">
271
                        <div class="save"></div>
272
                        <div class="remove"></div>
273
                    </div>
274
                </div>
275
            </div>
276
        </div>
277
        <div class="buttons">
278
            <button type="button" class="save" id="metadata-cancel">{% trans "Close" %}</button>
279
            <button type="button" class="create" id="metadata-create">{% trans "Create New" %}</button>
280
        </div>
281
    </div>
282
</div>
283

    
284
<a id="metadata-scrollable" href="#" rel="#metadata-wizard"></a>
285

    
286
<div id="machinesview"></div>
287

    
288
<div class="confirm_multiple">
289
    <p>{% trans "Your actions will affect" %} <span class="actionLen">XX</span> {% trans "machines" %}</p>
290
    <button class="yes">{% trans "Confirm All" %}</button>
291
    <button class="no">{% trans "Cancel All" %}</button>
292
</div>
293

    
294
<script>
295

296
// TODO: This should be populated with more rules for all available states
297
var actions = { 'reboot':        ['UNKOWN', 'ACTIVE', 'REBOOT'],
298
                'shutdown':      ['UNKOWN', 'ACTIVE', 'REBOOT'],
299
                'console':       ['ACTIVE'],
300
                'start':         ['UNKOWN', 'STOPPED'],
301
                'destroy':       ['UNKOWN', 'ACTIVE', 'STOPPED', 'REBOOT', 'ERROR', 'BUILD']
302
               };
303

304

305
//change hover icon on prev,next buttons
306
$("#wizard button.next").hover(function() {
307
        $(this).find(".img-next").attr("src","static/next-hover.png");
308
    },
309
    function() {
310
        $(this).find(".img-next").attr("src","static/next.png");
311
    }
312
);
313
$("#wizard button.prev").hover(function() {
314
        $(this).find(".img-prev").attr("src","static/prev-hover.png");
315
    },
316
    function() {
317
        $(this).find(".img-prev").attr("src","static/prev.png");
318
    }
319
);
320

321
//add hover to labels
322
$('#machines-pane span.typebody').mouseover(function() {
323
    $(this).addClass('typehover');
324
});
325
$('#machines-pane span.typebody').mouseout(function() {
326
    $(this).removeClass('typehover');
327
});
328

329
// switch to list view
330
$("#machines-pane a#list").click(function(){
331
    list_view();
332
    return false;
333
});
334

335
// switch to standard view
336
$("#machines-pane a#standard").click(function(){
337
    standard_view();
338
    return false;
339
});
340

341
// switch to single view
342
$("#machines-pane a#single").click(function(){
343
    single_view();
344
    return false;
345
});
346

347
// launch VM creation wizard
348
$("#machines-pane a#create").click(function(){
349
    // launch wizard only if images and flavors are found
350
    if (images.length > 0  && flavors.length > 0) {
351
        $('#machines-pane a#create').data('overlay').close();
352
        $("#wizard").scrollable().begin();
353
        $("#wizard").show();
354
        $('#machines-pane a#create').data('overlay').load();
355
        // enable submit button
356
        $("#wizard #start").removeAttr('disabled');
357
    } else if (images.length == 0 ) {
358
        ajax_error('NO_IMAGES');
359
        return false;
360
    } else if (flavors.length == 0) {
361
        ajax_error('NO_FLAVORS');
362
        return false;
363
    }
364
});
365

366
// create wizard overlay
367
$(function() {
368
    $("#machines-pane a#create").overlay({
369
        mask: '#666',
370
        effect: 'default',
371
        top: '5%',
372
        oneInstance: false,
373
        closeOnClick: false
374
    });
375
});
376

377
// wizard
378
$(function() {
379
    var root = $("#wizard").scrollable();
380
    var api = root.scrollable();
381
    // rangeinput with default configuration
382
    // validation logic is done inside the onBeforeSeek callback
383
    api.onBeforeSeek(function(event, i) {
384
        // update status bar
385
        $("#status li").removeClass("active").eq(i).addClass("active");
386
        // we are going 1 step backwards so no need for validation
387
        if (api.getIndex() > i) {
388
            $("#wizard .li-" + i).removeClass("checked");
389
            $("#wizard .li-" + i).find(".img-check").css("visibility","hidden");
390
        }
391
        if (api.getIndex() < i) {
392
            $("#wizard .li-" + api.getIndex()).addClass("checked");
393
            $("#wizard .li-" + api.getIndex()).find(".img-check").css("visibility","visible");
394
             // 1. get current page
395
             var page = root.find(".page").eq(api.getIndex()),
396
             // 2. .. and all required fields inside the page
397
             inputs = page.find(".required :input").removeClass("error"),
398
             // 3. .. which are empty
399
             empty = inputs.filter(function() {
400
                return $(this).val().replace(/\s*/g, '') == '';
401
             });
402
             // if there are empty fields, then
403
            if (empty.length) {
404
                // add a CSS class name "error" for empty & required fields
405
                empty.addClass("error");
406
                // cancel seeking of the scrollable by returning false
407
                return false;
408
            // everything is good
409
            }
410
        }
411
        // update confirm step
412
        if (api.getIndex()==0) {
413
            var image = $("input[type=radio][name=image-id]:checked");
414
            var imageRef = image.length ? image[0].id : false
415
            if (imageRef) {
416
                var imageName = $("label[for=" + imageRef + "] .image-title").text();
417
                $("#machine_image-label")[0].textContent = imageName;
418
                $("input[type=text][name=machine_name]")[0].value = "My " + imageName + " server";
419
            }
420
        } else if (api.getIndex()==1) {
421
            $("#machine_cpu-label")[0].textContent = $("#cpu-indicator")[0].value;
422
            $("#machine_ram-label")[0].textContent = $("#ram-indicator")[0].value;
423
            $("#machine_storage-label")[0].textContent = $("#storage-indicator")[0].value;
424
        }
425
    });
426
    // if tab is pressed on the next button seek to next page
427
    $(root).live('keydown', function (e) {
428
       if ( e.keyCode == 9 ){
429
           if(e.preventDefault) {
430
               e.preventDefault();
431
           }
432
           api.next();
433
        }
434
    });
435
    //submit wizard by pressing enter on the name textbox
436
    $("#name").keypress(function (e) {
437
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
438
            $('#start').click();
439
            return false;
440
        } else {
441
            return true;
442
        }
443
    });
444
});
445

446
// disable sliders in flavor selection
447
function disableSliders() {
448
    $("#cpu").attr('disabled',true);
449
    $("#ram").attr('disabled',true);
450
    $("#storage").attr('disabled',true);
451
}
452

453
//update radio button when clicking on text
454
$("#small-body").live('click' ,function() {
455
    $(this).parent().find("#small").click();
456
});
457

458
$("#medium-body").live('click' ,function() {
459
    $(this).parent().find("#medium").click();
460
});
461

462
$("#large-body").live('click' ,function() {
463
    $(this).parent().find("#large").click();
464
});
465

466
$("#custom-body").live('click' ,function() {
467
    $(this).parent().find("#custom").click();
468
});
469

470
//select image div on radio button select
471
$('#machines-pane .radio').live('click' ,function() {
472
    $(this).parents("div").find(".image").removeClass('selecteddiv');
473
    if($(this).is(':checked'))  {
474
        $(this).parent().addClass('selecteddiv');
475
    }
476
});
477

478
// validate cpu input box
479
$("#cpu-indicator").live('change',function(){
480
    var v = Number(this.value);
481
    var i = cpus.indexOf(v);
482
    if (isNaN(v)) {
483
        $(this).value = cpus[0];
484
        $("#cpu").data('rangeinput').setValue(0);
485
    } else if (i == -1) {
486
        for (var j=0; j < cpus.length; j++)
487
            if (v<cpus[j])
488
                break;
489
        $("#cpu").data('rangeinput').setValue(j);
490
    } else {
491
        $("#cpu").data('rangeinput').setValue(i);
492
    }
493
    return false;
494
});
495

496
// validate ram input box
497
$("#ram-indicator").live('change',function(){
498
    var v = Number(this.value);
499
    var i = ram.indexOf(v);
500
    if (isNaN(v)) {
501
        $(this).value = cpus[0];
502
        $("#ram").data('rangeinput').setValue(0);
503
    } else if (i == -1) {
504
        for (var j=0; j < ram.length; j++)
505
            if (v<ram[j])
506
                break;
507
        $("#ram").data('rangeinput').setValue(j);
508
    } else {
509
        $("#ram").data('rangeinput').setValue(i);
510
    }
511
    return false;
512
});
513

514
// validate storage input box
515
$("#storage-indicator").live('change',function(){
516
    var v = Number(this.value);
517
    var i = disks.indexOf(v);
518
    if (isNaN(v)) {
519
        $(this).value = disks[0];
520
        $("#storage").data('rangeinput').setValue(0);
521
    } else if (i == -1) {
522
        for (var j=0; j < disks.length; j++)
523
            if (v<disks[j])
524
                break;
525
        $("#storage").data('rangeinput').setValue(j);
526
    } else {
527
        $("#storage").data('rangeinput').setValue(i);
528
    }
529
    return false;
530
});
531

532
// selecting the small size
533
$("#small").click(function(){
534
    $("#cpu").data('rangeinput').setValue(0);
535
    $("#ram").data('rangeinput').setValue(0);
536
    $("#storage").data('rangeinput').setValue(0);
537
    $("#cpu-indicator")[0].value = cpus[0];
538
    $("#ram-indicator")[0].value = ram[0];
539
    $("#storage-indicator")[0].value = disks[0];
540
    $("#small").addClass("active");
541
    $("#medium").removeClass("active");
542
    $("#large").removeClass("active");
543
    $("#custom").removeClass("active");
544
});
545

546
// selecting the medium size
547
$("#medium").click(function(){
548
    $("#cpu").data('rangeinput').setValue(1);
549
    $("#ram").data('rangeinput').setValue(1);
550
    $("#storage").data('rangeinput').setValue(1);
551
    $("#cpu-indicator")[0].value = cpus[1];
552
    $("#ram-indicator")[0].value = ram[1];
553
    $("#storage-indicator")[0].value = disks[1];
554
    $("#medium").addClass("active");
555
    $("#small").removeClass("active");
556
    $("#large").removeClass("active");
557
    $("#custom").removeClass("active");
558
});
559

560
// selecting the large size
561
$("#large").click(function(){
562
    $("#cpu").data('rangeinput').setValue(2);
563
    $("#ram").data('rangeinput').setValue(2);
564
    $("#storage").data('rangeinput').setValue(2);
565
    $("#cpu-indicator")[0].value = cpus[2];
566
    $("#ram-indicator")[0].value = ram[2];
567
    $("#storage-indicator")[0].value = disks[2];
568
    $("#large").addClass("active");
569
    $("#medium").removeClass("active");
570
    $("#small").removeClass("active");
571
    $("#custom").removeClass("active");
572
});
573

574
// selecting the custom flavor enables the sliders
575
$("#custom").click(function(){
576
    $("#cpu").attr('disabled',false);
577
    $("#ram").attr('disabled',false);
578
    $("#storage").attr('disabled',false);
579
    $("strong.sliders").style = 'color: #778899;';
580
    $("#custom input").attr('checked', 'checked');
581
    $("#custom").addClass("active");
582
    $("#medium").removeClass("active");
583
    $("#large").removeClass("active");
584
    $("#small").removeClass("active");
585
});
586

587
//when textbox gains focus, add selection in css
588
$('#cpu-indicator').focus(function() {
589
    $(this).addClass('selectedrange');
590
});
591

592
$('#ram-indicator').focus(function() {
593
    $(this).addClass('selectedrange');
594
});
595

596
$('#storage-indicator').focus(function() {
597
    $(this).addClass('selectedrange');
598
});
599

600
//when textbox loses focus, clear selection in css
601
$('#cpu-indicator').blur(function() {
602
    $(this).removeClass('selectedrange');
603
});
604

605
$('#ram-indicator').blur(function() {
606
    $(this).removeClass('selectedrange');
607
});
608

609
$('#storage-indicator').blur(function() {
610
    $(this).removeClass('selectedrange');
611
});
612

613
// exit the wizard
614
$("#cancel").click(function() {
615
    $("#machines-pane a#create").overlay().close();
616
});
617

618
// starting a new VM through the wizard
619
$("#start").click(function() {
620
    var imageRef = $('input[type=radio][name=image-id]:checked')[0].id.replace('img-radio-','');
621
    var flavorRef = identify_flavor($("#cpu-indicator")[0].value, $("#storage-indicator")[0].value, $("#ram-indicator")[0].value);
622
    var machineName = $('input[name=machine_name]')[0].value;
623
    if (jQuery.trim(machineName) == ''){
624
        return false;
625
    }
626

627
    // replace text 'create new' with progress indicator
628
    $(this).text('');
629
    $(this).html('<img src="static/icons/indicators/medium/horizontal-progress.gif" / >');
630
    // disable submit button to prevent multiple calls
631
    $(this).attr("disabled", true);
632

633
    create_vm(machineName, imageRef, flavorRef);
634

635
    try {
636
        console.warn('creating ' + $("input[name=machine_name]")[0].value);
637
    } catch(err){}
638

639
});
640

641
// metadata wizard
642
$(function() {
643
    // create wizard overlay
644
    $("a#metadata-scrollable").overlay({
645
        mask: '#666',
646
        effect: 'default',
647
        top: '10%',
648
        closeOnClick: false,
649
        oneInstance: false,
650
        closeOnEsc: false,
651
        load: false,
652
        onClose: function() {
653
            // reset input areas
654
            serverID = $("#metadata-wizard p:first").text();
655
            $("#metadata-wizard div.metadata-container").empty();
656
            get_metadata(serverID, true);
657
        }
658
    });
659
});
660

661
// bring up metadata overlay
662
function show_metadata_wizard() {
663
    // get metadata for current server and fill the dialog
664
    serverID = $("#metadata-wizard p:first").text();
665
    get_metadata(serverID);
666
    $("#metadata-wizard").show();
667
    $("a#metadata-scrollable").data('overlay').load();
668
    $('#metadata-wizard .large-spinner').show();
669
    return false;
670
}
671

672
// update metadata list
673
function list_metadata(data) {
674
    // empty the list if it already exists
675
    $("#metadata-wizard div.metadata-container").empty();
676
    // get the values to show
677
    meta = data.metadata.values;
678
    // set serve icon
679
    var icon_name = os_icon(data.metadata);
680
    $("#metadata-wizard .machine-icon").attr("src","static/icons/machines/small/" + icon_name + '-' + $("#metadata-wizard div#on-off").text() + '.png');
681
    // show values
682
    for (key in meta) {
683
        pair = $("#metadata-wizard div.metadata-pair-template:last").clone();
684
        //truncate metadata
685
        pair.find("div.metadata-key").text(key.substring(0,15));
686
        if (meta[key].length > 25) {
687
            pair.find("div.metadata-value").text(meta[key].substring(0,25) + "...");
688
        } else {
689
            pair.find("div.metadata-value").text(meta[key]);
690
        }
691
        //get the serverID
692
        serverID = $("#metadata-wizard p:first").text();
693
        //store the full metadata value on a hidden div
694
        pair.find("div.metadata-full-value").text(meta[key]);
695
        // show/hide edit-remove buttons on hover
696
        pair.hover(function () {$(this).find('.metadata-edit').show();}, function () {$(this).find('.metadata-edit').hide();});
697
        // add it to the list
698
        pair.appendTo("#metadata-wizard div.metadata-container").fadeIn();
699
    }
700
}
701

702
// exit the metadata wizard
703
$("#metadata-cancel").click(function(){
704
    $("a#metadata-scrollable").overlay().close();
705
});
706

707
//intercept create new metadata click
708
$("#metadata-wizard #metadata-create").click(function(){
709
    pair = $("#metadata-wizard div.metadata-add-template:first").clone();
710
    pair.prependTo("#metadata-wizard div.metadata-container").fadeIn();
711
      with (pair.find('input#add-meta-key')) {
712
        with (pair.find('ul:first')) {
713
          find('li').click(function() {
714
            $(this).parent().parent().find('.textdropdown-outer').find('input:first').attr('value', $(this).find('.dropdownitem').html());
715
            $(this).parent().hide();
716
          });
717
          hide();
718
        }
719

720
        keypress(function() {
721
          $(this).parent().next('ul:first').hide();
722
        });
723

724
        change(function() {
725
          $(this).parent().next('ul:first').hide();
726
        });
727

728
        wrap('<div class="textdropdown-outer" style="width: ' + width() + 'px; height: ' + (height() + 5) + 'px"></div>');
729
        var btn = parent().prepend('<div class="textdropdown-btn">&nbsp;</div>').find('.textdropdown-btn');
730
        width(width() - btn.width() - 5);
731
        css("border", "0");
732

733
        btn.click(function() {
734
          var p = $(this).parent();
735
          with (p.next('ul:first')) {
736
            $(this).parent().parent().find('ul:first').css('position', 'absolute');
737
            $(this).parent().parent().find('ul:first').css('width',    p.width());
738
            $(this).parent().parent().find('ul:first').css('left',     p.position().left + 4);
739
            $(this).parent().parent().find('ul:first').css('top',      p.position().top + p.height() + 1);
740
            var elem = $(this).parent().parent().find('ul:first')[0];
741
            if(elem.style.display == 'none') {
742
                 $(this).parent().parent().find('ul:first').show();
743
            } else {
744
                 $(this).parent().parent().find('ul:first').hide();
745
            }
746

747
          }
748
        });
749
      }
750
    pair.find('input#add-meta-key').focus();
751
    //submit keyword by pressing enter on the textbox
752
    $(this).parent().parent().find('input#add-meta-value').keypress(function (e) {
753
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
754
            $(this).parent().parent().find('.addbuttons .save').click();
755
            return false;
756
        } else {
757
            return true;
758
        }
759
    });
760
});
761

762
//save new metadata
763
$('#metadata-wizard .addbuttons .save').die('click');
764
$('#metadata-wizard .addbuttons .save').live('click', function(){
765
    keyValue = $(this).parent().parent().find('input#add-meta-key').val();
766
    valValue = $(this).parent().parent().find('input#add-meta-value').val();
767
    if ((keyValue == '{% trans 'max 15 characters' %}') || (valValue == '{% trans 'max 150 characters' %}')) {
768
        return false;
769
    } else {
770
        serverID = $("#metadata-wizard p:first").text();
771
        pair = $("#metadata-wizard div.metadata-pair-template:last").clone();
772
        pair.find("div.metadata-key").text(keyValue.substring(0,15));
773
        if (valValue.length > 25) {
774
            pair.find("div.metadata-value").text(valValue.substring(0,25) + "...");
775
        } else {
776
            pair.find("div.metadata-value").text(valValue);
777
        }
778
        pair.find("div.metadata-full-value").text(valValue);
779
        update_metadata(serverID, keyValue, valValue);
780
        $(this).parent().parent().remove();
781
        pair.hover(function () {$(this).find('.metadata-edit').show();}, function () {$(this).find('.metadata-edit').hide();});
782
        // add it to the list
783
        if ($("#metadata-wizard div.metadata-container").find("div.metadata-pair-template").length > 0) {
784
            pair.insertBefore("#metadata-wizard div.metadata-container div.metadata-pair-template:first").fadeIn();
785
        } else {
786
            pair.prependTo("#metadata-wizard div.metadata-container").fadeIn();
787
        }
788
    }
789
});
790

791
//intercept cancel new metadata creation
792
$("#metadata-wizard .addbuttons .cancel").die('click');
793
$("#metadata-wizard .addbuttons .cancel").live('click',function(){
794
    $(this).parent().parent().fadeOut('fast', function() { $(this).remove(); });
795
});
796

797
//metadata remove button
798
$("#metadata-wizard .metadata-edit .remove").die('click')
799
$("#metadata-wizard .metadata-edit .remove").live('click', function() {
800
    $(this).parent().parent().fadeOut('slow');
801
    serverID = $("#metadata-wizard p:first").text();
802
    keyValue = $(this).parent().parent().find('div.metadata-key').text();
803
    //update icons if deleting the OS metadata
804
    if (keyValue == "OS") {
805
        $("#metadata-wizard .machine-icon").attr("src","static/icons/machines/small/unknown-" + $("#metadata-wizard div#on-off").text() + '.png');
806
        $("#machinesview-icon").find("div#" + serverID).find("img.logo").attr("src", "static/icons/machines/medium/unknown-" + $("#metadata-wizard div#on-off").text() + '.png');
807
    }
808
    delete_metadata(serverID, keyValue);
809
});
810

811
//metadata edit button
812
$("#metadata-wizard .metadata-edit .edit").die('click');
813
$("#metadata-wizard .metadata-edit .edit").live('click', function() {
814
    $(this).parent().parent().find('div.metadata-value').html("<input id=\"value-edit\" maxlength=\"150\" type=\"text\" class=\"metatextbox\" value=\"" + $(this).parent().parent().find('.metadata-full-value').text() +
815
                                    "\" / ><span class=\"oldValue\">" +
816
                                    $(this).parent().parent().find('.metadata-full-value').text() + "</span>");
817
    //submit keyword by pressing enter on the textbox
818
    $(this).parent().parent().find('input.metatextbox').keypress(function (e) {
819
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
820
            $(this).parent().parent().find('.editbuttons .save').click();
821
            return false;
822
        } else {
823
            return true;
824
        }
825
    });
826
    $(this).parent().parent().find('input.metatextbox').select()
827
    $(this).parent().hide();
828
    $(this).parent().parent().unbind('mouseenter').unbind('mouseleave');
829
    $(this).parent().parent().find('.editbuttons').show();
830
});
831

832
//capture Esc key
833
bar = {};
834
bar.keydown = function(e) {
835
    if (e.keyCode == 27) {
836
        //if we are inside an add or edit textbox, cancel editing
837
        if ($('input.metatextbox:focus').length > 0) {
838
            $('input.metatextbox:focus').parent().parent().find('.editbuttons .remove').click();
839
        } else if ($('input#add-meta-key:focus').length > 0)  {
840
            $('input#add-meta-key:focus').parent().parent().find('.addbuttons .cancel').click();
841
        } else if ($('input#add-meta-value:focus').length > 0) {
842
            $('input#add-meta-value:focus').parent().parent().find('.addbuttons .cancel').click();
843
        } else {
844
            //else close the metadata wizard
845
            $("a#metadata-scrollable").overlay().close();
846
        }
847
        e.preventDefault();
848
        e.stopPropagation();
849
    }
850
};
851
document.keydown = bar.keydown;
852

853
//metadata cancel edit button
854
$("#metadata-wizard .editbuttons .remove").die('click');
855
$("#metadata-wizard .editbuttons .remove").live('click', function() {
856
    var oldValue = $(this).parent().parent().find('.oldValue').text();
857
    if (oldValue.length > 25) {
858
        oldValue = oldValue.substring(0,25) + "...";
859
    }
860
    $(this).parent().parent().find('div.metadata-value').html(oldValue);
861
    $(this).parent().parent().hover(function () {$(this).find('.metadata-edit').show();}, function () {$(this).find('.metadata-edit').hide();});
862
    $(this).parent().hide();
863
});
864

865

866
//metadata save edit button
867
$("#metadata-wizard .editbuttons .save").die('click');
868
$("#metadata-wizard .editbuttons .save").live('click', function() {
869
    newValue = $(this).parent().parent().find('input.metatextbox').val();
870
    keyValue = $(this).parent().parent().find('div.metadata-key').text();
871
    oldValue = $(this).parent().parent().find('.oldValue').text();
872
    if (!(newValue == oldValue)) {
873
        update_metadata(serverID, keyValue, newValue);
874
    }
875
    if (newValue.length > 25) {
876
        newValueSort = newValue.substring(0,25) + "...";
877
    } else {
878
        newValueSort = newValue
879
    }
880
    $(this).parent().parent().find('div.metadata-value').html(newValueSort);
881
    $(this).parent().parent().find('div.metadata-full-value').html(newValue);
882
    $(this).parent().parent().hover(function () {$(this).find('.metadata-edit').show();}, function () {$(this).find('.metadata-edit').hide();});
883
    $(this).parent().hide();
884

885
});
886

887
// intercept create metadata key focus
888
$("#metadata-wizard input#add-meta-key").live('focusin', function() {
889
    if ($(this).parent().hasClass("div-enabled")) {
890
    } else {
891
        $(this).parent().addClass("div-enabled");
892
        $(this).addClass("input-enabled");
893
        if (this.value == '{% trans 'max 15 characters' %}') {
894
            this.value = '';
895
        }
896
    }
897
    return false;
898
});
899

900
// intercept create metadata key focus out
901
$("#metadata-wizard input#add-meta-key").live('focusout', function() {
902
    $(this).parent().removeClass("div-enabled");
903
    if (this.value == "") {
904
        $(this).removeClass("input-enabled");
905
        this.value = '{% trans 'max 15 characters' %}';
906
    }
907
    return false;
908
});
909

910

911
// intercept metadata dropdown item click
912
$(".metadata-add-template li").live('click', function() {
913
    $(this).parent().parent().parent().find("input#add-meta-value").focus();
914
    $(this).parent().parent().parent().find("input#add-meta-key").addClass("input-enabled");
915
});
916

917
// intercept create metadata key focus
918
$("#metadata-wizard input#add-meta-value").live('focusin', function() {
919
    if ($(this).hasClass("input-enabled")) {
920
    } else {
921
        $(this).addClass("input-enabled");
922
        this.value = '';
923
    }
924
    return false;
925
});
926

927
// intercept create metadata key focus out
928
$("#metadata-wizard input#add-meta-value").live('focusout', function() {
929
    if (this.value == "") {
930
        $(this).removeClass("input-enabled");
931
        this.value = '{% trans 'max 150 characters' %}';
932
    }
933
    return false;
934
});
935

936
// intercept click on cancel button in metadata add dialog
937
$('#add-dialog button.cancel').live('click', function() {
938

939
});
940

941
// intercept click on save button in metadata add dialog
942
$('#add-dialog button.save').live('click', function() {
943
    // if both fields are filled in
944
    if ($('input.key').hasClass("input-enabled") && $('textarea.value').hasClass("input-enabled")) {
945
        // get the server id, meta key and meta value needed for the ajax call
946
        var serverID = $(this).parent().find('h3 p').text();
947
        var meta_key = $(this).parent().find('input.key').attr('value');
948
        var meta_value = $(this).parent().find('textarea.value')[0].value;
949
        // make the ajax call and list the new GET results
950
        add_metadata(serverID, meta_key, meta_value);
951
        // go to previous step
952
        $('#add-dialog button.prev').click();
953
    } else {
954
        // find which field is not filled in and focus there
955
        if (!$('input.key').hasClass("input-enabled")) {
956
            $('input.key').focus();
957
            $('input.key').focusin();
958
        } else {
959
            $('textarea.value').focus();
960
            $('textarea.value').focusin();
961
        }
962
    }
963
    return false;
964
});
965

966
// confirm all actions
967
$("#machines-pane div.confirm_multiple .yes").live('click', function(){
968
    while(pending_actions.length > 0){ // if there is a pending action for this server execute it
969
        action = pending_actions.pop(); // extract action
970
        var serverID = action[1];
971
        if ($.cookie("view") != '1') { // standard view
972
            $('#' + serverID + ' .selected').removeClass('selected');
973
            $('#' + serverID + ' .display').removeClass('display');
974
            if (action[0] == shutdown) {
975
                $('#' + serverID + ' .status').text(TRANSITIONS['Shutting down']);
976
                $('#' + serverID + ' .state').removeClass().addClass('state shutting-state');
977
            } else if (action[0] == start) {
978
                $('#' + serverID + ' .status').text(TRANSITIONS['Starting']);
979
                $('#' + serverID + ' .state').removeClass().addClass('state starting-state');
980
            } else if (action[0] == reboot) {
981
                $('#' + serverID + ' .status').text(TRANSITIONS['Rebooting']);
982
                $('#' + serverID + ' .state').removeClass().addClass('state rebooting-state');
983
            } else if (action[0] == destroy) {
984
                $('#' + serverID + ' .status').text(TRANSITIONS['Destroying']);
985
                $('#' + serverID + ' .state').removeClass().addClass('state destroying-state');
986
            }
987
            $('#' + serverID + ' .spinner').show();
988
        } else { // list view
989
            osIcon = $('#'+serverID).parent().parent().find('.list-logo');
990
            osIcon.attr('os',osIcon.attr('src'));
991
            osIcon.attr('src','static/icons/indicators/small/progress.gif');
992
            if (action[0] == shutdown) {
993
                $('#' + serverID).parent().parent().find('span.status').text(TRANSITIONS['Shutting down']);
994
            } else if (action[0] == start) {
995
                $('#' + serverID).parent().parent().find('span.status').text(TRANSITIONS['Starting']);
996
            } else if (action[0] == reboot) {
997
                $('#' + serverID).parent().parent().find('span.status').text(TRANSITIONS['Rebooting']);
998
            } else if (action[0] == destroy) {
999
                $('#' + serverID).parent().parent().find('span.status').text(TRANSITIONS['Destroying']);
1000
            }
1001
        }
1002
        action[0]([serverID]); // execute action
1003
    }
1004
    $('#machinesview-list .actions .selected').removeClass('selected');
1005
    update_confirmations();
1006
    return false;
1007
});
1008

1009
// cancel all actions
1010
$("#machines-pane div.confirm_multiple button.no").live('click', function(){
1011
    pending_actions = [];
1012
    $('#machines-pane .machine .selected').removeClass('selected');
1013
    $('#machinesview-list .actions .selected').removeClass('selected');
1014
    $('#machines-pane .machine .display').removeClass('display');
1015

1016
    update_confirmations();
1017
    return false;
1018
});
1019

1020
// basic functions executed on page load
1021
if (images.length > 0) {
1022
    // populate image list
1023
    update_wizard_images();
1024
}
1025
if (flavors.length > 0) {
1026
    // configure flavors
1027
    update_wizard_flavors();
1028
}
1029
// create tabs for main menu
1030
$("ul.tabs").tabs("div.panes ul");
1031

1032
//fix ie z-index bug by moving the overlays to the bottom
1033
$(document).ready(function() {
1034
    if ($.browser.msie) {
1035
        $("body").append($("#wizard"));
1036
        $("body").append($("#metadata-wizard"));
1037
    }
1038
});
1039

1040
//IE specific fixes
1041
if ($.browser.msie) {
1042
    //IE fix for dropdown li hover
1043
    $("#metadata-wizard ul li").live("mouseenter", function () {
1044
        $(this).css("background-color","#efefef");
1045
        $(this).css("cursor","pointer");
1046
    });
1047
    $("#metadata-wizard ul li").live("mouseleave", function () {
1048
        $(this).css("background-color","transparent");
1049
        $(this).css("cursor","default");
1050
    });
1051
}
1052

    
1053
</script>