Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_create_view.js @ 5f26e13f

History | View | Annotate | Download (33.6 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.$(".clip-copy");
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
        },
46

    
47
        handle_vm_added: function() {
48
            this.$(".show-machine").removeClass("in-progress");
49
        },
50
        
51
        show_password: function() {
52
            this.$(".show-machine").addClass("in-progress");
53
            this.password.text(this.pass);
54
            if (storage.vms.get(this.vm_id)) {
55
                this.$(".show-machine").removeClass("in-progress");
56
            }
57
        },
58

    
59
        onClose: function() {
60
            this.password.text("");
61
            this.vm_id = undefined;
62
        },
63
        
64
        beforeOpen: function() {
65
            try { delete this.clipboard } catch (err) { console.log(err) };
66
            this.clipboard = new util.ClipHelper(this.copy);
67
        },
68
        
69
        onOpen: function() {
70
            this.copy.show();
71
            try {
72
                this.clipboard.setText(this.pass);
73
                this.copy.show();
74
            } catch (err) {
75
                this.copy.hide();
76
            }
77
        },
78

    
79
        show: function(pass, vm_id) {
80
            this.pass = pass;
81
            this.vm_id = vm_id;
82
            
83
            views.VMCreationPasswordView.__super__.show.apply(this, arguments);
84
            this.show_password();
85
        }
86
    })
87

    
88

    
89
    
90
    views.CreateVMStepView = views.View.extend({
91
        step: "1",
92
        title: "Image",
93
        submit: false,
94

    
95
        initialize: function(view) {
96
            this.parent = view;
97
            this.el = view.$("div.create-step-cont.step-" + this.step);
98
            this.header = this.$(".step-header .step-" + this.step);
99
            this.view_id = "create_step_" + this.step;
100

    
101
            views.CreateVMStepView.__super__.initialize.apply(this);
102
        },
103

    
104
        show: function() {
105
            // show current
106
            this.el.show();
107
            this.header.addClass("current");
108
            this.header.show();
109
            this.update_layout();
110
        },
111

    
112
        reset: function() {
113
        }
114
    })
115

    
116
    views.CreateImageSelectView = views.CreateVMStepView.extend({
117

    
118
        initialize: function() {
119
            views.CreateImageSelectView.__super__.initialize.apply(this, arguments);
120

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

    
132
            this.types = this.$(".type-filter li");
133
            this.categories_list = this.$(".category-filters");
134

    
135
            // params initialization
136
            this.type_selections = ["system", "custom"]
137
            this.selected_type = "system";
138
            this.selected_categories = [];
139
            this.images = [];
140

    
141
            // update
142
            this.update_images();
143

    
144
            // handlers initialization
145
            this.init_handlers();
146
            this.init_position();
147
        },
148

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

    
161
        update_images: function() {
162
            this.images = storage.images.active();
163
            this.images_ids = _.map(this.images, function(img){return img.id});
164
            if (this.selected_type == "custom") { this.images = []; this.images_ids = []; }
165

    
166
            return this.images;
167
        },
168

    
169
        update_layout: function() {
170
            this.select_type(this.selected_type);
171
        },
172
        
173
        get_categories: function(images) {
174
            return [];
175
            return ["Desktop", "Server", "Linux", "Windows"];
176
        },
177

    
178
        reset_categories: function() {
179
            var categories = this.get_categories(this.images);
180
            this.categories_list.find("li").remove();
181

    
182
            _.each(categories, _.bind(function(cat) {
183
                var el = $("<li />");
184
                el.text(cat);
185
                this.categories_list.append(el);
186
            }, this));
187

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

    
202
            this.reset_categories();
203
            this.update_images();
204
            this.reset_images();
205
            this.select_image();
206
        },
207

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

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

    
234
                var size = image.get_readable_size();
235

    
236
                this.image_details_size.text(size);
237
                this.image_details_gui.text(image.get("GUI"));
238

    
239
            } else {
240
                this.image_details.hide();
241
            }
242

    
243
            this.validate();
244
        },
245

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

    
258
            this.select_image();
259
            
260
            var self = this;
261
            this.images_list.find(".image-details").click(function(){
262
                self.select_image($(this).data("image"));
263
            });
264
            
265
        },
266

    
267
        show: function() {
268
            views.CreateImageSelectView.__super__.show.apply(this, arguments);
269
        },
270

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

    
285
        reset: function() {
286
            this.selected_image = undefined;
287
            this.reset_images();
288
        },
289

    
290
        get: function() {
291
            return {'image': this.selected_image};
292
        },
293

    
294
        validate: function() {
295
            if (!this.selected_image) {
296
                this.parent.$(".form-action.next").hide();
297
            } else {
298
                this.parent.$(".form-action.next").show();
299
            }
300
        }
301
    });
302

    
303
    views.CreateFlavorSelectView = views.CreateVMStepView.extend({
304
        step: 2,
305
        initialize: function() {
306
            views.CreateFlavorSelectView.__super__.initialize.apply(this, arguments);
307
            this.parent.bind("image:change", _.bind(this.handle_image_change, this));
308

    
309
            this.cpus = this.$(".flavors-cpu-list");
310
            this.disks = this.$(".flavors-disk-list");
311
            this.mems = this.$(".flavors-mem-list");
312

    
313
            this.predefined_flavors = SUGGESTED_FLAVORS;
314
            this.predefined_flavors_keys = _.keys(SUGGESTED_FLAVORS);
315
            this.predefined_flavors_keys = _.sortBy(this.predefined_flavors_keys, _.bind(function(k){
316
                var flv = this.predefined_flavors[k];
317
                return flv.ram * flv.cpu * flv.disk;
318
            }, this));
319

    
320
            this.predefined = this.$(".predefined-list");
321
            this.update_predefined_flavors();
322
        },
323

    
324
        handle_image_change: function(data) {
325
            this.current_image = data;
326
            this.update_valid_predefined();
327
            this.update_flavors_data();
328
            this.reset_flavors();
329
            this.update_layout();
330
        },
331

    
332
        validate_selected_flavor: function() {
333
            if (!this.flavor_is_valid(this.current_flavor)) {
334
                this.select_valid_flavor();
335
            }
336
        },
337

    
338
        reset_flavors: function() {
339
            this.$(".flavor-opts-list .option").remove();
340
            this.create_flavors();
341
        },
342

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

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

    
359
        handle_predefined_click: function(el) {
360
            if (el.hasClass("disabled")) { return };
361
            this.set_current(el.data("flavor"))
362
        },
363

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

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

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

    
408
        update_selected_predefined: function() {
409
            var self = this;
410
            this.predefined.find("li").removeClass("selected");
411

    
412
            _.each(this.valid_predefined, function(key){
413
                var flv = self.predefined_flavors[key];
414
                var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
415

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

    
442
            this.update_unavailable_values();
443
        },
444

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

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

    
470
            this.set_current(found);
471
            this.validate_selected_flavor();
472
        },
473

    
474
        set_current: function(flv) {
475

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

    
484
            this.current_flavor = flv;
485
            this.trigger("change");
486
            if (this.current_flavor) {
487
                this.update_selected_flavor();
488
                this.update_selected_predefined();
489
            }
490
            
491
            this.validate();
492
        },
493
        
494
        select_default_flavor: function() {
495
               
496
        },
497

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

    
514
        create_flavors: function() {
515
            var flavors = this.get_active_flavors();
516
            var valid_flavors = this.get_valid_flavors();
517
            this.__added_flavors = {'cpu':[], 'ram':[], 'disk':[]};
518

    
519
            _.each(flavors, _.bind(function(flv){
520
                this.add_flavor(flv);
521
            }, this));
522
            
523
            this.sort_flavors(this.disks);
524
            this.sort_flavors(this.cpus);
525
            this.sort_flavors(this.mems);
526

    
527
            var self = this;
528
            this.$(".flavor-options li.option").click(function(){
529
                var el = $(this);
530

    
531
                if (el.hasClass("disabled")) { return }
532

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

    
540
                self.update_selected_from_ui();
541
            })
542
        },
543

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

    
562
            var flv = storage.flavors.get_flavor.apply(storage.flavors, args);
563
            return flv;
564
        },
565

    
566
        update_selected_flavor: function() {
567
            var flv = this.current_flavor;
568
            if (!flv) { return }
569
            this.$(".option").removeClass("selected");
570

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

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

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

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

    
606
            
607
        },
608
        
609
        get_active_flavors: function() {
610
            return storage.flavors.active();
611
        },
612

    
613
        get_valid_flavors: function() {
614
            return this.flavors;
615
        },
616

    
617
        update_layout: function() {
618
            this.update_selected_flavor();
619
            this.update_disabled_flavors();
620
            this.validate();
621
            this.validate_selected_flavor();
622
        },
623

    
624
        reset: function() {
625
            this.current_image = storage.images.at(0);
626
            this.flavors = [];
627
            this.flavors_data = {'cpu':[], 'mem':[], 'disk':[]};
628
            this.update_flavors_data();
629
        },
630

    
631
        validate: function() {
632
            if (!this.current_flavor) {
633
                this.parent.$(".form-action.next").hide();
634
            } else {
635
                this.parent.$(".form-action.next").show();
636
            }
637
        },
638

    
639
        get: function() {
640
            return {'flavor': this.current_flavor}
641
        }
642

    
643
    });
644

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

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

    
673
        init_handlers: function() {
674
            this.name.bind("keypress", _.bind(function(e) {
675
                this.name_changed = true;
676
                if (e.keyCode == 13) { this.parent.submit() };    
677
            }, this));
678

    
679
            this.name.bind("click", _.bind(function() {
680
                if (!this.name_changed) {
681
                    this.name.val("");
682
                }
683
            }, this))
684
        },
685

    
686
        show: function() {
687
            views.CreateSubmitView.__super__.show.apply(this, arguments);
688
            this.update_layout();
689
        },
690
        
691
        update_flavor_details: function() {
692
            var flavor = this.parent.get_params().flavor;
693

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

    
705
        update_image_details: function() {
706
            var image = this.parent.get_params().image;
707

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

    
722
        update_layout: function() {
723
            var params = this.parent.get_params();
724
            if (!params.image || !params.flavor) { return }
725

    
726
            if (!params.image) { return }
727
            var vm_name = "My {0} server".format(params.image.get("name"));
728
            var orig_name = vm_name;
729
            
730
            var existing = true;
731
            var j = 0;
732

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

    
744
            this.confirm.find("li.image .value").text(params.flavor.get("image"));
745
            this.confirm.find("li.cpu .value").text(params.flavor.get("cpu") + "x");
746
            this.confirm.find("li.mem .value").text(params.flavor.get("ram"));
747
            this.confirm.find("li.disk .value").text(params.flavor.get("disk"));
748

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

    
762
            this.update_image_details();
763
            this.update_flavor_details();
764
        },
765

    
766
        reset: function() {
767
            this.roles.find(".val").removeClass("selected");
768
            this.name_changed = false;
769
            this.update_layout();
770
        },
771

    
772
        get_meta: function() {
773
            if (this.roles.find(".selected").length == 0) {
774
                return false;
775
            }
776

    
777
            var role = $(this.roles.find(".selected").get(0)).data("value");
778
            return {'Role': role }
779
        },
780

    
781
        get: function() {
782
            var val = {'name': this.name.val() };
783
            if (this.get_meta()) {
784
                val.metadata = this.get_meta();
785
            }
786
            
787
            return val;
788
        }
789
    });
790

    
791
    views.CreateVMView = views.Overlay.extend({
792
        
793
        view_id: "create_vm_view",
794
        content_selector: "#createvm-overlay-content",
795
        css_class: 'overlay-createvm overlay-info',
796
        overlay_id: "metadata-overlay",
797

    
798
        subtitle: false,
799
        title: "Create new machine",
800

    
801
        initialize: function(options) {
802
            views.CreateVMView.__super__.initialize.apply(this);
803
            this.current_step = 1;
804

    
805
            this.password_view = new views.VMCreationPasswordView();
806

    
807
            this.steps = [];
808
            this.steps[1] = new views.CreateImageSelectView(this);
809
            this.steps[1].bind("change", _.bind(function(data) {this.trigger("image:change", data)}, this));
810

    
811
            this.steps[2] = new views.CreateFlavorSelectView(this);
812
            this.steps[3] = new views.CreateSubmitView(this);
813

    
814
            this.cancel_btn = this.$(".create-controls .cancel");
815
            this.next_btn = this.$(".create-controls .next");
816
            this.prev_btn = this.$(".create-controls .prev");
817
            this.submit_btn = this.$(".create-controls .submit");
818

    
819
            this.history = this.$(".steps-history");
820
            this.history_steps = this.$(".steps-history .steps-history-step");
821
            
822
            this.init_handlers();
823
        },
824

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

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

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

    
877
        close_all: function() {
878
            this.hide();
879
        },
880

    
881
        reset: function() {
882
            this.current_step = 1;
883

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

    
888
            this.steps[1].show();
889
            this.steps[2].show();
890
            this.steps[3].show();
891

    
892
            this.submit_btn.removeClass("in-progress");
893
        },
894

    
895
        onShow: function() {
896
            this.reset()
897
            this.update_layout();
898
        },
899

    
900
        update_layout: function() {
901
            this.show_step(this.current_step);
902
            this.current_view.update_layout();
903
        },
904

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

    
923
        show_step: function(step) {
924
            this.current_view = this.steps[step];
925
            this.update_controls();
926

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

    
932
            this.update_steps_history();
933
        },
934

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

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

    
973
        get_params: function() {
974
            return _.extend({}, this.steps[1].get(), this.steps[2].get(), this.steps[3].get());
975
        }
976
    });
977
    
978
})(this);
979