Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_create_view.js @ c6e9caec

History | View | Annotate | Download (31.3 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
        },
55

    
56
        onClose: function() {
57
            this.password.text("");
58
            this.vm_id = undefined;
59
        },
60
        
61
        beforeOpen: function() {
62
            try { delete this.clipboard } catch (err) { console.log(err) };
63
            this.clipboard = new util.ClipHelper(this.copy);
64
        },
65
        
66
        onOpen: function() {
67
            this.copy.show();
68
            try {
69
                this.clipboard.setText(this.pass);
70
                this.copy.show();
71
            } catch (err) {
72
                this.copy.hide();
73
            }
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
            this.show_password();
82
        }
83
    })
84

    
85

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
163
            return this.images;
164
        },
165

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

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

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

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

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

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

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

    
231
                var size = image.get_readable_size();
232

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

    
236
            } else {
237
                this.image_details.hide();
238
            }
239
        },
240

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

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

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

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

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

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

    
290
    views.CreateFlavorSelectView = views.CreateVMStepView.extend({
291
        step: 2,
292
        initialize: function() {
293
            views.CreateFlavorSelectView.__super__.initialize.apply(this, arguments);
294
            this.parent.bind("image:change", _.bind(this.handle_image_change, this));
295

    
296
            this.cpus = this.$(".flavors-cpu-list");
297
            this.disks = this.$(".flavors-disk-list");
298
            this.mems = this.$(".flavors-mem-list");
299

    
300
            this.predefined_flavors = SUGGESTED_FLAVORS;
301
            this.predefined_flavors_keys = _.keys(SUGGESTED_FLAVORS);
302
            this.predefined_flavors_keys = _.sortBy(this.predefined_flavors_keys, _.bind(function(k){
303
                var flv = this.predefined_flavors[k];
304
                return flv.ram * flv.cpu * flv.disk;
305
            }, this));
306

    
307
            this.predefined = this.$(".predefined-list");
308
            this.update_predefined_flavors();
309
        },
310

    
311
        handle_image_change: function(data) {
312
            this.current_image = data;
313
            this.update_valid_predefined();
314
            this.update_flavors_data();
315
            this.reset_flavors();
316
            this.update_layout();
317
        },
318

    
319
        reset_flavors: function() {
320
            this.$(".flavor-opts-list .option").remove();
321
            this.create_flavors();
322
        },
323

    
324
        update_predefined_flavors: function() {
325
            this.predefined.find("li").remove();
326
            _.each(this.predefined_flavors_keys, _.bind(function(key) {
327
                var val = this.predefined_flavors[key];
328
                var el = $(('<li class="predefined-selection" id="predefined-flavor-{0}">' +
329
                           '{1}</li>').format(key, _(key).capitalize()));
330

    
331
                this.predefined.append(el);
332
                el.data({flavor: storage.flavors.get_flavor(val.cpu, val.ram, val.disk, this.flavors)})
333
                el.click(_.bind(function() {
334
                    this.handle_predefined_click(el);
335
                }, this))
336
            }, this));
337
            this.update_valid_predefined();
338
        },
339

    
340
        handle_predefined_click: function(el) {
341
            if (el.hasClass("disabled")) { return };
342
            this.set_current(el.data("flavor"))
343
        },
344

    
345
        update_valid_predefined: function() {
346
            this.update_unavailable_values();
347
            var self = this;
348
            this.valid_predefined = _.select(_.map(this.predefined_flavors, function(flv, key){
349
                var existing = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
350
                // non existing
351
                if (!existing) {
352
                    return false;
353
                }
354
                
355
                // not available for image
356
                if (self.unavailable_values && self.unavailable_values.disk.indexOf(existing.get_disk_size()) > -1) {
357
                    return false
358
                }
359

    
360
                return key;
361
            }), function(ret) { return ret });
362
            
363
            $("li.predefined-selection").addClass("disabled");
364
            _.each(this.valid_predefined, function(key) {
365
                $("#predefined-flavor-" + key).removeClass("disabled");
366
            })
367
        },
368

    
369
        update_selected_predefined: function() {
370
            var self = this;
371
            this.predefined.find("li").removeClass("selected");
372

    
373
            _.each(this.valid_predefined, function(key){
374
                var flv = self.predefined_flavors[key];
375
                var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
376

    
377
                if (exists && (exists.id == self.current_flavor.id)) {
378
                    $("#predefined-flavor-" + key).addClass("selected");
379
                }
380
            })
381
        },
382
        
383
        update_flavors_data: function() {
384
            this.flavors = storage.flavors.active();
385
            this.flavors_data = storage.flavors.get_data(this.flavors);
386
            
387
            var self = this;
388
            var set = false;
389
            
390
            // FIXME: validate current flavor
391
            
392
            if (!this.current_flavor) {
393
                _.each(this.valid_predefined, function(key) {
394
                    var flv = self.predefined_flavors[key];
395
                    var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
396
                    if (exists && !set) {
397
                        self.set_current(exists);
398
                        set = true;
399
                    }
400
                })
401
            }
402

    
403
            this.update_unavailable_values();
404
        },
405

    
406
        update_unavailable_values: function() {
407
            if (!this.current_image) { this.unavailable_values = {disk:[], ram:[], cpu:[]}; return };
408
            this.unavailable_values = storage.flavors.unavailable_values_for_image(this.current_image);
409
        },
410
        
411
        flavor_is_valid: function(flv) {
412
            if (!flv) { return false };
413
            var existing = storage.flavors.get_flavor(flv.get("cpu"), flv.get("ram"), flv.get("disk"), this.flavors);
414
            if (!existing) { return false };
415
            if (this.unavailable_values && this.unavailable_values.disk.indexOf(flv.get("disk") > -1)) {
416
                return false
417
            }
418
            return true;
419
        },
420
            
421
        set_valid_current_for: function(t, val) {
422
            var found = this.flavors[0];
423
            _.each(this.flavors, function(flv) {
424
                if (flv.get(t) == val) {
425
                    found = flv;
426
                }
427
            });
428

    
429
            this.set_current(found);
430
        },
431

    
432
        set_current: function(flv) {
433

    
434
            if (!flv) {
435
                // user clicked on invalid combination
436
                // force the first available choice for the
437
                // type of option he last clicked
438
                this.set_valid_current_for.apply(this, this.last_choice);
439
                return;
440
            }
441

    
442
            this.current_flavor = flv;
443
            this.trigger("change");
444
            this.update_selected_flavor();
445
            this.update_selected_predefined();
446
        },
447
        
448
        select_default_flavor: function() {
449
               
450
        },
451

    
452
        update_selected_from_ui: function() {
453
            this.set_current(this.ui_selected());
454
        },
455
        
456
        update_disabled_flavors: function() {
457
            this.$(".flavor-options.disk li").removeClass("disabled");
458
            if (!this.unavailable_values) { return }
459
            
460
            this.$("#create-vm-flavor-options .flavor-options.disk li").each(_.bind(function(i, el){
461
                var el_value = $(el).data("value") * 1000;
462
                if (this.unavailable_values.disk.indexOf(el_value) > -1) {
463
                    $(el).addClass("disabled");
464
                };
465
            }, this));
466
        },
467

    
468
        create_flavors: function() {
469
            var flavors = this.get_active_flavors();
470
            var valid_flavors = this.get_valid_flavors();
471
            this.__added_flavors = {'cpu':[], 'ram':[], 'disk':[]};
472

    
473
            _.each(flavors, _.bind(function(flv){
474
                this.add_flavor(flv);
475
            }, this));
476
            
477
            var self = this;
478
            this.$(".flavor-options li.option").click(function(){
479
                var el = $(this);
480

    
481
                if (el.hasClass("disabled")) { return }
482

    
483
                el.parent().find(".option").removeClass("selected");
484
                el.addClass("selected");
485
                
486
                if (el.hasClass("mem")) { self.last_choice = ["ram", $(this).data("value")] }
487
                if (el.hasClass("cpu")) { self.last_choice = ["cpu", $(this).data("value")] }
488
                if (el.hasClass("disk")) { self.last_choice = ["disk", $(this).data("value")] }
489

    
490
                self.update_selected_from_ui();
491
            })
492
        },
493
        
494
        ui_selected: function() {
495
            var args = [this.$(".option.cpu.selected").data("value"), 
496
                this.$(".option.mem.selected").data("value"), 
497
                this.$(".option.disk.selected").data("value"),
498
            this.flavors];
499

    
500
            var flv = storage.flavors.get_flavor.apply(storage.flavors, args);
501
            return flv;
502
        },
503

    
504
        update_selected_flavor: function() {
505
            var flv = this.current_flavor;
506
            this.$(".option").removeClass("selected");
507

    
508
            this.$(".option.cpu.value-" + flv.get("cpu")).addClass("selected");
509
            this.$(".option.mem.value-" + flv.get("ram")).addClass("selected");
510
            this.$(".option.disk.value-" + flv.get("disk")).addClass("selected");
511
        },
512
        
513
        __added_flavors: {'cpu':[], 'ram':[], 'disk':[]},
514
        add_flavor: function(flv) {
515
            var values = {'cpu': flv.get('cpu'), 'mem': flv.get('ram'), 'disk': flv.get('disk')};
516

    
517
            disabled = "";
518
            
519
            if (this.__added_flavors.cpu.indexOf(values.cpu) == -1) {
520
                var cpu = $(('<li class="option cpu value-{0} {1}">' + 
521
                             '<span class="value">{0}</span>' + 
522
                             '<span class="metric">x</span></li>').format(values.cpu, disabled)).data('value', values.cpu);
523
                this.cpus.append(cpu);
524
                this.__added_flavors.cpu.push(values.cpu);
525
            }
526

    
527
            if (this.__added_flavors.ram.indexOf(values.mem) == -1) {
528
                var mem = $(('<li class="option mem value-{0}">' + 
529
                             '<span class="value">{0}</span>' + 
530
                             '<span class="metric">MB</span></li>').format(values.mem)).data('value', values.mem);
531
                this.mems.append(mem);
532
                this.__added_flavors.ram.push(values.mem);
533
            }
534

    
535
            if (this.__added_flavors.disk.indexOf(values.disk) == -1) {
536
                var disk = $(('<li class="option disk value-{0}">' + 
537
                              '<span class="value">{0}</span>' + 
538
                              '<span class="metric">GB</span></li>').format(values.disk)).data('value', values.disk);
539
                this.disks.append(disk);
540
                this.__added_flavors.disk.push(values.disk)
541
            }
542

    
543
            
544
        },
545
        
546
        get_active_flavors: function() {
547
            return storage.flavors.active();
548
        },
549

    
550
        get_valid_flavors: function() {
551
            return this.flavors;
552
        },
553

    
554
        update_layout: function() {
555
            this.update_selected_flavor();
556
            this.update_disabled_flavors();
557
        },
558

    
559
        reset: function() {
560
            this.current_image = storage.images.at(0);
561
            this.flavors = [];
562
            this.flavors_data = {'cpu':[], 'mem':[], 'disk':[]};
563
            this.update_flavors_data();
564
        },
565

    
566
        get: function() {
567
            return {'flavor': this.current_flavor}
568
        }
569

    
570
    });
571

    
572
    views.CreateSubmitView = views.CreateVMStepView.extend({
573
        step: 3,
574
        initialize: function() {
575
            views.CreateSubmitView.__super__.initialize.apply(this, arguments);
576
            this.roles = this.$("li.predefined-meta.role .values");
577
            this.confirm = this.$(".confirm-params ul");
578
            this.name = this.$("input.rename-field");
579
            this.name_changed = false;
580
            this.init_suggested_roles();
581
            this.init_handlers();
582
        },
583

    
584
        init_suggested_roles: function() {
585
            var cont = this.roles;
586
            cont.empty();
587
            
588
            // TODO: get suggested from snf.api.conf
589
            _.each(window.SUGGESTED_ROLES, function(r){
590
                var el = $('<span class="val">{0}</span>'.format(r));
591
                el.data("value", r);
592
                cont.append(el);
593
                el.click(function() {
594
                    $(this).parent().find(".val").removeClass("selected");
595
                    $(this).toggleClass("selected");
596
                })
597
            })
598
        },
599

    
600
        init_handlers: function() {
601
            this.name.bind("keypress", _.bind(function(e) {
602
                this.name_changed = true;
603
                if (e.keyCode == 13) { this.parent.submit() };    
604
            }, this));
605

    
606
            this.name.bind("click", _.bind(function() {
607
                if (!this.name_changed) {
608
                    this.name.val("");
609
                }
610
            }, this))
611
        },
612

    
613
        show: function() {
614
            views.CreateSubmitView.__super__.show.apply(this, arguments);
615
            this.update_layout();
616
        },
617
        
618
        update_flavor_details: function() {
619
            var flavor = this.parent.get_params().flavor;
620

    
621
            function set_detail(sel, key) {
622
                var val = key;
623
                if (key == undefined) { val = flavor.get(sel) };
624
                this.$(".confirm-cont.flavor .flavor-" + sel + " .value").text(val)
625
            }
626
            
627
            set_detail("cpu", flavor.get("cpu") + "x");
628
            set_detail("ram", flavor.get("ram") + " MB");
629
            set_detail("disk", util.readablizeBytes(flavor.get("disk") * 1024 * 1024 * 1024));
630
        },
631

    
632
        update_image_details: function() {
633
            var image = this.parent.get_params().image;
634

    
635
            function set_detail(sel, key) {
636
                var val = key;
637
                if (key == undefined) { val = image.get(sel) };
638
                this.$(".confirm-cont.image .image-" + sel + " .value").text(val)
639
            }
640
            
641
            set_detail("description");
642
            set_detail("name");
643
            set_detail("os", _(image.get("OS")).capitalize());
644
            set_detail("gui", image.get("GUI"));
645
            set_detail("size", image.get_readable_size());
646
            set_detail("kernel");
647
        },
648

    
649
        update_layout: function() {
650
            var params = this.parent.get_params();
651

    
652
            if (!params.image) { return }
653
            var vm_name = "My {0} server".format(params.image.get("name"));
654
            var orig_name = vm_name;
655
            
656
            var existing = true;
657
            var j = 0;
658

    
659
            while (existing && !this.name_changed) {
660
                var existing = storage.vms.select(function(vm){return vm.get("name") == vm_name}).length
661
                if (existing) {
662
                    j++;
663
                    vm_name = orig_name + " " + j;
664
                }
665
            }
666
            if (!_(this.name.val()).trim() || !this.name_changed) {
667
                this.name.val(vm_name);
668
            }
669

    
670
            this.confirm.find("li.image .value").text(params.flavor.get("image"));
671
            this.confirm.find("li.cpu .value").text(params.flavor.get("cpu") + "x");
672
            this.confirm.find("li.mem .value").text(params.flavor.get("ram"));
673
            this.confirm.find("li.disk .value").text(params.flavor.get("disk"));
674

    
675
            if (!this.name_changed && this.parent.visible()) {
676
                if (!$.browser.msie && !$.browser.opera) {
677
                    this.$("#create-vm-name").select();
678
                } else {
679
                    window.setTimeout(_.bind(function(){
680
                        this.$("#create-vm-name").select();
681
                    }, this), 400)
682
                }
683
            }
684
            
685
            var img = snf.ui.helpers.os_icon_path(params.image.get("OS"))
686
            this.name.css({backgroundImage:"url({0})".format(img)})
687

    
688
            this.update_image_details();
689
            this.update_flavor_details();
690
        },
691

    
692
        reset: function() {
693
            this.roles.find(".val").removeClass("selected");
694
            this.name_changed = false;
695
            this.update_layout();
696
        },
697

    
698
        get_meta: function() {
699
            if (this.roles.find(".selected").length == 0) {
700
                return false;
701
            }
702

    
703
            var role = $(this.roles.find(".selected").get(0)).data("value");
704
            return {'Role': role }
705
        },
706

    
707
        get: function() {
708
            var val = {'name': this.name.val() };
709
            if (this.get_meta()) {
710
                val.metadata = this.get_meta();
711
            }
712
            
713
            return val;
714
        }
715
    });
716

    
717
    views.CreateVMView = views.Overlay.extend({
718
        
719
        view_id: "create_vm_view",
720
        content_selector: "#createvm-overlay-content",
721
        css_class: 'overlay-createvm overlay-info',
722
        overlay_id: "metadata-overlay",
723

    
724
        subtitle: false,
725
        title: "Create new machine",
726

    
727
        initialize: function(options) {
728
            views.CreateVMView.__super__.initialize.apply(this);
729
            this.current_step = 1;
730

    
731
            this.password_view = new views.VMCreationPasswordView();
732

    
733
            this.steps = [];
734
            this.steps[1] = new views.CreateImageSelectView(this);
735
            this.steps[1].bind("change", _.bind(function(data) {this.trigger("image:change", data)}, this));
736

    
737
            this.steps[2] = new views.CreateFlavorSelectView(this);
738
            this.steps[3] = new views.CreateSubmitView(this);
739

    
740
            this.cancel_btn = this.$(".create-controls .cancel");
741
            this.next_btn = this.$(".create-controls .next");
742
            this.prev_btn = this.$(".create-controls .prev");
743
            this.submit_btn = this.$(".create-controls .submit");
744

    
745
            this.history = this.$(".steps-history");
746
            this.history_steps = this.$(".steps-history .steps-history-step");
747
            
748
            this.init_handlers();
749
        },
750

    
751
        init_handlers: function() {
752
            var self = this;
753
            this.next_btn.click(_.bind(function(){
754
                this.set_step(this.current_step + 1);
755
                this.update_layout();
756
            }, this))
757
            this.prev_btn.click(_.bind(function(){
758
                this.set_step(this.current_step - 1);
759
                this.update_layout();
760
            }, this))
761
            this.cancel_btn.click(_.bind(function(){
762
                this.close_all();
763
            }, this))
764
            this.submit_btn.click(_.bind(function(){
765
                this.submit();
766
            }, this))
767
            
768
            this.history.find(".completed").live("click", function() {
769
                var step = parseInt($(this).attr("id").replace("vm-create-step-history-", ""));
770
                self.set_step(step);
771
                self.update_layout();
772
            })
773
        },
774

    
775
        set_step: function(st) {
776
        },
777
        
778
        validate: function(data) {
779
            if (_(data.name).trim() == "") {
780
                this.$(".form-field").addClass("error");
781
                return false;
782
            } else {
783
                return true;
784
            }
785
        },
786

    
787
        submit: function() {
788
            if (this.submiting) { return };
789
            var data = this.get_params();
790
            var meta = {};
791
            if (this.validate(data)) {
792
                this.submit_btn.addClass("in-progress");
793
                this.submiting = true;
794
                if (data.metadata) { meta = data.metadata; }
795
                storage.vms.create(data.name, data.image, data.flavor, meta, {}, _.bind(function(data){
796
                    this.close_all();
797
                    this.password_view.show(data.server.adminPass, data.server.id);
798
                    this.submiting = false;
799
                }, this));
800
            }
801
        },
802

    
803
        close_all: function() {
804
            this.hide();
805
        },
806

    
807
        reset: function() {
808
            this.current_step = 1;
809

    
810
            this.steps[1].reset();
811
            this.steps[2].reset();
812
            this.steps[3].reset();
813

    
814
            this.steps[1].show();
815
            this.steps[2].show();
816
            this.steps[3].show();
817

    
818
            this.submit_btn.removeClass("in-progress");
819
        },
820

    
821
        onShow: function() {
822
            this.reset()
823
            this.update_layout();
824
        },
825

    
826
        update_layout: function() {
827
            this.show_step(this.current_step);
828
            this.current_view.update_layout();
829
        },
830

    
831
        beforeOpen: function() {
832
            this.submiting = false;
833
            this.reset();
834
            this.current_step = 1;
835
            this.$(".steps-container").css({"margin-left":0 + "px"});
836
            this.show_step(1);
837
        },
838
        
839
        set_step: function(step) {
840
            if (step <= 1) {
841
                step = 1
842
            }
843
            if (step > this.steps.length - 1) {
844
                step = this.steps.length - 1;
845
            }
846
            this.current_step = step;
847
        },
848

    
849
        show_step: function(step) {
850
            this.current_view = this.steps[step];
851
            this.update_controls();
852

    
853
            this.steps[step].show();
854
            var width = this.el.find('.container').width();
855
            var left = (step -1) * width * -1;
856
            this.$(".steps-container").animate({"margin-left": left + "px"}, 300);
857

    
858
            this.update_steps_history();
859
        },
860

    
861
        update_steps_history: function() {
862
            var self = this;
863
            function get_step(s) {
864
                return self.history.find(".step" + s + "h");
865
            }
866
            
867
            var current_step = parseInt(this.current_view.step);
868
            _.each(this.steps, function(stepv) {
869
                var step = parseInt(stepv.step);
870
                get_step(step).removeClass("completed").removeClass("current");
871
                if (step == current_step) {
872
                    get_step(step).removeClass("completed").addClass("current");
873
                }
874
                if (step < current_step) {
875
                    get_step(step).removeClass("current").addClass("completed");
876
                }
877
            });
878
        },
879

    
880
        update_controls: function() {
881
            var step = this.current_step;
882
            if (step == 1) {
883
                this.prev_btn.hide();
884
                this.cancel_btn.show();
885
            } else {
886
                this.prev_btn.show();
887
                this.cancel_btn.hide();
888
            }
889
            
890
            if (step == this.steps.length - 1) {
891
                this.next_btn.hide();
892
                this.submit_btn.show();
893
            } else {
894
                this.next_btn.show();
895
                this.submit_btn.hide();
896
            }
897
        },
898

    
899
        get_params: function() {
900
            return _.extend({}, this.steps[1].get(), this.steps[2].get(), this.steps[3].get());
901
        }
902
    });
903
    
904
})(this);
905