Statistics
| Branch: | Tag: | Revision:

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

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
            try {
57
                this.clipboard.setText(this.pass);
58
                this.copy.show();
59
            } catch (err) {
60
                this.copy.hide();
61
            }
62
        },
63

    
64
        show: function(pass, vm_id) {
65
            this.pass = pass;
66
            this.vm_id = vm_id;
67

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

    
73

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

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

    
86
            views.CreateVMStepView.__super__.initialize.apply(this);
87
        },
88

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

    
97
        reset: function() {
98
        }
99
    })
100

    
101
    views.CreateImageSelectView = views.CreateVMStepView.extend({
102

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

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

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

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

    
126
            // update
127
            this.update_images();
128

    
129
            // handlers initialization
130
            this.init_handlers();
131
            this.init_position();
132
        },
133

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

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

    
151
            return this.images;
152
        },
153

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

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

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

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

    
187
            this.reset_categories();
188
            this.update_images();
189
            this.reset_images();
190
            this.select_image();
191
        },
192

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

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

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

    
223
            } else {
224
                this.image_details.hide();
225
            }
226
        },
227

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
390
            this.update_unavailable_values();
391
        },
392

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

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

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

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

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

    
450
                if (el.hasClass("disabled")) { return }
451

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

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

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

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

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

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

    
485
            disabled = "";
486

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

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

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

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

    
515
        get_valid_flavors: function() {
516
            return this.flavors;
517
        },
518

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

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

    
532
        get: function() {
533
            return {'flavor': this.current_flavor}
534
        }
535

    
536
    });
537

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

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

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

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

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

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

    
598
        update_image_details: function() {
599
            var image = this.parent.get_params().image;
600

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

    
615
        update_layout: function() {
616
            var params = this.parent.get_params();
617

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

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

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

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

    
647
            this.update_image_details();
648
            this.update_flavor_details();
649
        },
650

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

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

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

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

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

    
683
        subtitle: false,
684
        title: "Create new machine",
685

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

    
690
            this.password_view = new views.VMCreationPasswordView();
691

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

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

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

    
707
        },
708

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

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

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

    
754
        close_all: function() {
755
            this.hide();
756
        },
757

    
758
        reset: function() {
759
            this.current_step = 1;
760

    
761
            this.steps[1].reset();
762
            this.steps[2].reset();
763
            this.steps[3].reset();
764

    
765
            this.steps[1].show();
766
            this.steps[2].show();
767
            this.steps[3].show();
768

    
769
            this.submit_btn.removeClass("in-progress");
770
        },
771

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

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

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

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

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

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

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