Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_create_view.js @ 1325fc64

History | View | Annotate | Download (31 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
            try { delete this.clipboard } catch (err) { console.log(err) };
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
                this.copy.hide();
62
            }
63
        },
64

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

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

    
74

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
152
            return this.images;
153
        },
154

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
391
            this.update_unavailable_values();
392
        },
393

    
394
        update_unavailable_values: function() {
395
            if (!this.current_image) { this.unavailable_values = {disk:[], ram:[], cpu:[]}; return };
396
            this.unavailable_values = storage.flavors.unavailable_values_for_image(this.current_image);
397
        },
398
        
399
        flavor_is_valid: function(flv) {
400
            if (!flv) { return false };
401
            var existing = storage.flavors.get_flavor(flv.get("cpu"), flv.get("ram"), flv.get("disk"), this.flavors);
402
            if (!existing) { return false };
403
            if (this.unavailable_values && this.unavailable_values.disk.indexOf(flv.get("disk") > -1)) {
404
                return false
405
            }
406
            return true;
407
        },
408
            
409
        set_valid_current_for: function(t, val) {
410
            var found = this.flavors[0];
411
            _.each(this.flavors, function(flv) {
412
                if (flv.get(t) == val) {
413
                    found = flv;
414
                }
415
            });
416

    
417
            this.set_current(found);
418
        },
419

    
420
        set_current: function(flv) {
421

    
422
            if (!flv) {
423
                // user clicked on invalid combination
424
                // force the first available choice for the
425
                // type of option he last clicked
426
                this.set_valid_current_for.apply(this, this.last_choice);
427
                return;
428
            }
429

    
430
            this.current_flavor = flv;
431
            this.trigger("change");
432
            this.update_selected_flavor();
433
            this.update_selected_predefined();
434
        },
435
        
436
        select_default_flavor: function() {
437
               
438
        },
439

    
440
        update_selected_from_ui: function() {
441
            this.set_current(this.ui_selected());
442
        },
443
        
444
        update_disabled_flavors: function() {
445
            this.$(".flavor-options.disk li").removeClass("disabled");
446
            if (!this.unavailable_values) { return }
447
            
448
            this.$("#create-vm-flavor-options .flavor-options.disk li").each(_.bind(function(i, el){
449
                var el_value = $(el).data("value") * 1000;
450
                if (this.unavailable_values.disk.indexOf(el_value) > -1) {
451
                    $(el).addClass("disabled");
452
                };
453
            }, this));
454
        },
455

    
456
        create_flavors: function() {
457
            var flavors = this.get_active_flavors();
458
            var valid_flavors = this.get_valid_flavors();
459
            this.__added_flavors = {'cpu':[], 'ram':[], 'disk':[]};
460

    
461
            _.each(flavors, _.bind(function(flv){
462
                this.add_flavor(flv);
463
            }, this));
464
            
465
            var self = this;
466
            this.$(".flavor-options li.option").click(function(){
467
                var el = $(this);
468

    
469
                if (el.hasClass("disabled")) { return }
470

    
471
                el.parent().find(".option").removeClass("selected");
472
                el.addClass("selected");
473
                
474
                if (el.hasClass("mem")) { self.last_choice = ["ram", $(this).data("value")] }
475
                if (el.hasClass("cpu")) { self.last_choice = ["cpu", $(this).data("value")] }
476
                if (el.hasClass("disk")) { self.last_choice = ["disk", $(this).data("value")] }
477

    
478
                self.update_selected_from_ui();
479
            })
480
        },
481
        
482
        ui_selected: function() {
483
            var args = [this.$(".option.cpu.selected").data("value"), 
484
                this.$(".option.mem.selected").data("value"), 
485
                this.$(".option.disk.selected").data("value"),
486
            this.flavors];
487

    
488
            var flv = storage.flavors.get_flavor.apply(storage.flavors, args);
489
            return flv;
490
        },
491

    
492
        update_selected_flavor: function() {
493
            var flv = this.current_flavor;
494
            this.$(".option").removeClass("selected");
495

    
496
            this.$(".option.cpu.value-" + flv.get("cpu")).addClass("selected");
497
            this.$(".option.mem.value-" + flv.get("ram")).addClass("selected");
498
            this.$(".option.disk.value-" + flv.get("disk")).addClass("selected");
499
        },
500
        
501
        __added_flavors: {'cpu':[], 'ram':[], 'disk':[]},
502
        add_flavor: function(flv) {
503
            var values = {'cpu': flv.get('cpu'), 'mem': flv.get('ram'), 'disk': flv.get('disk')};
504

    
505
            disabled = "";
506
            
507
            if (this.__added_flavors.cpu.indexOf(values.cpu) == -1) {
508
                var cpu = $(('<li class="option cpu value-{0} {1}">' + 
509
                             '<span class="value">{0}</span>' + 
510
                             '<span class="metric">x</span></li>').format(values.cpu, disabled)).data('value', values.cpu);
511
                this.cpus.append(cpu);
512
                this.__added_flavors.cpu.push(values.cpu);
513
            }
514

    
515
            if (this.__added_flavors.ram.indexOf(values.mem) == -1) {
516
                var mem = $(('<li class="option mem value-{0}">' + 
517
                             '<span class="value">{0}</span>' + 
518
                             '<span class="metric">MB</span></li>').format(values.mem)).data('value', values.mem);
519
                this.mems.append(mem);
520
                this.__added_flavors.ram.push(values.mem);
521
            }
522

    
523
            if (this.__added_flavors.disk.indexOf(values.disk) == -1) {
524
                var disk = $(('<li class="option disk value-{0}">' + 
525
                              '<span class="value">{0}</span>' + 
526
                              '<span class="metric">GB</span></li>').format(values.disk)).data('value', values.disk);
527
                this.disks.append(disk);
528
                this.__added_flavors.disk.push(values.disk)
529
            }
530

    
531
            
532
        },
533
        
534
        get_active_flavors: function() {
535
            return storage.flavors.active();
536
        },
537

    
538
        get_valid_flavors: function() {
539
            return this.flavors;
540
        },
541

    
542
        update_layout: function() {
543
            this.update_selected_flavor();
544
            this.update_disabled_flavors();
545
        },
546

    
547
        reset: function() {
548
            this.current_image = storage.images.at(0);
549
            this.flavors = [];
550
            this.flavors_data = {'cpu':[], 'mem':[], 'disk':[]};
551
            this.update_flavors_data();
552
        },
553

    
554
        get: function() {
555
            return {'flavor': this.current_flavor}
556
        }
557

    
558
    });
559

    
560
    views.CreateSubmitView = views.CreateVMStepView.extend({
561
        step: 3,
562
        initialize: function() {
563
            views.CreateSubmitView.__super__.initialize.apply(this, arguments);
564
            this.roles = this.$("li.predefined-meta.role .values");
565
            this.confirm = this.$(".confirm-params ul");
566
            this.name = this.$("input.rename-field");
567
            this.name_changed = false;
568
            this.init_suggested_roles();
569
            this.init_handlers();
570
        },
571

    
572
        init_suggested_roles: function() {
573
            var cont = this.roles;
574
            cont.empty();
575
            
576
            // TODO: get suggested from snf.api.conf
577
            _.each(window.SUGGESTED_ROLES, function(r){
578
                var el = $('<span class="val">{0}</span>'.format(r));
579
                el.data("value", r);
580
                cont.append(el);
581
                el.click(function() {
582
                    $(this).parent().find(".val").removeClass("selected");
583
                    $(this).toggleClass("selected");
584
                })
585
            })
586
        },
587

    
588
        init_handlers: function() {
589
            this.name.bind("keypress", _.bind(function(e) {
590
                this.name_changed = true;
591
                if (e.keyCode == 13) { this.parent.submit() };    
592
            }, this));
593

    
594
            this.name.bind("click", _.bind(function() {
595
                if (!this.name_changed) {
596
                    this.name.val("");
597
                }
598
            }, this))
599
        },
600

    
601
        show: function() {
602
            views.CreateSubmitView.__super__.show.apply(this, arguments);
603
            this.update_layout();
604
        },
605
        
606
        update_flavor_details: function() {
607
            var flavor = this.parent.get_params().flavor;
608

    
609
            function set_detail(sel, key) {
610
                var val = key;
611
                if (key == undefined) { val = flavor.get(sel) };
612
                this.$(".confirm-cont.flavor .flavor-" + sel + " .value").text(val)
613
            }
614
            
615
            set_detail("cpu", flavor.get("cpu") + "x");
616
            set_detail("ram", flavor.get("ram") + " MB");
617
            set_detail("disk", util.readablizeBytes(flavor.get("disk") * 1024 * 1024 * 1024));
618
        },
619

    
620
        update_image_details: function() {
621
            var image = this.parent.get_params().image;
622

    
623
            function set_detail(sel, key) {
624
                var val = key;
625
                if (key == undefined) { val = image.get(sel) };
626
                this.$(".confirm-cont.image .image-" + sel + " .value").text(val)
627
            }
628
            
629
            set_detail("description");
630
            set_detail("name");
631
            set_detail("os", _(image.get("OS")).capitalize());
632
            set_detail("gui", image.get("GUI"));
633
            set_detail("size", util.readablizeBytes(image.get_size() * 1024 * 1024));
634
            set_detail("kernel");
635
        },
636

    
637
        update_layout: function() {
638
            var params = this.parent.get_params();
639

    
640
            if (!params.image) { return }
641
            var vm_name = "My {0} server".format(params.image.get("name"));
642
            var orig_name = vm_name;
643
            
644
            var existing = true;
645
            var j = 0;
646

    
647
            while (existing && !this.name_changed) {
648
                var existing = storage.vms.select(function(vm){return vm.get("name") == vm_name}).length
649
                if (existing) {
650
                    j++;
651
                    vm_name = orig_name + " " + j;
652
                }
653
            }
654
            if (!_(this.name.val()).trim() || !this.name_changed) {
655
                this.name.val(vm_name);
656
            }
657

    
658
            this.confirm.find("li.image .value").text(params.flavor.get("image"));
659
            this.confirm.find("li.cpu .value").text(params.flavor.get("cpu") + "x");
660
            this.confirm.find("li.mem .value").text(params.flavor.get("ram"));
661
            this.confirm.find("li.disk .value").text(params.flavor.get("disk"));
662

    
663
            if (!this.name_changed && this.parent.visible()) {
664
                if (!$.browser.msie && !$.browser.opera) {
665
                    this.$("#create-vm-name").select();
666
                } else {
667
                    window.setTimeout(_.bind(function(){
668
                        this.$("#create-vm-name").select();
669
                    }, this), 400)
670
                }
671
            }
672
            
673
            var img = snf.ui.helpers.os_icon_path(params.image.get("OS"))
674
            this.name.css({backgroundImage:"url({0})".format(img)})
675

    
676
            this.update_image_details();
677
            this.update_flavor_details();
678
        },
679

    
680
        reset: function() {
681
            this.roles.find(".val").removeClass("selected");
682
            this.name_changed = false;
683
            this.update_layout();
684
        },
685

    
686
        get_meta: function() {
687
            if (this.roles.find(".selected").length == 0) {
688
                return false;
689
            }
690

    
691
            var role = $(this.roles.find(".selected").get(0)).data("value");
692
            return {'Role': role }
693
        },
694

    
695
        get: function() {
696
            var val = {'name': this.name.val() };
697
            if (this.get_meta()) {
698
                val.metadata = this.get_meta();
699
            }
700
            
701
            return val;
702
        }
703
    });
704

    
705
    views.CreateVMView = views.Overlay.extend({
706
        
707
        view_id: "create_vm_view",
708
        content_selector: "#createvm-overlay-content",
709
        css_class: 'overlay-createvm overlay-info',
710
        overlay_id: "metadata-overlay",
711

    
712
        subtitle: false,
713
        title: "Create new machine",
714

    
715
        initialize: function(options) {
716
            views.CreateVMView.__super__.initialize.apply(this);
717
            this.current_step = 1;
718

    
719
            this.password_view = new views.VMCreationPasswordView();
720

    
721
            this.steps = [];
722
            this.steps[1] = new views.CreateImageSelectView(this);
723
            this.steps[1].bind("change", _.bind(function(data) {this.trigger("image:change", data)}, this));
724

    
725
            this.steps[2] = new views.CreateFlavorSelectView(this);
726
            this.steps[3] = new views.CreateSubmitView(this);
727

    
728
            this.cancel_btn = this.$(".create-controls .cancel");
729
            this.next_btn = this.$(".create-controls .next");
730
            this.prev_btn = this.$(".create-controls .prev");
731
            this.submit_btn = this.$(".create-controls .submit");
732

    
733
            this.history = this.$(".steps-history");
734
            this.history_steps = this.$(".steps-history .steps-history-step");
735
            
736
            this.init_handlers();
737
        },
738

    
739
        init_handlers: function() {
740
            var self = this;
741
            this.next_btn.click(_.bind(function(){
742
                this.set_step(this.current_step + 1);
743
                this.update_layout();
744
            }, this))
745
            this.prev_btn.click(_.bind(function(){
746
                this.set_step(this.current_step - 1);
747
                this.update_layout();
748
            }, this))
749
            this.cancel_btn.click(_.bind(function(){
750
                this.close_all();
751
            }, this))
752
            this.submit_btn.click(_.bind(function(){
753
                this.submit();
754
            }, this))
755
            
756
            this.history.find(".completed").live("click", function() {
757
                var step = parseInt($(this).attr("id").replace("vm-create-step-history-", ""));
758
                self.set_step(step);
759
                self.update_layout();
760
            })
761
        },
762

    
763
        set_step: function(st) {
764
        },
765
        
766
        validate: function(data) {
767
            if (_(data.name).trim() == "") {
768
                this.$(".form-field").addClass("error");
769
                return false;
770
            } else {
771
                return true;
772
            }
773
        },
774

    
775
        submit: function() {
776
            if (this.submiting) { return };
777
            var data = this.get_params();
778
            var meta = {};
779
            if (this.validate(data)) {
780
                this.submit_btn.addClass("in-progress");
781
                this.submiting = true;
782
                if (data.metadata) { meta = data.metadata; }
783
                storage.vms.create(data.name, data.image, data.flavor, meta, {}, _.bind(function(data){
784
                    this.close_all();
785
                    this.password_view.show(data.server.adminPass, data.server.id);
786
                    this.submiting = false;
787
                }, this));
788
            }
789
        },
790

    
791
        close_all: function() {
792
            this.hide();
793
        },
794

    
795
        reset: function() {
796
            this.current_step = 1;
797

    
798
            this.steps[1].reset();
799
            this.steps[2].reset();
800
            this.steps[3].reset();
801

    
802
            this.steps[1].show();
803
            this.steps[2].show();
804
            this.steps[3].show();
805

    
806
            this.submit_btn.removeClass("in-progress");
807
        },
808

    
809
        onShow: function() {
810
            this.reset()
811
            this.update_layout();
812
        },
813

    
814
        update_layout: function() {
815
            this.show_step(this.current_step);
816
            this.current_view.update_layout();
817
        },
818

    
819
        beforeOpen: function() {
820
            this.submiting = false;
821
            this.reset();
822
            this.current_step = 1;
823
            this.$(".steps-container").css({"margin-left":0 + "px"});
824
            this.show_step(1);
825
        },
826
        
827
        set_step: function(step) {
828
            if (step <= 1) {
829
                step = 1
830
            }
831
            if (step > this.steps.length - 1) {
832
                step = this.steps.length - 1;
833
            }
834
            this.current_step = step;
835
        },
836

    
837
        show_step: function(step) {
838
            this.current_view = this.steps[step];
839
            this.update_controls();
840

    
841
            this.steps[step].show();
842
            var width = this.el.find('.container').width();
843
            var left = (step -1) * width * -1;
844
            this.$(".steps-container").animate({"margin-left": left + "px"}, 300);
845

    
846
            this.update_steps_history();
847
        },
848

    
849
        update_steps_history: function() {
850
            var self = this;
851
            function get_step(s) {
852
                return self.history.find(".step" + s + "h");
853
            }
854
            
855
            var current_step = parseInt(this.current_view.step);
856
            _.each(this.steps, function(stepv) {
857
                var step = parseInt(stepv.step);
858
                get_step(step).removeClass("completed").removeClass("current");
859
                if (step == current_step) {
860
                    get_step(step).removeClass("completed").addClass("current");
861
                }
862
                if (step < current_step) {
863
                    get_step(step).removeClass("current").addClass("completed");
864
                }
865
            });
866
        },
867

    
868
        update_controls: function() {
869
            var step = this.current_step;
870
            if (step == 1) {
871
                this.prev_btn.hide();
872
                this.cancel_btn.show();
873
            } else {
874
                this.prev_btn.show();
875
                this.cancel_btn.hide();
876
            }
877
            
878
            if (step == this.steps.length - 1) {
879
                this.next_btn.hide();
880
                this.submit_btn.show();
881
            } else {
882
                this.next_btn.show();
883
                this.submit_btn.hide();
884
            }
885
        },
886

    
887
        get_params: function() {
888
            return _.extend({}, this.steps[1].get(), this.steps[2].get(), this.steps[3].get());
889
        }
890
    });
891
    
892
})(this);
893