Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_create_view.js @ 2385c471

History | View | Annotate | Download (28.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
                this.hide();
37
                snf.ui.main.show_vm_details(storage.vms.get(this.vm_id));
38
            }, this));
39
            
40
        },
41
        
42
        show_password: function() {
43
            this.password.text(this.pass);
44
        },
45

    
46
        onClose: function() {
47
            this.password.text("");
48
        },
49
        
50
        beforeOpen: function() {
51
            if (this.clipboard) { return };
52
            this.clipboard = new util.ClipHelper(this.copy);
53
        },
54
        
55
        onOpen: function() {
56
            this.copy.show();
57
            try {
58
                this.clipboard.setText(this.pass);
59
                this.copy.show();
60
            } catch (err) {
61
                console.error(err);
62
                this.copy.hide();
63
            }
64
        },
65

    
66
        show: function(pass, vm_id) {
67
            this.pass = pass;
68
            this.vm_id = vm_id;
69

    
70
            views.VMCreationPasswordView.__super__.show.apply(this, arguments);
71
            this.show_password();
72
        }
73
    })
74

    
75

    
76
    
77
    views.CreateVMStepView = views.View.extend({
78
        step: "1",
79
        title: "Image",
80
        submit: false,
81

    
82
        initialize: function(view) {
83
            this.parent = view;
84
            this.el = view.$("div.create-step-cont.step-" + this.step);
85
            this.header = this.$(".step-header .step-" + this.step);
86
            this.view_id = "create_step_" + this.step;
87

    
88
            views.CreateVMStepView.__super__.initialize.apply(this);
89
        },
90

    
91
        show: function() {
92
            // show current
93
            this.el.show();
94
            this.header.addClass("current");
95
            this.header.show();
96
            this.update_layout();
97
        },
98

    
99
        reset: function() {
100
        }
101
    })
102

    
103
    views.CreateImageSelectView = views.CreateVMStepView.extend({
104

    
105
        initialize: function() {
106
            views.CreateImageSelectView.__super__.initialize.apply(this, arguments);
107

    
108
            // elements
109
            this.images_list_cont = this.$(".images-list-cont");
110
            this.images_list = this.$(".images-list-cont ul");
111
            this.image_details = this.$(".images-info-cont");
112
            this.image_details_desc = this.$(".images-info-cont .description p");
113
            this.image_details_title = this.$(".images-info-cont h4");
114
            this.image_details_size = this.$(".images-info-cont .size p");
115
            this.image_details_os = this.$(".images-info-cont .os p");
116
            this.image_details_kernel = this.$(".images-info-cont .kernel p");
117
            this.image_details_gui = this.$(".images-info-cont .gui p");
118

    
119
            this.types = this.$(".type-filter li");
120
            this.categories_list = this.$(".category-filters");
121

    
122
            // params initialization
123
            this.type_selections = ["system", "custom"]
124
            this.selected_type = "system";
125
            this.selected_categories = [];
126
            this.images = [];
127

    
128
            // update
129
            this.update_images();
130

    
131
            // handlers initialization
132
            this.init_handlers();
133
            this.init_position();
134
        },
135

    
136
        init_position: function() {
137
            //this.el.css({position: "absolute"});
138
            //this.el.css({top:"10px"})
139
        },
140
        
141
        init_handlers: function() {
142
            var self = this;
143
            this.types.live("click", function() {
144
                self.select_type($(this).attr("id").replace("type-select-",""));
145
            })
146
        },
147

    
148
        update_images: function() {
149
            this.images = storage.images.active();
150
            this.images_ids = _.map(this.images, function(img){return img.id});
151
            if (this.selected_type == "custom") { this.images = []; this.images_ids = []; }
152

    
153
            return this.images;
154
        },
155

    
156
        update_layout: function() {
157
            this.select_type(this.selected_type);
158
        },
159
        
160
        get_categories: function(images) {
161
            return [];
162
            return ["Desktop", "Server", "Linux", "Windows"];
163
        },
164

    
165
        reset_categories: function() {
166
            var categories = this.get_categories(this.images);
167
            this.categories_list.find("li").remove();
168

    
169
            _.each(categories, _.bind(function(cat) {
170
                var el = $("<li />");
171
                el.text(cat);
172
                this.categories_list.append(el);
173
            }, this));
174

    
175
            if (!categories.length) { 
176
                this.categories_list.parent().find(".clear").hide();
177
                this.categories_list.parent().find(".empty").show();
178
            } else {
179
                this.categories_list.parent().find(".clear").show();
180
                this.categories_list.parent().find(".empty").hide();
181
            }
182
        },
183
        
184
        select_type: function(type) {
185
            this.selected_type = type;
186
            this.types.removeClass("selected");
187
            this.types.filter("#type-select-" + this.selected_type).addClass("selected");
188

    
189
            this.reset_categories();
190
            this.update_images();
191
            this.reset_images();
192
            this.select_image();
193
        },
194

    
195
        select_image: function(image) {
196
            if (!image && this.images_ids.length) {
197
                if (this.selected_image && this.images_ids.indexOf(this.selected_image.id) > -1) {
198
                    image = this.selected_image;
199
                } else {
200
                    image = storage.images.get(this.images_ids[0]);
201
                }
202
            }
203

    
204
            if (!this.images_ids.length) { image = this.selected_image || undefined };
205
            
206
            this.selected_image = image;
207
            this.trigger("change", image);
208
            
209
            if (image) {
210
                this.image_details.show();
211
                this.images_list.find(".image-details").removeClass("selected");
212
                this.images_list.find(".image-details#create-vm-image-" + this.selected_image.id).addClass("selected");
213
                
214
                this.image_details_desc.text(image.get("description"));
215
                
216
                var img = snf.ui.helpers.os_icon_tag(image.get("OS"))
217
                this.image_details_title.html(img + image.get("name"));
218
                this.image_details_os.text(_(image.get("OS")).capitalize());
219
                this.image_details_kernel.text(image.get("kernel"));
220

    
221
                var size = util.readablizeBytes(parseInt(image.get("size")) * 1024 * 1024);
222
                this.image_details_size.text(size);
223
                this.image_details_gui.text(image.get("GUI"));
224

    
225
            } else {
226
                this.image_details.hide();
227
            }
228
        },
229

    
230
        reset_images: function() {
231
            this.images_list.find("li").remove();
232
            _.each(this.images, _.bind(function(img){
233
                this.add_image(img);
234
            }, this))
235
            
236
            if (this.images.length) {
237
                this.images_list.parent().find(".empty").hide();
238
            } else {
239
                this.images_list.parent().find(".empty").show();
240
            }
241

    
242
            this.select_image();
243
            
244
            var self = this;
245
            this.images_list.find(".image-details").click(function(){
246
                self.select_image($(this).data("image"));
247
            });
248
            
249
        },
250

    
251
        show: function() {
252
            views.CreateImageSelectView.__super__.show.apply(this, arguments);
253
        },
254

    
255
        add_image: function(img) {
256
            var image = $(('<li id="create-vm-image-{1}"' +
257
                           'class="image-details clearfix">{2}{0}' +
258
                           '<p>{4}</p><span class="size">{3}' +
259
                           '</span></li>').format(img.get("name"), 
260
                                                  img.id, 
261
                                                  snf.ui.helpers.os_icon_tag(img.get("OS")),
262
                                                  util.readablizeBytes(parseInt(img.get("size"))* 1024 * 1024),
263
                                                  util.truncate(img.get("description"),35)));
264
            image.data("image", img);
265
            image.data("image_id", img.id);
266
            this.images_list.append(image);
267
        },
268

    
269
        reset: function() {
270
            this.selected_image = undefined;
271
            this.reset_images();
272
        },
273

    
274
        get: function() {
275
            return {'image': this.selected_image};
276
        }
277
    });
278

    
279
    views.CreateFlavorSelectView = views.CreateVMStepView.extend({
280
        step: 2,
281
        initialize: function() {
282
            views.CreateFlavorSelectView.__super__.initialize.apply(this, arguments);
283
            this.parent.bind("image:change", _.bind(this.handle_image_change, this));
284

    
285
            this.cpus = this.$(".flavors-cpu-list");
286
            this.disks = this.$(".flavors-disk-list");
287
            this.mems = this.$(".flavors-mem-list");
288

    
289
            this.predefined_flavors = SUGGESTED_FLAVORS;
290
            this.predefined_flavors_keys = _.keys(SUGGESTED_FLAVORS);
291
            this.predefined_flavors_keys = _.sortBy(this.predefined_flavors_keys, _.bind(function(k){
292
                var flv = this.predefined_flavors[k];
293
                return flv.ram * flv.cpu * flv.disk;
294
            }, this));
295

    
296
            this.predefined = this.$(".predefined-list");
297
            this.update_predefined_flavors();
298
        },
299

    
300
        handle_image_change: function(data) {
301
            this.current_image = data;
302
            this.update_valid_predefined();
303
            this.update_flavors_data();
304
            this.reset_flavors();
305
            this.update_layout();
306
        },
307

    
308
        reset_flavors: function() {
309
            this.$(".flavor-opts-list .option").remove();
310
            this.create_flavors();
311
        },
312

    
313
        update_predefined_flavors: function() {
314
            this.predefined.find("li").remove();
315
            _.each(this.predefined_flavors_keys, _.bind(function(key) {
316
                var val = this.predefined_flavors[key];
317
                var el = $(('<li class="predefined-selection" id="predefined-flavor-{0}">' +
318
                           '{1}</li>').format(key, _(key).capitalize()));
319

    
320
                this.predefined.append(el);
321
                el.data({flavor: storage.flavors.get_flavor(val.cpu, val.ram, val.disk, this.flavors)})
322
                el.click(_.bind(function() {
323
                    this.handle_predefined_click(el);
324
                }, this))
325
            }, this));
326
            this.update_valid_predefined();
327
        },
328

    
329
        handle_predefined_click: function(el) {
330
            if (el.hasClass("disabled")) { return };
331
            this.set_current(el.data("flavor"))
332
        },
333

    
334
        update_valid_predefined: function() {
335
            this.update_unavailable_values();
336
            var self = this;
337
            this.valid_predefined = _.select(_.map(this.predefined_flavors, function(flv, key){
338
                var existing = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
339
                // non existing
340
                if (!existing) {
341
                    return false;
342
                }
343
                
344
                // not available for image
345
                if (self.unavailable_values && self.unavailable_values.disk.indexOf(existing.get_disk_size()) > -1) {
346
                    return false
347
                }
348

    
349
                return key;
350
            }), function(ret) { return ret });
351
            
352
            $("li.predefined-selection").addClass("disabled");
353
            _.each(this.valid_predefined, function(key) {
354
                $("#predefined-flavor-" + key).removeClass("disabled");
355
            })
356
        },
357

    
358
        update_selected_predefined: function() {
359
            var self = this;
360
            this.predefined.find("li").removeClass("selected");
361

    
362
            _.each(this.valid_predefined, function(key){
363
                var flv = self.predefined_flavors[key];
364
                var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
365

    
366
                if (exists && (exists.id == self.current_flavor.id)) {
367
                    $("#predefined-flavor-" + key).addClass("selected");
368
                }
369
            })
370
        },
371
        
372
        update_flavors_data: function() {
373
            this.flavors = storage.flavors.active();
374
            this.flavors_data = storage.flavors.get_data(this.flavors);
375
            
376
            var self = this;
377
            var set = false;
378
            
379
            // FIXME: validate current flavor
380
            
381
            if (!this.current_flavor) {
382
                _.each(this.valid_predefined, function(key) {
383
                    var flv = self.predefined_flavors[key];
384
                    var exists = storage.flavors.get_flavor(flv.cpu, flv.ram, flv.disk, self.flavors);
385
                    if (exists && !set) {
386
                        self.set_current(exists);
387
                        set = true;
388
                    }
389
                })
390
            }
391

    
392
            this.update_unavailable_values();
393
        },
394

    
395
        update_unavailable_values: function() {
396
            if (!this.current_image) { this.unavailable_values = {disk:[], ram:[], cpu:[]}; return };
397
            this.unavailable_values = storage.flavors.unavailable_values_for_image(this.current_image);
398
        },
399
        
400
        flavor_is_valid: function(flv) {
401
            if (!flv) { return false };
402
            var existing = storage.flavors.get_flavor(flv.get("cpu"), flv.get("ram"), flv.get("disk"), this.flavors);
403
            if (!existing) { return false };
404
            if (this.unavailable_values && this.unavailable_values.disk.indexOf(flv.get("disk") > -1)) {
405
                return false
406
            }
407
            return true;
408
        },
409
            
410
        set_current: function(flv) {
411
            //console.log(flv);
412
            //if (!this.flavor_is_valid(flv)) { flv = undefined };
413
            
414
            this.current_flavor = flv;
415
            this.trigger("change");
416
            this.update_selected_flavor();
417
            this.update_selected_predefined();
418
        },
419
        
420
        select_default_flavor: function() {
421
               
422
        },
423

    
424
        update_selected_from_ui: function() {
425
            this.set_current(this.ui_selected());
426
        },
427
        
428
        update_disabled_flavors: function() {
429
            this.$(".flavor-options.disk li").removeClass("disabled");
430
            if (!this.unavailable_values) { return }
431

    
432
            this.$(".flavor-options.disk li").each(_.bind(function(i, el){
433
                var el_value = $(el).data("value") * 1024;
434
                if (this.unavailable_values.disk.indexOf(el_value) > -1) {
435
                    $(el).addClass("disabled");
436
                };
437
            }, this));
438
        },
439

    
440
        create_flavors: function() {
441
            var flavors = this.get_active_flavors();
442
            var valid_flavors = this.get_valid_flavors();
443

    
444
            _.each(flavors, _.bind(function(flv){
445
                this.add_flavor(flv);
446
            }, this));
447
            
448
            var self = this;
449
            this.$(".flavor-options li.option").click(function(){
450
                var el = $(this);
451

    
452
                if (el.hasClass("disabled")) { return }
453

    
454
                el.parent().find(".option").removeClass("selected");
455
                el.addClass("selected");
456
                
457
                if (el.hasClass("mem")) { this.last_choice = "mem" }
458
                if (el.hasClass("cpu")) { this.last_choice = "cpu" }
459
                if (el.hasClass("disk")) { this.last_choice = "disk" }
460

    
461
                self.update_selected_from_ui();
462
            })
463
        },
464
        
465
        ui_selected: function() {
466
            var args = [this.$(".option.cpu.selected").data("value"), 
467
                this.$(".option.mem.selected").data("value"), 
468
                this.$(".option.disk.selected").data("value"),
469
            this.flavors];
470

    
471
            var flv = storage.flavors.get_flavor.apply(storage.flavors, args);
472
            return flv;
473
        },
474

    
475
        update_selected_flavor: function() {
476
            var flv = this.current_flavor;
477
            this.$(".option").removeClass("selected");
478

    
479
            this.$(".option.cpu.value-" + flv.get("cpu")).addClass("selected");
480
            this.$(".option.mem.value-" + flv.get("ram")).addClass("selected");
481
            this.$(".option.disk.value-" + flv.get("disk")).addClass("selected");
482
        },
483

    
484
        add_flavor: function(flv) {
485
            var values = {'cpu': flv.get('cpu'), 'mem': flv.get('ram'), 'disk': flv.get('disk')};
486

    
487
            disabled = "";
488

    
489
            if (this.$('li.option.cpu.value-{0}'.format(values.cpu)).length == 0) {
490
                var cpu = $(('<li class="option cpu value-{0} {1}">' + 
491
                             '<span class="value">{0}</span>' + 
492
                             '<span class="metric">x</span></li>').format(values.cpu, disabled)).data('value', values.cpu);
493

    
494
                this.cpus.append(cpu);
495
            }
496
            if (this.$('li.option.mem.value-{0}'.format(values.mem)).length == 0) {
497
                var mem = $(('<li class="option mem value-{0}">' + 
498
                             '<span class="value">{0}</span>' + 
499
                             '<span class="metric">MB</span></li>').format(values.mem)).data('value', values.mem);
500

    
501
                this.mems.append(mem);
502
            }
503
            if (this.$('li.option.disk.value-{0}'.format(values.disk)).length == 0) {
504
                var disk = $(('<li class="option disk value-{0}">' + 
505
                              '<span class="value">{0}</span>' + 
506
                              '<span class="metric">GB</span></li>').format(values.disk)).data('value', values.disk);
507

    
508
                this.disks.append(disk);
509
            }
510
            
511
        },
512
        
513
        get_active_flavors: function() {
514
            return storage.flavors.active();
515
        },
516

    
517
        get_valid_flavors: function() {
518
            return this.flavors;
519
        },
520

    
521
        update_layout: function() {
522
            this.update_selected_flavor();
523
            this.update_disabled_flavors();
524
        },
525

    
526
        reset: function() {
527
            this.current_image = storage.images.at(0);
528
            this.flavors = [];
529
            this.flavors_data = {'cpu':[], 'mem':[], 'disk':[]};
530
            this.update_flavors_data();
531
            this.reset_flavors();
532
        },
533

    
534
        get: function() {
535
            return {'flavor': this.current_flavor}
536
        }
537

    
538
    });
539

    
540
    views.CreateSubmitView = views.CreateVMStepView.extend({
541
        step: 3,
542
        initialize: function() {
543
            views.CreateSubmitView.__super__.initialize.apply(this, arguments);
544
            this.roles = this.$("li.predefined-meta.role .values");
545
            this.confirm = this.$(".confirm-params ul");
546
            this.name = this.$("input.rename-field");
547
            this.name_changed = false;
548
            this.init_suggested_roles();
549
            this.init_handlers();
550
        },
551

    
552
        init_suggested_roles: function() {
553
            var cont = this.roles;
554
            cont.empty();
555
            
556
            // TODO: get suggested from snf.api.conf
557
            _.each(window.SUGGESTED_ROLES, function(r){
558
                var el = $('<span class="val">{0}</span>'.format(r));
559
                el.data("value", r);
560
                cont.append(el);
561
                el.click(function() {
562
                    $(this).parent().find(".val").removeClass("selected");
563
                    $(this).toggleClass("selected");
564
                })
565
            })
566
        },
567

    
568
        init_handlers: function() {
569
            this.name.bind("keypress", _.bind(function(e) {
570
                this.name_changed = true;
571
                if (e.keyCode == 13) { this.parent.submit() };    
572
            }, this));
573

    
574
            this.name.bind("click", _.bind(function() {
575
                if (!this.name_changed) {
576
                    this.name.val("");
577
                }
578
            }, this))
579
        },
580

    
581
        show: function() {
582
            views.CreateSubmitView.__super__.show.apply(this, arguments);
583
            this.update_layout();
584
        },
585
        
586
        update_flavor_details: function() {
587
            var flavor = this.parent.get_params().flavor;
588

    
589
            function set_detail(sel, key) {
590
                var val = key;
591
                if (key == undefined) { val = flavor.get(sel) };
592
                this.$(".confirm-cont.flavor .flavor-" + sel + " .value").text(val)
593
            }
594
            
595
            set_detail("cpu");
596
            set_detail("ram", flavor.get("ram") + " MB");
597
            set_detail("disk", util.readablizeBytes(flavor.get("disk") * 1024 * 1024 * 1024));
598
        },
599

    
600
        update_image_details: function() {
601
            var image = this.parent.get_params().image;
602

    
603
            function set_detail(sel, key) {
604
                var val = key;
605
                if (key == undefined) { val = image.get(sel) };
606
                this.$(".confirm-cont.image .image-" + sel + " .value").text(val)
607
            }
608
            
609
            set_detail("description");
610
            set_detail("name");
611
            set_detail("os", image.get("OS"));
612
            set_detail("gui", image.get("GUI"));
613
            set_detail("size", util.readablizeBytes(image.get_size() * 1024 * 1024));
614
            set_detail("kernel");
615
        },
616

    
617
        update_layout: function() {
618
            var params = this.parent.get_params();
619

    
620
            if (!params.image) { return }
621
            var vm_name = "My {0} server".format(params.image.get("name"));
622
            var orig_name = vm_name;
623
            
624
            var existing = true;
625
            var j = 0;
626

    
627
            while (existing && !this.name_changed) {
628
                var existing = storage.vms.select(function(vm){return vm.get("name") == vm_name}).length
629
                if (existing) {
630
                    j++;
631
                    vm_name = orig_name + " " + j;
632
                }
633
            }
634
            if (!_(this.name.val()).trim() || !this.name_changed) {
635
                this.name.val(vm_name);
636
            }
637

    
638
            this.confirm.find("li.image .value").text(params.flavor.get("image"));
639
            this.confirm.find("li.cpu .value").text(params.flavor.get("cpu") + "x");
640
            this.confirm.find("li.mem .value").text(params.flavor.get("ram"));
641
            this.confirm.find("li.disk .value").text(params.flavor.get("disk"));
642

    
643
            if (!this.name_changed) {
644
            }
645
            
646
            var img = snf.ui.helpers.os_icon_path(params.image.get("OS"))
647
            this.name.css({backgroundImage:"url({0})".format(img)})
648

    
649
            this.update_image_details();
650
            this.update_flavor_details();
651
        },
652

    
653
        reset: function() {
654
            this.roles.find(".val").removeClass("selected");
655
            this.name_changed = false;
656
            this.update_layout();
657
        },
658

    
659
        get_meta: function() {
660
            if (this.roles.find(".selected").length == 0) {
661
                return false;
662
            }
663

    
664
            var role = $(this.roles.find(".selected").get(0)).data("value");
665
            return {'Role': role }
666
        },
667

    
668
        get: function() {
669
            var val = {'name': this.name.val() };
670
            if (this.get_meta()) {
671
                val.metadata = this.get_meta();
672
            }
673
            
674
            return val;
675
        }
676
    });
677

    
678
    views.CreateVMView = views.Overlay.extend({
679
        
680
        view_id: "create_vm_view",
681
        content_selector: "#createvm-overlay-content",
682
        css_class: 'overlay-createvm overlay-info',
683
        overlay_id: "metadata-overlay",
684

    
685
        subtitle: false,
686
        title: "Create new machine",
687

    
688
        initialize: function(options) {
689
            views.CreateVMView.__super__.initialize.apply(this);
690
            this.current_step = 1;
691

    
692
            this.password_view = new views.VMCreationPasswordView();
693

    
694
            this.steps = [];
695
            this.steps[1] = new views.CreateImageSelectView(this);
696
            this.steps[1].bind("change", _.bind(function(data) {this.trigger("image:change", data)}, this));
697

    
698
            this.steps[2] = new views.CreateFlavorSelectView(this);
699
            this.steps[3] = new views.CreateSubmitView(this);
700

    
701
            this.cancel_btn = this.$(".create-controls .cancel")
702
            this.next_btn = this.$(".create-controls .next")
703
            this.prev_btn = this.$(".create-controls .prev")
704
            this.submit_btn = this.$(".create-controls .submit")
705
            
706
            this.init_handlers();
707
            this.update_layout();
708

    
709
        },
710

    
711
        init_handlers: function() {
712
            this.next_btn.click(_.bind(function(){
713
                this.set_step(this.current_step + 1);
714
                this.update_layout();
715
            }, this))
716
            this.prev_btn.click(_.bind(function(){
717
                this.set_step(this.current_step - 1);
718
                this.update_layout();
719
            }, this))
720
            this.cancel_btn.click(_.bind(function(){
721
                this.close_all();
722
            }, this))
723
            this.submit_btn.click(_.bind(function(){
724
                this.submit();
725
            }, this))
726
        },
727

    
728
        set_step: function(st) {
729
        },
730
        
731
        validate: function(data) {
732
            if (_(data.name).trim() == "") {
733
                this.$(".form-field").addClass("error");
734
                return false;
735
            } else {
736
                return true;
737
            }
738
        },
739

    
740
        submit: function() {
741
            if (this.submiting) { return };
742
            var data = this.get_params();
743
            var meta = {};
744
            if (this.validate(data)) {
745
                this.submit_btn.addClass("in-progress");
746
                this.submiting = true;
747
                if (data.metadata) { meta = data.metadata; }
748
                storage.vms.create(data.name, data.image, data.flavor, meta, {}, _.bind(function(data){
749
                    this.close_all();
750
                    this.password_view.show(data.server.adminPass, data.server.id);
751
                    this.submiting = false;
752
                }, this));
753
            }
754
        },
755

    
756
        close_all: function() {
757
            this.hide();
758
        },
759

    
760
        reset: function() {
761
            this.current_step = 1;
762

    
763
            this.steps[1].reset();
764
            this.steps[2].reset();
765
            this.steps[3].reset();
766

    
767
            this.steps[1].show();
768
            this.steps[2].show();
769
            this.steps[3].show();
770

    
771
            this.submit_btn.removeClass("in-progress");
772
        },
773

    
774
        onShow: function() {
775
            this.reset()
776
            this.update_layout();
777
        },
778

    
779
        update_layout: function() {
780
            this.show_step(this.current_step);
781
            this.current_view.update_layout();
782
        },
783

    
784
        beforeOpen: function() {
785
            this.submiting = false;
786
            this.reset();
787
            this.current_step = 1;
788
            this.$(".steps-container").css({"margin-left":0 + "px"});
789
            this.show_step(1);
790
        },
791
        
792
        set_step: function(step) {
793
            if (step <= 1) {
794
                step = 1
795
            }
796
            if (step > this.steps.length - 1) {
797
                step = this.steps.length - 1;
798
            }
799
            this.current_step = step;
800
        },
801

    
802
        show_step: function(step) {
803
            this.current_view = this.steps[step];
804
            this.update_controls();
805

    
806
            this.steps[step].show();
807
            var width = this.el.find('.container').width();
808
            var left = (step -1) * width * -1;
809
            this.$(".steps-container").css({"margin-left": left + "px"});
810
        },
811

    
812
        update_controls: function() {
813
            var step = this.current_step;
814
            if (step == 1) {
815
                this.prev_btn.hide();
816
                this.cancel_btn.show();
817
            } else {
818
                this.prev_btn.show();
819
                this.cancel_btn.hide();
820
            }
821
            
822
            if (step == this.steps.length - 1) {
823
                this.next_btn.hide();
824
                this.submit_btn.show();
825
            } else {
826
                this.next_btn.show();
827
                this.submit_btn.hide();
828
            }
829
        },
830

    
831
        get_params: function() {
832
            return _.extend({}, this.steps[1].get(), this.steps[2].get(), this.steps[3].get());
833
        }
834
    });
835
    
836
})(this);
837