Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ 23307de4

History | View | Annotate | Download (42.7 kB)

1
<!--
2
Copyright 2011 GRNET S.A. All rights reserved.
3

4
Redistribution and use in source and binary forms, with or
5
without modification, are permitted provided that the following
6
conditions are met:
7

8
  1. Redistributions of source code must retain the above
9
     copyright notice, this list of conditions and the following
10
     disclaimer.
11

12
  2. Redistributions in binary form must reproduce the above
13
     copyright notice, this list of conditions and the following
14
     disclaimer in the documentation and/or other materials
15
     provided with the distribution.
16

17
THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
POSSIBILITY OF SUCH DAMAGE.
29

30
The views and conclusions contained in the software and
31
documentation are those of the authors and should not be
32
interpreted as representing official policies, either expressed
33
or implied, of GRNET S.A.
34
-->
35

    
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 %}" title="{% trans "Icon " %}"></a>
52
        <a id="list" href="{% url machines-list %}" title="{% trans "List " %}"></a>
53
        <a id="single" href="{% url machines-single %}" title="{% trans "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="/about">{% 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-labels">
246
                    <div class="metadata-label">{% trans "Tag" %}</div>
247
                    <div class="metadata-label last">{% trans "Value" %}</div>
248
                </div>
249
                <div class="metadata-container">
250
                    <!-- append metadata entries here -->
251
                </div>
252
                <div class="metadata-add-template" style="display:none;">
253
                    <input type="text" id="add-meta-key" maxlength="15"></input>
254
                    <ul style="display:none;" class="dropdown-container">
255
                        {% for o in default_keywords %}
256
                            <li><span class="dropdownitem">{{o}}</span></li>
257
                        {% endfor %}
258
                    </ul>
259
                    <input type="text" id="add-meta-value" maxlength="150" value="{% trans 'max 150 characters' %}"></input>
260
                    <div class="addbuttons">
261
                        <div class="save"></div>
262
                        <div class="cancel"></div>
263
                    </div>
264
                </div>
265
                <div class="metadata-pair-template" style="display:none;">
266
                    <div class="metadata-key">{% trans "OS" %}</div>
267
                    <div class="vertical-separator"></div>
268
                    <div class="metadata-value">{% trans "Debian" %}</div>
269
                    <div class="metadata-full-value" style="display:none;"></div>
270
                    <div class="metadata-edit">
271
                        <div class="edit"></div>
272
                        <div class="remove"></div>
273
                    </div>
274
                    <div class="editbuttons" style="display:none;">
275
                        <div class="save"></div>
276
                        <div class="remove"></div>
277
                    </div>
278
                </div>
279
            </div>
280
        </div>
281
        <div class="buttons">
282
            <button type="button" class="save" id="metadata-cancel">{% trans "Close" %}</button>
283
            <button type="button" class="create" id="metadata-create">{% trans "Create New" %}</button>
284
        </div>
285
    </div>
286
</div>
287

    
288
<a id="metadata-scrollable" href="#" rel="#metadata-wizard"></a>
289

    
290
<div id="machinesview"></div>
291

    
292
<div class="confirm_multiple">
293
    <p>{% trans "Your actions will affect" %} <span class="actionLen">XX</span> {% trans "machines" %}</p>
294
    <button class="yes">{% trans "Confirm All" %}</button>
295
    <button class="no">{% trans "Cancel All" %}</button>
296
</div>
297

    
298
<script>
299

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

308

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

325
//add hover to labels
326
$('#machines-pane span.typebody').mouseover(function() {
327
    $(this).addClass('typehover');
328
});
329
$('#machines-pane span.typebody').mouseout(function() {
330
    $(this).removeClass('typehover');
331
});
332

333
// switch to list view
334
$("#machines-pane a#list").click(function(){
335
    list_view();
336
    return false;
337
});
338

339
// switch to standard view
340
$("#machines-pane a#standard").click(function(){
341
    standard_view();
342
    return false;
343
});
344

345
// switch to single view
346
$("#machines-pane a#single").click(function(){
347
    single_view();
348
    return false;
349
});
350

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

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

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

430
        // remove focus from create button
431
        $("#create").blur();
432
    });
433
    // if tab is pressed on the next button seek to next page
434
    $(root).live('keydown', function (e) {
435
       if ( e.keyCode == 9 || e.keyCode == 13){
436
           if(e.preventDefault) {
437
               e.preventDefault();
438
           }
439
           api.next();
440
        }
441
    });
442
    //submit wizard by pressing enter on the name textbox
443
    $("#name").keypress(function (e) {
444
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
445
            $('#start').click();
446
            return false;
447
        } else {
448
            return true;
449
        }
450
    });
451
});
452

453
// disable sliders in flavor selection
454
function disableSliders() {
455
    $("#cpu").attr('disabled',true);
456
    $("#ram").attr('disabled',true);
457
    $("#storage").attr('disabled',true);
458
}
459

460
//update radio button when clicking on text
461
$("#small-body").live('click' ,function() {
462
    $(this).parent().find("#small").click();
463
});
464

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

469
$("#large-body").live('click' ,function() {
470
    $(this).parent().find("#large").click();
471
});
472

473
$("#custom-body").live('click' ,function() {
474
    $(this).parent().find("#custom").click();
475
});
476

477
//select image div on radio button select
478
$('#machines-pane .radio').live('click' ,function() {
479
    $(this).parents("div").find(".image").removeClass('selecteddiv');
480
    if($(this).is(':checked'))  {
481
        $(this).parent().addClass('selecteddiv');
482
    }
483
});
484

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

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

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

539
// selecting the small size
540
$("#small").click(function(){
541
    $("#cpu").data('rangeinput').setValue(0);
542
    $("#ram").data('rangeinput').setValue(0);
543
    $("#storage").data('rangeinput').setValue(0);
544
    $("#cpu-indicator")[0].value = cpus[0];
545
    $("#ram-indicator")[0].value = ram[0];
546
    $("#storage-indicator")[0].value = disks[0];
547
    $("#small").addClass("active");
548
    $("#medium").removeClass("active");
549
    $("#large").removeClass("active");
550
    $("#custom").removeClass("active");
551
});
552

553
// selecting the medium size
554
$("#medium").click(function(){
555
    $("#cpu").data('rangeinput').setValue(1);
556
    $("#ram").data('rangeinput').setValue(1);
557
    $("#storage").data('rangeinput').setValue(1);
558
    $("#cpu-indicator")[0].value = cpus[1];
559
    $("#ram-indicator")[0].value = ram[1];
560
    $("#storage-indicator")[0].value = disks[1];
561
    $("#medium").addClass("active");
562
    $("#small").removeClass("active");
563
    $("#large").removeClass("active");
564
    $("#custom").removeClass("active");
565
});
566

567
// selecting the large size
568
$("#large").click(function(){
569
    $("#cpu").data('rangeinput').setValue(2);
570
    $("#ram").data('rangeinput').setValue(2);
571
    $("#storage").data('rangeinput').setValue(2);
572
    $("#cpu-indicator")[0].value = cpus[2];
573
    $("#ram-indicator")[0].value = ram[2];
574
    $("#storage-indicator")[0].value = disks[2];
575
    $("#large").addClass("active");
576
    $("#medium").removeClass("active");
577
    $("#small").removeClass("active");
578
    $("#custom").removeClass("active");
579
});
580

581
// selecting the custom flavor enables the sliders
582
$("#custom").click(function(){
583
    $("#cpu").attr('disabled',false);
584
    $("#ram").attr('disabled',false);
585
    $("#storage").attr('disabled',false);
586
    $("strong.sliders").style = 'color: #778899;';
587
    $("#custom input").attr('checked', 'checked');
588
    $("#custom").addClass("active");
589
    $("#medium").removeClass("active");
590
    $("#large").removeClass("active");
591
    $("#small").removeClass("active");
592
});
593

594
//when textbox gains focus, add selection in css
595
$('#cpu-indicator').focus(function() {
596
    $(this).addClass('selectedrange');
597
});
598

599
$('#ram-indicator').focus(function() {
600
    $(this).addClass('selectedrange');
601
});
602

603
$('#storage-indicator').focus(function() {
604
    $(this).addClass('selectedrange');
605
});
606

607
//when textbox loses focus, clear selection in css
608
$('#cpu-indicator').blur(function() {
609
    $(this).removeClass('selectedrange');
610
});
611

612
$('#ram-indicator').blur(function() {
613
    $(this).removeClass('selectedrange');
614
});
615

616
$('#storage-indicator').blur(function() {
617
    $(this).removeClass('selectedrange');
618
});
619

620
// exit the wizard
621
$("#cancel").click(function() {
622
    $("#machines-pane a#create").overlay().close();
623
});
624

625
// starting a new VM through the wizard
626
$("#start").click(function() {
627
    var imageRef = $('input[type=radio][name=image-id]:checked')[0].id.replace('img-radio-','');
628
    var flavorRef = identify_flavor($("#cpu-indicator")[0].value, $("#storage-indicator")[0].value, $("#ram-indicator")[0].value);
629
    var machineName = $('input[name=machine_name]')[0].value;
630
    if (jQuery.trim(machineName) == ''){
631
        return false;
632
    }
633

634
    // replace text 'create new' with progress indicator
635
    $(this).text('');
636
    $(this).html('<img src="static/icons/indicators/medium/horizontal-progress.gif" / >');
637
    // disable submit button to prevent multiple calls
638
    $(this).attr("disabled", true);
639

640
    create_vm(machineName, imageRef, flavorRef);
641

642
    try {
643
        console.warn('creating ' + $("input[name=machine_name]")[0].value);
644
    } catch(err){}
645

646
});
647

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

668
// bring up metadata overlay
669
function show_metadata_wizard() {
670
    // get metadata for current server and fill the dialog
671
    serverID = $("#metadata-wizard p:first").text();
672
    get_metadata(serverID);
673
    $("#metadata-wizard").show();
674
    $("a#metadata-scrollable").data('overlay').load();
675
    $('#metadata-wizard .large-spinner').show();
676
    return false;
677
}
678

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

709
// exit the metadata wizard
710
$("#metadata-cancel").click(function(){
711
    $("a#metadata-scrollable").overlay().close();
712
});
713

714
//intercept create new metadata click
715
$("#metadata-wizard #metadata-create").click(function(){
716
    pair = $("#metadata-wizard div.metadata-add-template:first").clone();
717
    pair.prependTo("#metadata-wizard div.metadata-container").fadeIn();
718
      with (pair.find('input#add-meta-key')) {
719
        with (pair.find('ul:first')) {
720
          find('li').click(function() {
721
            $(this).parent().parent().find('.textdropdown-outer').find('input:first').attr('value', $(this).find('.dropdownitem').html());
722
            $(this).parent().hide();
723
          });
724
          hide();
725
        }
726

727
        keypress(function() {
728
          $(this).parent().next('ul:first').hide();
729
        });
730

731
        change(function() {
732
          $(this).parent().next('ul:first').hide();
733
        });
734

735
        wrap('<div class="textdropdown-outer" style="width: ' + width() + 'px; height: ' + (height() + 5) + 'px"></div>');
736
        var btn = parent().prepend('<div class="textdropdown-btn">&nbsp;</div>').find('.textdropdown-btn');
737
        width(width() - btn.width() - 5);
738
        css("border", "0");
739

740
        btn.click(function() {
741
          var p = $(this).parent();
742
          with (p.next('ul:first')) {
743
            $(this).parent().parent().find('ul:first').css('position', 'absolute');
744
            $(this).parent().parent().find('ul:first').css('width',    p.width());
745
            $(this).parent().parent().find('ul:first').css('left',     p.position().left + 4);
746
            $(this).parent().parent().find('ul:first').css('top',      p.position().top + p.height() + 1);
747
            var elem = $(this).parent().parent().find('ul:first')[0];
748
            if(elem.style.display == 'none') {
749
                 $(this).parent().parent().find('ul:first').show();
750
            } else {
751
                 $(this).parent().parent().find('ul:first').hide();
752
            }
753

754
          }
755
        });
756
      }
757
    pair.find('input#add-meta-key').focus();
758
    //submit keyword by pressing enter on the textbox
759
    $(this).parent().parent().find('input#add-meta-value').keypress(function (e) {
760
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
761
            $(this).parent().parent().find('.addbuttons .save').click();
762
            return false;
763
        } else {
764
            return true;
765
        }
766
    });
767
});
768

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

798
//intercept cancel new metadata creation
799
$("#metadata-wizard .addbuttons .cancel").die('click');
800
$("#metadata-wizard .addbuttons .cancel").live('click',function(){
801
    $(this).parent().parent().fadeOut('fast', function() { $(this).remove(); });
802
});
803

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

818
//metadata edit button
819
$("#metadata-wizard .metadata-edit .edit").die('click');
820
$("#metadata-wizard .metadata-edit .edit").live('click', function() {
821
    $(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() +
822
                                    "\" / ><span class=\"oldValue\">" +
823
                                    $(this).parent().parent().find('.metadata-full-value').text() + "</span>");
824
    //submit keyword by pressing enter on the textbox
825
    $(this).parent().parent().find('input.metatextbox').keypress(function (e) {
826
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
827
            $(this).parent().parent().find('.editbuttons .save').click();
828
            return false;
829
        } else {
830
            return true;
831
        }
832
    });
833
    $(this).parent().parent().find('input.metatextbox').select()
834
    $(this).parent().hide();
835
    $(this).parent().parent().unbind('mouseenter').unbind('mouseleave');
836
    $(this).parent().parent().find('.editbuttons').show();
837
});
838

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

860
//metadata cancel edit button
861
$("#metadata-wizard .editbuttons .remove").die('click');
862
$("#metadata-wizard .editbuttons .remove").live('click', function() {
863
    var oldValue = $(this).parent().parent().find('.oldValue').text();
864
    if (oldValue.length > 25) {
865
        oldValue = oldValue.substring(0,25) + "...";
866
    }
867
    $(this).parent().parent().find('div.metadata-value').html(oldValue);
868
    $(this).parent().parent().hover(function () {$(this).find('.metadata-edit').show();}, function () {$(this).find('.metadata-edit').hide();});
869
    $(this).parent().hide();
870
});
871

872

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

892
});
893

894
// intercept create metadata key focus
895
$("#metadata-wizard input#add-meta-key").live('focusin', function() {
896
    if ($(this).parent().hasClass("div-enabled")) {
897
    } else {
898
        $(this).parent().addClass("div-enabled");
899
        $(this).addClass("input-enabled");
900
        if (this.value == '{% trans 'max 15 characters' %}') {
901
            this.value = '';
902
        }
903
    }
904
    return false;
905
});
906

907
// intercept create metadata key focus out
908
$("#metadata-wizard input#add-meta-key").live('focusout', function() {
909
    $(this).parent().removeClass("div-enabled");
910
    if (this.value == "") {
911
        $(this).removeClass("input-enabled");
912
        this.value = '{% trans 'max 15 characters' %}';
913
    }
914
    return false;
915
});
916

917

918
// intercept metadata dropdown item click
919
$(".metadata-add-template li").live('click', function() {
920
    $(this).parent().parent().parent().find("input#add-meta-value").focus();
921
    $(this).parent().parent().parent().find("input#add-meta-key").addClass("input-enabled");
922
});
923

924
// intercept create metadata key focus
925
$("#metadata-wizard input#add-meta-value").live('focusin', function() {
926
    if ($(this).hasClass("input-enabled")) {
927
    } else {
928
        $(this).addClass("input-enabled");
929
        this.value = '';
930
    }
931
    return false;
932
});
933

934
// intercept create metadata key focus out
935
$("#metadata-wizard input#add-meta-value").live('focusout', function() {
936
    if (this.value == "") {
937
        $(this).removeClass("input-enabled");
938
        this.value = '{% trans 'max 150 characters' %}';
939
    }
940
    return false;
941
});
942

943
// intercept click on cancel button in metadata add dialog
944
$('#add-dialog button.cancel').live('click', function() {
945

946
});
947

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

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

1016
// cancel all actions
1017
$("#machines-pane div.confirm_multiple button.no").live('click', function(){
1018
    pending_actions = [];
1019
    $('#machines-pane .machine .selected').removeClass('selected');
1020
    $('#machinesview-list .actions .selected').removeClass('selected');
1021
    $('#machines-pane .machine .display').removeClass('display');
1022

1023
    update_confirmations();
1024
    return false;
1025
});
1026

1027
// basic functions executed on page load
1028
if (images.length > 0) {
1029
    // populate image list
1030
    update_wizard_images();
1031
}
1032
if (flavors.length > 0) {
1033
    // configure flavors
1034
    update_wizard_flavors();
1035
}
1036
// create tabs for main menu
1037
$("ul.tabs").tabs("div.panes ul");
1038

1039
//fix ie z-index bug by moving the overlays to the bottom
1040
$(document).ready(function() {
1041
    if ($.browser.msie) {
1042
        $("body").append($("#wizard"));
1043
        $("body").append($("#metadata-wizard"));
1044
    }
1045
});
1046

1047
//IE specific fixes
1048
if ($.browser.msie) {
1049
    //IE fix for dropdown li hover
1050
    $("#metadata-wizard ul li").live("mouseenter", function () {
1051
        $(this).css("background-color","#efefef");
1052
        $(this).css("cursor","pointer");
1053
    });
1054
    $("#metadata-wizard ul li").live("mouseleave", function () {
1055
        $(this).css("background-color","transparent");
1056
        $(this).css("cursor","default");
1057
    });
1058
    //IE fix for metadata wizard hover
1059
    $("#metadata-wizard div.metadata-pair-template").live("mouseenter", function () {
1060
        $(this).css("background-color","#74aec9");
1061
    });
1062
    $("#metadata-wizard ul li").live("mouseleave", function () {
1063
        $(this).css("background-color","transparent");
1064
    });
1065
}
1066

    
1067
</script>