Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_create_view.js @ 35584d80

History | View | Annotate | Download (33.4 kB)

1
;(function(root){
2

    
3
    // root
4
    var root = root;
5
    
6
    // setup namepsaces
7
    var snf = root.synnefo = root.synnefo || {};
8
    var models = snf.models = snf.models || {}
9
    var storage = snf.storage = snf.storage || {};
10
    var ui = snf.ui = snf.ui || {};
11
    var util = snf.util = snf.util || {};
12

    
13
    var views = snf.views = snf.views || {}
14

    
15
    // shortcuts
16
    var bb = root.Backbone;
17

    
18

    
19
    views.VMCreationPasswordView = views.Overlay.extend({
20
        view_id: "creation_password_view",
21
        content_selector: "#creation-password-overlay",
22
        css_class: 'overlay-password overlay-info',
23
        overlay_id: "creation-password-overlay",
24

    
25
        subtitle: "",
26
        title: "Machine password",
27

    
28
        initialize: function(options) {
29
            views.FeedbackView.__super__.initialize.apply(this, arguments);
30
            _.bindAll(this, 'show_password');
31

    
32
            this.password = this.$("#new-machine-password");
33
            this.copy = this.$(".clipboard");
34

    
35
            this.$(".show-machine").click(_.bind(function(){
36
                if (this.$(".show-machine").hasClass("in-progress")) {
37
                    return;
38
                }
39
                this.hide();
40
                snf.ui.main.show_vm_details(storage.vms.get(this.vm_id));
41
            }, this));
42

    
43
            _.bindAll(this, "handle_vm_added");
44
            storage.vms.bind("add", this.handle_vm_added);
45
            this.password.text("");
46
        },
47

    
48
        handle_vm_added: function() {
49
            this.$(".show-machine").removeClass("in-progress");
50
        },
51
        
52
        show_password: function() {
53
            this.$(".show-machine").addClass("in-progress");
54
            this.password.text(this.pass);
55
            if (storage.vms.get(this.vm_id)) {
56
                this.$(".show-machine").removeClass("in-progress");
57
            }
58
            
59
            this.clip = new snf.util.ClipHelper(this.copy, this.pass);
60
        },
61

    
62
        onClose: function() {
63
            this.password.text("");
64
            this.vm_id = undefined;
65
            try { delete this.clip; } catch (err) {};
66
        },
67
        
68
        beforeOpen: function() {
69
            this.copy.empty();
70
        },
71
        
72
        onOpen: function() {
73
            this.show_password();
74
        },
75

    
76
        show: function(pass, vm_id) {
77
            this.pass = pass;
78
            this.vm_id = vm_id;
79
            
80
            views.VMCreationPasswordView.__super__.show.apply(this, arguments);
81
        }
82
    })
83

    
84

    
85
    
86
    views.CreateVMStepView = views.View.extend({
87
        step: "1",
88
        title: "Image",
89
        submit: false,
90

    
91
        initialize: function(view) {
92
            this.parent = view;
93
            this.el = view.$("div.create-step-cont.step-" + this.step);
94
            this.header = this.$(".step-header .step-" + this.step);
95
            this.view_id = "create_step_" + this.step;
96

    
97
            views.CreateVMStepView.__super__.initialize.apply(this);
98
        },
99

    
100
        show: function() {
101
            // show current
102
            this.el.show();
103
            this.header.addClass("current");
104
            this.header.show();
105
            this.update_layout();
106
        },
107

    
108
        reset: function() {
109
        }
110
    })
111

    
112
    views.CreateImageSelectView = views.CreateVMStepView.extend({
113

    
114
        initialize: function() {
115
            views.CreateImageSelectView.__super__.initialize.apply(this, arguments);
116

    
117
            // elements
118
            this.images_list_cont = this.$(".images-list-cont");
119
            this.images_list = this.$(".images-list-cont ul");
120
            this.image_details = this.$(".images-info-cont");
121
            this.image_details_desc = this.$(".images-info-cont .description p");
122
            this.image_details_title = this.$(".images-info-cont h4");
123
            this.image_details_size = this.$(".images-info-cont .size p");
124
            this.image_details_os = this.$(".images-info-cont .os p");
125
            this.image_details_kernel = this.$(".images-info-cont .kernel p");
126
            this.image_details_gui = this.$(".images-info-cont .gui p");
127

    
128
            this.types = this.$(".type-filter li");
129
            this.categories_list = this.$(".category-filters");
130

    
131
            // params initialization
132
            this.type_selections = ["system", "custom"]
133
            this.selected_type = "system";
134
            this.selected_categories = [];
135
            this.images = [];
136

    
137
            // update
138
            this.update_images();
139

    
140
            // handlers initialization
141
            this.init_handlers();
142
            this.init_position();
143
        },
144

    
145
        init_position: function() {
146
            //this.el.css({position: "absolute"});
147
            //this.el.css({top:"10px"})
148
        },
149
        
150
        init_handlers: function() {
151
            var self = this;
152
            this.types.live("click", function() {
153
                self.select_type($(this).attr("id").replace("type-select-",""));
154
            })
155
        },
156

    
157
        update_images: function() {
158
            this.images = storage.images.active();
159
            this.images_ids = _.map(this.images, function(img){return img.id});
160
            if (this.selected_type == "custom") { this.images = []; this.images_ids = []; }
161

    
162
            return this.images;
163
        },
164

    
165
        update_layout: function() {
166
            this.select_type(this.selected_type);
167
        },
168
        
169
        get_categories: function(images) {
170
            return [];
171
            return ["Desktop", "Server", "Linux", "Windows"];
172
        },
173

    
174
        reset_categories: function() {
175
            var categories = this.get_categories(this.images);
176
            this.categories_list.find("li").remove();
177

    
178
            _.each(categories, _.bind(function(cat) {
179
                var el = $("<li />");
180
                el.text(cat);
181
                this.categories_list.append(el);
182
            }, this));
183

    
184
            if (!categories.length) { 
185
                this.categories_list.parent().find(".clear").hide();
186
                this.categories_list.parent().find(".empty").show();
187
            } else {
188
                this.categories_list.parent().find(".clear").show();
189
                this.categories_list.parent().find(".empty").hide();
190
            }
191
        },
192
        
193
        select_type: function(type) {
194
            this.selected_type = type;
195
            this.types.removeClass("selected");
196
            this.types.filter("#type-select-" + this.selected_type).addClass("selected");
197

    
198
            this.reset_categories();
199
            this.update_images();
200
            this.reset_images();
201
            this.select_image();
202
        },
203

    
204
        select_image: function(image) {
205
            if (!image && this.images_ids.length) {
206
                if (this.selected_image && this.images_ids.indexOf(this.selected_image.id) > -1) {
207
                    image = this.selected_image;
208
                } else {
209
                    image = storage.images.get(this.images_ids[0]);
210
                }
211
            }
212

    
213
            if (!this.images_ids.length) { image = this.selected_image || undefined };
214
            
215
            this.selected_image = image;
216
            this.trigger("change", image);
217
            
218
            if (image) {
219
                this.image_details.show();
220
                this.images_list.find(".image-details").removeClass("selected");
221
                this.images_list.find(".image-details#create-vm-image-" + this.selected_image.id).addClass("selected");
222
                
223
                this.image_details_desc.text(image.get("description"));
224
                
225
                var img = snf.ui.helpers.os_icon_tag(image.get("OS"))
226
                this.image_details_title.html(img + image.get("name"));
227
                this.image_details_os.text(_(image.get("OS")).capitalize());
228
                this.image_details_kernel.text(image.get("kernel"));
229

    
230
                var size = image.get_readable_size();
231

    
232
                this.image_details_size.text(size);
233
                this.image_details_gui.text(image.get("GUI"));
234

    
235
            } else {
236
                this.image_details.hide();
237
            }
238

    
239
            this.validate();
240
        },
241

    
242
        reset_images: function() {
243
            this.images_list.find("li").remove();
244
            _.each(this.images, _.bind(function(img){
245
                this.add_image(img);
246
            }, this))
247
            
248
            if (this.images.length) {
249
                this.images_list.parent().find(".empty").hide();
250
            } else {
251
                this.images_list.parent().find(".empty").show();
252
            }
253

    
254
            this.select_image();
255
            
256
            var self = this;
257
            this.images_list.find(".image-details").click(function(){
258
                self.select_image($(this).data("image"));
259
            });
260
            
261
        },
262

    
263
        show: function() {
264
            views.CreateImageSelectView.__super__.show.apply(this, arguments);
265
        },
266

    
267
        add_image: function(img) {
268
            var image = $(('<li id="create-vm-image-{1}"' +
269
                           'class="image-details clearfix">{2}{0}' +
270
                           '<p>{4}</p><span class="size">{3}' +
271
                           '</span></li>').format(img.get("name"), 
272
                                                  img.id, 
273
                                                  snf.ui.helpers.os_icon_tag(img.get("OS")),
274
                                                  img.get_readable_size(),
275
                                                  util.truncate(img.get("description"),35)));
276
            image.data("image", img);
277
            image.data("image_id", img.id);
278
            this.images_list.append(image);
279
        },
280

    
281
        reset: function() {
282
            this.selected_image = undefined;
283
            this.reset_images();
284
        },
285

    
286
        get: function() {
287
            return {'image': this.selected_image};
288
        },
289

    
290
        validate: function() {
291
            if (!this.selected_image) {
292
                this.parent.$(".form-action.next").hide();
293
            } else {
294
                this.parent.$(".form-action.next").show();
295
            }
296
        }
297
    });
298

    
299
    views.CreateFlavorSelectView = views.CreateVMStepView.extend({
300
        step: 2,
301
        initialize: function() {
302
            views.CreateFlavorSelectView.__super__.initialize.apply(this, arguments);
303
            this.parent.bind("image:change", _.bind(this.handle_image_change, this));
304

    
305
            this.cpus = this.$(".flavors-cpu-list");
306
            this.disks = this.$(".flavors-disk-list");
307
            this.mems = this.$(".flavors-mem-list");
308

    
309
            this.predefined_flavors = SUGGESTED_FLAVORS;
310
            this.predefined_flavors_keys = _.keys(SUGGESTED_FLAVORS);
311
            this.predefined_flavors_keys = _.sortBy(this.predefined_flavors_keys, _.bind(function(k){
312
                var flv = this.predefined_flavors[k];
313
                return flv.ram * flv.cpu * flv.disk;
314
            }, this));
315

    
316
            this.predefined = this.$(".predefined-list");
317
            this.update_predefined_flavors();
318
        },
319

    
320
        handle_image_change: function(data) {
321
            this.current_image = data;
322
            this.update_valid_predefined();
323
            this.update_flavors_data();
324
            this.reset_flavors();
325
            this.update_layout();
326
        },
327

    
328
        validate_selected_flavor: function() {
329
            if (!this.flavor_is_valid(this.current_flavor)) {
330
                this.select_valid_flavor();
331
            }
332
        },
333

    
334
        reset_flavors: function() {
335
            this.$(".flavor-opts-list .option").remove();
336
            this.create_flavors();
337
        },
338

    
339
        update_predefined_flavors: function() {
340
            this.predefined.find("li").remove();
341
            _.each(this.predefined_flavors_keys, _.bind(function(key) {
342
                var val = this.predefined_flavors[key];
343
                var el = $(('<li class="predefined-selection" id="predefined-flavor-{0}">' +
344
                           '{1}</li>').format(key, _(key).capitalize()));
345

    
346
                this.predefined.append(el);
347
                el.data({flavor: storage.flavors.get_flavor(val.cpu, val.ram, val.disk, this.flavors)})
348
                el.click(_.bind(function() {
349
                    this.handle_predefined_click(el);
350
                }, this))
351
            }, this));
352
            this.update_valid_predefined();
353
        },
354

    
355
        handle_predefined_click: function(el) {
356
            if (el.hasClass("disabled")) { return };
357
            this.set_current(el.data("flavor"))
358
        },
359

    
360
        select_valid_flavor: function() {
361
            var found = false;
362
            var self = this;
363
            _.each(this.flavors, function(flv) {
364
                if (self.flavor_is_valid(flv)) {
365
                    found = flv;
366
                    return false;
367
                }
368
            });
369
            
370
            if (found) {
371
                this.set_current(found);
372
            } else {
373
                this.current_flavor = undefined;
374
                this.validate();
375
                this.$("li.predefined-selection").addClass("disabled");
376
                this.$(".flavor-opts-list li").removeClass("selected");
377
            }
378
        },
379

    
380
        update_valid_predefined: function() {
381
            this.update_unavailable_values();
382
            var self = this;
383
            this.valid_predefined = _.select(_.map(this.predefined_flavors, function(flv, key){
384
                var existing = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
385
                // non existing
386
                if (!existing) {
387
                    return false;
388
                }
389
                
390
                // not available for image
391
                if (self.unavailable_values && self.unavailable_values.disk.indexOf(existing.get_disk_size()) > -1) {
392
                    return false
393
                }
394

    
395
                return key;
396
            }), function(ret) { return ret });
397
            
398
            $("li.predefined-selection").addClass("disabled");
399
            _.each(this.valid_predefined, function(key) {
400
                $("#predefined-flavor-" + key).removeClass("disabled");
401
            })
402
        },
403

    
404
        update_selected_predefined: function() {
405
            var self = this;
406
            this.predefined.find("li").removeClass("selected");
407

    
408
            _.each(this.valid_predefined, function(key){
409
                var flv = self.predefined_flavors[key];
410
                var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
411

    
412
                if (exists && (exists.id == self.current_flavor.id)) {
413
                    $("#predefined-flavor-" + key).addClass("selected");
414
                }
415
            })
416
        },
417
        
418
        update_flavors_data: function() {
419
            this.flavors = storage.flavors.active();
420
            this.flavors_data = storage.flavors.get_data(this.flavors);
421
            
422
            var self = this;
423
            var set = false;
424
            
425
            // FIXME: validate current flavor
426
            
427
            if (!this.current_flavor) {
428
                _.each(this.valid_predefined, function(key) {
429
                    var flv = self.predefined_flavors[key];
430
                    var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
431
                    if (exists && !set) {
432
                        self.set_current(exists);
433
                        set = true;
434
                    }
435
                })
436
            }
437

    
438
            this.update_unavailable_values();
439
        },
440

    
441
        update_unavailable_values: function() {
442
            if (!this.current_image) { this.unavailable_values = {disk:[], ram:[], cpu:[]}; return };
443
            this.unavailable_values = storage.flavors.unavailable_values_for_image(this.current_image);
444
        },
445
        
446
        flavor_is_valid: function(flv) {
447
            if (!flv) { return false };
448

    
449
            var existing = storage.flavors.get_flavor(flv.get("cpu"), flv.get("ram"), flv.get("disk"), this.flavors);
450
            if (!existing) { return false };
451
            
452
            if (this.unavailable_values && (this.unavailable_values.disk.indexOf(parseInt(flv.get("disk")) * 1000) > -1)) {
453
                return false;
454
            }
455
            return true;
456
        },
457
            
458
        set_valid_current_for: function(t, val) {
459
            var found = this.flavors[0];
460
            _.each(this.flavors, function(flv) {
461
                if (flv.get(t) == val) {
462
                    found = flv;
463
                }
464
            });
465

    
466
            this.set_current(found);
467
            this.validate_selected_flavor();
468
        },
469

    
470
        set_current: function(flv) {
471

    
472
            if (!flv) {
473
                // user clicked on invalid combination
474
                // force the first available choice for the
475
                // type of option he last clicked
476
                this.set_valid_current_for.apply(this, this.last_choice);
477
                return;
478
            }
479

    
480
            this.current_flavor = flv;
481
            this.trigger("change");
482
            if (this.current_flavor) {
483
                this.update_selected_flavor();
484
                this.update_selected_predefined();
485
            }
486
            
487
            this.validate();
488
        },
489
        
490
        select_default_flavor: function() {
491
               
492
        },
493

    
494
        update_selected_from_ui: function() {
495
            this.set_current(this.ui_selected());
496
        },
497
        
498
        update_disabled_flavors: function() {
499
            this.$(".flavor-options.disk li").removeClass("disabled");
500
            if (!this.unavailable_values) { return }
501
            
502
            this.$("#create-vm-flavor-options .flavor-options.disk li").each(_.bind(function(i, el){
503
                var el_value = $(el).data("value") * 1000;
504
                if (this.unavailable_values.disk.indexOf(el_value) > -1) {
505
                    $(el).addClass("disabled");
506
                };
507
            }, this));
508
        },
509

    
510
        create_flavors: function() {
511
            var flavors = this.get_active_flavors();
512
            var valid_flavors = this.get_valid_flavors();
513
            this.__added_flavors = {'cpu':[], 'ram':[], 'disk':[]};
514

    
515
            _.each(flavors, _.bind(function(flv){
516
                this.add_flavor(flv);
517
            }, this));
518
            
519
            this.sort_flavors(this.disks);
520
            this.sort_flavors(this.cpus);
521
            this.sort_flavors(this.mems);
522

    
523
            var self = this;
524
            this.$(".flavor-options li.option").click(function(){
525
                var el = $(this);
526

    
527
                if (el.hasClass("disabled")) { return }
528

    
529
                el.parent().find(".option").removeClass("selected");
530
                el.addClass("selected");
531
                
532
                if (el.hasClass("mem")) { self.last_choice = ["ram", $(this).data("value")] }
533
                if (el.hasClass("cpu")) { self.last_choice = ["cpu", $(this).data("value")] }
534
                if (el.hasClass("disk")) { self.last_choice = ["disk", $(this).data("value")] }
535

    
536
                self.update_selected_from_ui();
537
            })
538
        },
539

    
540
        sort_flavors: function(els) {
541
            var prev = undefined;
542
            els.find("li").each(function(i,el){
543
                el = $(el);
544
                if (!prev) { prev = el; return true };
545
                if (el.data("value") < prev.data("value")) {
546
                    prev.before(el);
547
                }
548
                prev = el;
549
            })
550
        },
551
        
552
        ui_selected: function() {
553
            var args = [this.$(".option.cpu.selected").data("value"), 
554
                this.$(".option.mem.selected").data("value"), 
555
                this.$(".option.disk.selected").data("value"),
556
            this.flavors];
557

    
558
            var flv = storage.flavors.get_flavor.apply(storage.flavors, args);
559
            return flv;
560
        },
561

    
562
        update_selected_flavor: function() {
563
            var flv = this.current_flavor;
564
            if (!flv) { return }
565
            this.$(".option").removeClass("selected");
566

    
567
            this.$(".option.cpu.value-" + flv.get("cpu")).addClass("selected");
568
            this.$(".option.mem.value-" + flv.get("ram")).addClass("selected");
569
            this.$(".option.disk.value-" + flv.get("disk")).addClass("selected");
570
        },
571
        
572
        __added_flavors: {'cpu':[], 'ram':[], 'disk':[]},
573
        add_flavor: function(flv) {
574
            var values = {'cpu': flv.get('cpu'), 'mem': flv.get('ram'), 'disk': flv.get('disk')};
575

    
576
            disabled = "";
577
            
578
            if (this.__added_flavors.cpu.indexOf(values.cpu) == -1) {
579
                var cpu = $(('<li class="option cpu value-{0} {1}">' + 
580
                             '<span class="value">{0}</span>' + 
581
                             '<span class="metric">x</span></li>').format(values.cpu, disabled)).data('value', values.cpu);
582
                this.cpus.append(cpu);
583
                this.__added_flavors.cpu.push(values.cpu);
584
            }
585

    
586
            if (this.__added_flavors.ram.indexOf(values.mem) == -1) {
587
                var mem = $(('<li class="option mem value-{0}">' + 
588
                             '<span class="value">{0}</span>' + 
589
                             '<span class="metric">MB</span></li>').format(values.mem)).data('value', values.mem);
590
                this.mems.append(mem);
591
                this.__added_flavors.ram.push(values.mem);
592
            }
593

    
594
            if (this.__added_flavors.disk.indexOf(values.disk) == -1) {
595
                var disk = $(('<li class="option disk value-{0}">' + 
596
                              '<span class="value">{0}</span>' + 
597
                              '<span class="metric">GB</span></li>').format(values.disk)).data('value', values.disk);
598
                this.disks.append(disk);
599
                this.__added_flavors.disk.push(values.disk)
600
            }
601

    
602
            
603
        },
604
        
605
        get_active_flavors: function() {
606
            return storage.flavors.active();
607
        },
608

    
609
        get_valid_flavors: function() {
610
            return this.flavors;
611
        },
612

    
613
        update_layout: function() {
614
            this.update_selected_flavor();
615
            this.update_disabled_flavors();
616
            this.validate();
617
            this.validate_selected_flavor();
618
        },
619

    
620
        reset: function() {
621
            this.current_image = storage.images.at(0);
622
            this.flavors = [];
623
            this.flavors_data = {'cpu':[], 'mem':[], 'disk':[]};
624
            this.update_flavors_data();
625
        },
626

    
627
        validate: function() {
628
            if (!this.current_flavor) {
629
                this.parent.$(".form-action.next").hide();
630
            } else {
631
                this.parent.$(".form-action.next").show();
632
            }
633
        },
634

    
635
        get: function() {
636
            return {'flavor': this.current_flavor}
637
        }
638

    
639
    });
640

    
641
    views.CreateSubmitView = views.CreateVMStepView.extend({
642
        step: 3,
643
        initialize: function() {
644
            views.CreateSubmitView.__super__.initialize.apply(this, arguments);
645
            this.roles = this.$("li.predefined-meta.role .values");
646
            this.confirm = this.$(".confirm-params ul");
647
            this.name = this.$("input.rename-field");
648
            this.name_changed = false;
649
            this.init_suggested_roles();
650
            this.init_handlers();
651
        },
652

    
653
        init_suggested_roles: function() {
654
            var cont = this.roles;
655
            cont.empty();
656
            
657
            // TODO: get suggested from snf.api.conf
658
            _.each(window.SUGGESTED_ROLES, function(r){
659
                var el = $('<span class="val">{0}</span>'.format(r));
660
                el.data("value", r);
661
                cont.append(el);
662
                el.click(function() {
663
                    $(this).parent().find(".val").removeClass("selected");
664
                    $(this).toggleClass("selected");
665
                })
666
            })
667
        },
668

    
669
        init_handlers: function() {
670
            this.name.bind("keypress", _.bind(function(e) {
671
                this.name_changed = true;
672
                if (e.keyCode == 13) { this.parent.submit() };    
673
            }, this));
674

    
675
            this.name.bind("click", _.bind(function() {
676
                if (!this.name_changed) {
677
                    this.name.val("");
678
                }
679
            }, this))
680
        },
681

    
682
        show: function() {
683
            views.CreateSubmitView.__super__.show.apply(this, arguments);
684
            this.update_layout();
685
        },
686
        
687
        update_flavor_details: function() {
688
            var flavor = this.parent.get_params().flavor;
689

    
690
            function set_detail(sel, key) {
691
                var val = key;
692
                if (key == undefined) { val = flavor.get(sel) };
693
                this.$(".confirm-cont.flavor .flavor-" + sel + " .value").text(val)
694
            }
695
            
696
            set_detail("cpu", flavor.get("cpu") + "x");
697
            set_detail("ram", flavor.get("ram") + " MB");
698
            set_detail("disk", util.readablizeBytes(flavor.get("disk") * 1024 * 1024 * 1024));
699
        },
700

    
701
        update_image_details: function() {
702
            var image = this.parent.get_params().image;
703

    
704
            function set_detail(sel, key) {
705
                var val = key;
706
                if (key == undefined) { val = image.get(sel) };
707
                this.$(".confirm-cont.image .image-" + sel + " .value").text(val)
708
            }
709
            
710
            set_detail("description");
711
            set_detail("name");
712
            set_detail("os", _(image.get("OS")).capitalize());
713
            set_detail("gui", image.get("GUI"));
714
            set_detail("size", image.get_readable_size());
715
            set_detail("kernel");
716
        },
717

    
718
        update_layout: function() {
719
            var params = this.parent.get_params();
720
            if (!params.image || !params.flavor) { return }
721

    
722
            if (!params.image) { return }
723
            var vm_name = "My {0} server".format(params.image.get("name"));
724
            var orig_name = vm_name;
725
            
726
            var existing = true;
727
            var j = 0;
728

    
729
            while (existing && !this.name_changed) {
730
                var existing = storage.vms.select(function(vm){return vm.get("name") == vm_name}).length
731
                if (existing) {
732
                    j++;
733
                    vm_name = orig_name + " " + j;
734
                }
735
            }
736
            if (!_(this.name.val()).trim() || !this.name_changed) {
737
                this.name.val(vm_name);
738
            }
739

    
740
            this.confirm.find("li.image .value").text(params.flavor.get("image"));
741
            this.confirm.find("li.cpu .value").text(params.flavor.get("cpu") + "x");
742
            this.confirm.find("li.mem .value").text(params.flavor.get("ram"));
743
            this.confirm.find("li.disk .value").text(params.flavor.get("disk"));
744

    
745
            if (!this.name_changed && this.parent.visible()) {
746
                if (!$.browser.msie && !$.browser.opera) {
747
                    this.$("#create-vm-name").select();
748
                } else {
749
                    window.setTimeout(_.bind(function(){
750
                        this.$("#create-vm-name").select();
751
                    }, this), 400)
752
                }
753
            }
754
            
755
            var img = snf.ui.helpers.os_icon_path(params.image.get("OS"))
756
            this.name.css({backgroundImage:"url({0})".format(img)})
757

    
758
            this.update_image_details();
759
            this.update_flavor_details();
760
        },
761

    
762
        reset: function() {
763
            this.roles.find(".val").removeClass("selected");
764
            this.name_changed = false;
765
            this.update_layout();
766
        },
767

    
768
        get_meta: function() {
769
            if (this.roles.find(".selected").length == 0) {
770
                return false;
771
            }
772

    
773
            var role = $(this.roles.find(".selected").get(0)).data("value");
774
            return {'Role': role }
775
        },
776

    
777
        get: function() {
778
            var val = {'name': this.name.val() };
779
            if (this.get_meta()) {
780
                val.metadata = this.get_meta();
781
            }
782
            
783
            return val;
784
        }
785
    });
786

    
787
    views.CreateVMView = views.Overlay.extend({
788
        
789
        view_id: "create_vm_view",
790
        content_selector: "#createvm-overlay-content",
791
        css_class: 'overlay-createvm overlay-info',
792
        overlay_id: "metadata-overlay",
793

    
794
        subtitle: false,
795
        title: "Create new machine",
796

    
797
        initialize: function(options) {
798
            views.CreateVMView.__super__.initialize.apply(this);
799
            this.current_step = 1;
800

    
801
            this.password_view = new views.VMCreationPasswordView();
802

    
803
            this.steps = [];
804
            this.steps[1] = new views.CreateImageSelectView(this);
805
            this.steps[1].bind("change", _.bind(function(data) {this.trigger("image:change", data)}, this));
806

    
807
            this.steps[2] = new views.CreateFlavorSelectView(this);
808
            this.steps[3] = new views.CreateSubmitView(this);
809

    
810
            this.cancel_btn = this.$(".create-controls .cancel");
811
            this.next_btn = this.$(".create-controls .next");
812
            this.prev_btn = this.$(".create-controls .prev");
813
            this.submit_btn = this.$(".create-controls .submit");
814

    
815
            this.history = this.$(".steps-history");
816
            this.history_steps = this.$(".steps-history .steps-history-step");
817
            
818
            this.init_handlers();
819
        },
820

    
821
        init_handlers: function() {
822
            var self = this;
823
            this.next_btn.click(_.bind(function(){
824
                this.set_step(this.current_step + 1);
825
                this.update_layout();
826
            }, this))
827
            this.prev_btn.click(_.bind(function(){
828
                this.set_step(this.current_step - 1);
829
                this.update_layout();
830
            }, this))
831
            this.cancel_btn.click(_.bind(function(){
832
                this.close_all();
833
            }, this))
834
            this.submit_btn.click(_.bind(function(){
835
                this.submit();
836
            }, this))
837
            
838
            this.history.find(".completed").live("click", function() {
839
                var step = parseInt($(this).attr("id").replace("vm-create-step-history-", ""));
840
                self.set_step(step);
841
                self.update_layout();
842
            })
843
        },
844

    
845
        set_step: function(st) {
846
        },
847
        
848
        validate: function(data) {
849
            if (_(data.name).trim() == "") {
850
                this.$(".form-field").addClass("error");
851
                return false;
852
            } else {
853
                return true;
854
            }
855
        },
856

    
857
        submit: function() {
858
            if (this.submiting) { return };
859
            var data = this.get_params();
860
            var meta = {};
861
            if (this.validate(data)) {
862
                this.submit_btn.addClass("in-progress");
863
                this.submiting = true;
864
                if (data.metadata) { meta = data.metadata; }
865
                storage.vms.create(data.name, data.image, data.flavor, meta, {}, _.bind(function(data){
866
                    this.close_all();
867
                    this.password_view.show(data.server.adminPass, data.server.id);
868
                    this.submiting = false;
869
                }, this));
870
            }
871
        },
872

    
873
        close_all: function() {
874
            this.hide();
875
        },
876

    
877
        reset: function() {
878
            this.current_step = 1;
879

    
880
            this.steps[1].reset();
881
            this.steps[2].reset();
882
            this.steps[3].reset();
883

    
884
            this.steps[1].show();
885
            this.steps[2].show();
886
            this.steps[3].show();
887

    
888
            this.submit_btn.removeClass("in-progress");
889
        },
890

    
891
        onShow: function() {
892
            this.reset()
893
            this.update_layout();
894
        },
895

    
896
        update_layout: function() {
897
            this.show_step(this.current_step);
898
            this.current_view.update_layout();
899
        },
900

    
901
        beforeOpen: function() {
902
            this.submiting = false;
903
            this.reset();
904
            this.current_step = 1;
905
            this.$(".steps-container").css({"margin-left":0 + "px"});
906
            this.show_step(1);
907
        },
908
        
909
        set_step: function(step) {
910
            if (step <= 1) {
911
                step = 1
912
            }
913
            if (step > this.steps.length - 1) {
914
                step = this.steps.length - 1;
915
            }
916
            this.current_step = step;
917
        },
918

    
919
        show_step: function(step) {
920
            this.current_view = this.steps[step];
921
            this.update_controls();
922

    
923
            this.steps[step].show();
924
            var width = this.el.find('.container').width();
925
            var left = (step -1) * width * -1;
926
            this.$(".steps-container").animate({"margin-left": left + "px"}, 300);
927

    
928
            this.update_steps_history();
929
        },
930

    
931
        update_steps_history: function() {
932
            var self = this;
933
            function get_step(s) {
934
                return self.history.find(".step" + s + "h");
935
            }
936
            
937
            var current_step = parseInt(this.current_view.step);
938
            _.each(this.steps, function(stepv) {
939
                var step = parseInt(stepv.step);
940
                get_step(step).removeClass("completed").removeClass("current");
941
                if (step == current_step) {
942
                    get_step(step).removeClass("completed").addClass("current");
943
                }
944
                if (step < current_step) {
945
                    get_step(step).removeClass("current").addClass("completed");
946
                }
947
            });
948
        },
949

    
950
        update_controls: function() {
951
            var step = this.current_step;
952
            if (step == 1) {
953
                this.prev_btn.hide();
954
                this.cancel_btn.show();
955
            } else {
956
                this.prev_btn.show();
957
                this.cancel_btn.hide();
958
            }
959
            
960
            if (step == this.steps.length - 1) {
961
                this.next_btn.hide();
962
                this.submit_btn.show();
963
            } else {
964
                this.next_btn.show();
965
                this.submit_btn.hide();
966
            }
967
        },
968

    
969
        get_params: function() {
970
            return _.extend({}, this.steps[1].get(), this.steps[2].get(), this.steps[3].get());
971
        }
972
    });
973
    
974
})(this);
975