Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_main_view.js @ 24565655

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

    
12
    var views = snf.views = snf.views || {}
13

    
14
    // shortcuts
15
    var bb = root.Backbone;
16
    var util = snf.util;
17
    
18
    views.ApiInfoView = views.Overlay.extend({
19
        view_id: "api_info_view",
20
        
21
        content_selector: "#api-info-overlay",
22
        css_class: 'overlay-api-info overlay-info',
23
        overlay_id: "overlay-api-info",
24

    
25
        subtitle: "",
26
        title: "API Access",
27

    
28
        beforeOpen: function() {
29
            var cont = this.$(".copy-content p");
30
            var token = $.cookie("X-Auth-Token");
31

    
32
            cont.html("");
33
            cont.text(token);
34

    
35
            var clip = new snf.util.ClipHelper();
36
            cont.parent().append(clip.cont);
37
            clip.setText(token);
38
        },
39

    
40
        onClose: function() {
41
            var cont = this.$(".copy-content p");
42
            var token = $.cookie("X-Auth-Token");
43
            cont.html("");
44
        }
45
    });
46

    
47
    // TODO: implement me
48
    views.NoticeView = views.Overlay.extend({});
49

    
50
    views.MultipleActionsView = views.View.extend({
51
        view_id: "multiple_actions",
52

    
53
        _actions: {},
54
        el: '#multiple_actions_container',
55
        
56
        initialize: function() {
57
            this.actions = {};
58
            this.ns_config = {};
59

    
60
            views.MultipleActionsView.__super__.initialize.call(this);
61

    
62
            this.ns_tpl = this.$(".confirm_multiple_actions-template").clone()
63

    
64
            this.init_handlers();
65
            this.update_layout();
66
            
67
            // for heavy resize/scroll window events
68
            // do it `like a boss` 
69
            this.fix_position = _.throttle(this.fix_position, 100);
70
            this.update_layout = _.throttle(this.update_layout, 100);
71
            this.show_limit = 1;
72

    
73
            this.init_ns("vms", {
74
                msg_tpl:"Your actions will affect 1 machine",
75
                msg_tpl_plural:"Your actions will affect {0} machines",
76
                actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
77
                limit: 1,
78
                cancel_all: function() { snf.storage.vms.reset_pending_actions(); },
79
                do_all: function() { snf.storage.vms.do_all_pending_actions(); }
80
            });
81
            
82
            this.init_ns("nets", {
83
                msg_tpl:"Your actions will affect 1 private network",
84
                msg_tpl_plural:"Your actions will affect {0} private networks",
85
                actions_msg: {confirm: "Confirm all", cancel: "Cancel all"},
86
                limit: 1,
87
                cancel_all: function() { snf.storage.networks.reset_pending_actions(); },
88
                do_all: function() { snf.storage.networks.do_all_pending_actions(); }
89
            });
90

    
91
            this.init_ns("reboots", {
92
                msg_tpl:"1 machine needs to be rebooted for changes to apply.",
93
                msg_tpl_plural:"{0} machines needs to be rebooted for changes to apply.",
94
                actions_msg: {confirm: "Reboot all", cancel: "Cancel all"},
95
                limit: 0,
96
                cancel_all: function() { snf.storage.vms.reset_reboot_required(); },
97
                do_all: function() { snf.storage.vms.do_all_reboots(); }
98
            });
99
        },
100
        
101
        init_ns: function(ns, params) {
102
            this.actions[ns] = {};
103
            var nsconf = this.ns_config[ns] = params || {};
104
            nsconf.cont = $(this.$("#conirm_multiple_cont_template").clone());
105
            nsconf.cont.attr("id", "confirm_multiple_cont_" + ns);
106
            $(this.el).find(".ns-confirms-cont").append(nsconf.cont).addClass(ns);
107
            $(this.el).find(".ns-confirms-cont").append(nsconf.cont).addClass("confirm-ns");
108
            nsconf.cont.find(".msg button.yes").text(
109
                nsconf.actions_msg.confirm).click(_.bind(this.do_all, this, ns));
110
            nsconf.cont.find(".msg button.no").text(
111
                nsconf.actions_msg.cancel).click(_.bind(this.cancel_all, this, ns));
112
        },
113

    
114
        do_all: function(ns) {
115
            this.ns_config[ns].do_all();
116
        },
117

    
118
        cancel_all: function(ns) {
119
            this.ns_config[ns].cancel_all();
120
        },
121

    
122
        init_handlers: function() {
123
            var self = this;
124

    
125
            $(window).resize(_.bind(function(){
126
                this.fix_position();
127
            }, this));
128

    
129
            $(window).scroll(_.bind(function(){
130
                this.fix_position();
131
            }, this));
132

    
133
            storage.vms.bind("change:pending_action", _.bind(this.handle_action_add, this, "vms"));
134
            storage.vms.bind("change:reboot_required", _.bind(this.handle_action_add, this, "reboots"));
135
            storage.networks.bind("change:actions", _.bind(this.handle_action_add, this, "nets"));
136
        },
137

    
138
        handle_action_add: function(type, model, action) {
139
            var actions = this.actions[type];
140
            
141
            // TODO: remove type specific addition code in its own namespace
142
            if (type == "nets") {
143
                if (!action || action.is_empty()) {
144
                    delete actions[model.id];
145
                } else {
146
                    actions[model.id] = {model: model, actions: action.actions};
147
                }
148
            }
149

    
150
            if (type == "vms") {
151
                _.each(actions, function(action) {
152
                    if (action.model.id == model.id) {
153
                        delete actions[action]
154
                    }
155
                });
156

    
157
                var actobject = {};
158
                actobject[action] = [[]];
159
                actions[model.id] = {model: model, actions: actobject};
160
                if (typeof action == "undefined") {
161
                    delete actions[model.id]
162
                }
163
            }
164

    
165
            if (type == "reboots") {
166
                _.each(actions, function(action) {
167
                    if (action.model.id == model.id) {
168
                        delete actions[action]
169
                    }
170
                });
171
                var actobject = {};
172
                actobject['reboot'] = [[]];
173
                actions[model.id] = {model: model, actions: actobject};
174
                if (!action) {
175
                    delete actions[model.id]
176
                }
177
            }
178
            
179
            this.update_layout();
180
        },
181

    
182
        update_actions_content: function(ns) {
183
            var conf = this.ns_config[ns];
184
            conf.cont.find(".details").empty();
185
            conf.cont.find(".msg p").text("");
186
            
187
            var count = 0;
188
            var actionscount = 0;
189
            _.each(this.actions[ns], function(actions, model_id) {
190
                count++;
191
                _.each(actions.actions, function(params, act_name){
192
                    if (params && params.length) {
193
                        actionscount += params.length;
194
                    } else {
195
                        actionscount++;
196
                    }
197
                })
198
                this.total_confirm_actions++;
199
            });
200
            
201
            var limit = conf.limit;
202
            if (ui.main.current_view.view_id == "vm_list") {
203
                limit = 0;
204
            }
205

    
206
            if (actionscount > limit) {
207
                conf.cont.show();
208
                this.confirm_ns_open++;
209
            } else {
210
                conf.cont.hide();
211
            }
212
            
213
            var msg = count > 1 ? conf.msg_tpl_plural : conf.msg_tpl;
214
            conf.cont.find(".msg p").text(msg.format(count));
215

    
216
            return conf.cont;
217
        },
218

    
219
        fix_position: function() {
220
            $('.confirm_multiple').removeClass('fixed');
221
            if (($(this.el).offset().top +$(this.el).height())> ($(window).scrollTop() + $(window).height())) {
222
                $('.confirm_multiple').addClass('fixed');
223
            }
224
        },
225
        
226
        update_layout: function() {
227
            this.confirm_ns_open = 0;
228
            this.total_confirm_actions = 0;
229

    
230
            $(this.el).show();
231
            $(this.el).find("#conirm_multiple_cont_template").hide();
232
            $(this.el).find(".confirm-ns").show();
233
            
234
            _.each(this.ns_config, _.bind(function(params, key) {
235
                this.update_actions_content(key);
236
            }, this));
237

    
238
            if (this.confirm_ns_open > 0) {
239
                $(this.el).show();
240
                this.$(".confirm-all-cont").hide();
241
                this.$(".ns-confirms-cont").show();
242
            } else {
243
                $(this.el).hide();
244
                this.$(".confirm-all-cont").hide();
245
                this.$(".ns-confirms-cont").hide();
246
            }
247

    
248
            $(window).trigger("resize");
249
        }
250
    })
251
    
252
    // menu wrapper view
253
    views.SelectView = views.View.extend({
254
        
255
        initialize: function(view, router) {
256
            this.parent = view;
257
            this.router = router;
258
            this.pane_view_selector = $(".css-tabs");
259
            this.machine_view_selector = $("#view-select");
260
            this.el = $(".css-tabs");
261
            this.title = $(".tab-name");
262

    
263
            this.set_handlers();
264
            this.update_layout();
265

    
266
            views.SelectView.__super__.initialize.apply(this, arguments);
267
        },
268
        
269
        clear_active: function() {
270
            this.pane_view_selector.find("a").removeClass("active");
271
            this.machine_view_selector.find("a").removeClass("activelink");
272
        },
273
        
274
        // intercept menu links
275
        set_handlers: function() {
276
            var self = this;
277
            this.pane_view_selector.find("a").hover(function(){
278
                // FIXME: title from href ? omg
279
                self.title.text($(this).attr("href"));
280
            }, function(){
281
                self.title.text(self.parent.get_title());
282
            });
283

    
284
            this.pane_view_selector.find("a#machines_view_link").click(_.bind(function(ev){
285
                ev.preventDefault();
286
                this.router.vms_index();
287
            }, this))
288
            this.pane_view_selector.find("a#networks_view_link").click(_.bind(function(ev){
289
                ev.preventDefault();
290
                this.router.networks_view();
291
            }, this))
292
            this.pane_view_selector.find("a#disks_view_link").click(_.bind(function(ev){
293
                ev.preventDefault();
294
                this.router.disks_view();
295
            }, this))
296
            
297
            this.machine_view_selector.find("a#machines_view_icon_link").click(_.bind(function(ev){
298
                ev.preventDefault();
299
                var d = $.now();
300
                this.router.vms_icon_view();
301
            }, this))
302
            this.machine_view_selector.find("a#machines_view_list_link").click(_.bind(function(ev){
303
                ev.preventDefault();
304
                this.router.vms_list_view();
305
            }, this))
306
            this.machine_view_selector.find("a#machines_view_single_link").click(_.bind(function(ev){
307
                ev.preventDefault();
308
                this.router.vms_single_view();
309
            }, this))
310
        },
311

    
312
        update_layout: function() {
313
            this.clear_active();
314

    
315
            var pane_index = this.parent.pane_ids[this.parent.current_view_id];
316
            $(this.pane_view_selector.find("a")).removeClass("active");
317
            $(this.pane_view_selector.find("a").get(pane_index)).addClass("active");
318
            
319
            if (this.parent.current_view && this.parent.current_view.vms_view) {
320

    
321
                if (storage.vms.length > 0) {
322
                    this.machine_view_selector.show();
323
                    var machine_index = this.parent.views_ids[this.parent.current_view_id];
324
                    $(this.machine_view_selector.find("a").get(machine_index)).addClass("activelink");
325
                } else {
326
                    this.machine_view_selector.hide();
327
                }
328
            } else {
329
                this.machine_view_selector.hide();
330
            }
331

    
332
        }
333
    });
334

    
335
    views.MainView = views.View.extend({
336
        el: 'body',
337
        view_id: 'main',
338
        
339
        // FIXME: titles belong to SelectView
340
        views_titles: {
341
            'icon': 'machines', 'single': 'machines', 
342
            'list': 'machines', 'networks': 'networks',
343
            'disks': 'disks'
344
        },
345

    
346
        // indexes registry
347
        views_indexes: {0: 'icon', 2:'single', 1: 'list', 3:'networks'},
348
        views_pane_indexes: {0:'single', 1:'networks', 2:'disks'},
349

    
350
        // views classes registry
351
        views_classes: {'icon': views.IconView, 'single': views.SingleView, 
352
            'list': views.ListView, 'networks': views.NetworksView},
353

    
354
        // view ids
355
        views_ids: {'icon':0, 'single':2, 'list':1, 'networks':3},
356

    
357
        // on which pane id each view exists
358
        // machine views (icon,single,list) are all on first pane
359
        pane_ids: {'icon':0, 'single':0, 'list':0, 'networks':1, 'disks':2},
360
    
361
        initialize: function(show_view) {
362
            if (!show_view) { show_view = 'icon' };
363
            
364
            this.router = snf.router;
365
            this.empty_hidden = true;
366
            // fallback to browser error reporting (true for debug)
367
            this.skip_errors = true
368

    
369
            // reset views
370
            this.views = {};
371

    
372
            this.el = $("#app");
373
            // reset main view status
374
            this._loaded = false;
375
            this.status = "Initializing...";
376

    
377
            // initialize handlers
378
            this.init_handlers();
379

    
380
            // identify initial view from user cookies
381
            // this view will be visible after loading of
382
            // main view
383
            this.initial_view = this.session_view();
384

    
385
            views.MainView.__super__.initialize.call(this);
386

    
387
            $(window).focus(_.bind(this.handle_window_focus, this, "focus"));
388
            $(window).blur(_.bind(this.handle_window_focus, this, "out"));
389

    
390
            this.focused = true;
391
        },
392

    
393
        handle_window_focus: function(focus) {
394
            if (!snf.config.delay_on_blur) { return };
395

    
396
            if (focus === "focus") {
397
                this.focused = true;
398
                this.set_interval_timeouts(snf.config.update_interval);
399
            } else {
400
                this.focused = false;
401
                this.set_interval_timeouts(snf.config.blur_delay);
402
            }
403
        },
404

    
405
        set_interval_timeouts: function(time) {
406
            _.each([this._networks, this._vms], function(fetcher){
407
                if (!fetcher) { return };
408
                fetcher.timeout = time;
409
                fetcher.stop().start();
410
            })
411
        },
412
        
413
        vms_handlers_registered: false,
414

    
415
        // register event handlers
416
        // 
417
        // vms storage events to identify if vms list 
418
        // is empty and display empty view if user viewing
419
        // a machine view
420
        //
421
        // api/ui error event handlers
422
        init_handlers: function() {
423
            // vm handlers
424
            storage.vms.bind("remove", _.bind(this.check_empty, this));
425
            storage.vms.bind("add", _.bind(this.check_empty, this));
426
            storage.vms.bind("change:status", _.bind(this.check_empty, this));
427
            storage.vms.bind("reset", _.bind(this.check_empty, this));
428
            
429
            // api calls handlers
430
            synnefo.api.bind("error", _.bind(this.handle_api_error, this));
431
            synnefo.api.bind("change:error_state", _.bind(this.handle_api_error_state, this));
432
            synnefo.ui.bind("error", _.bind(this.handle_ui_error, this));
433
        },
434
        
435
        handle_api_error_state: function(state) {
436
            if (snf.api.error_state === snf.api.STATES.ERROR) {
437
                this.stop_intervals();
438
            } else {
439
                if (this.intervals_stopped) {
440
                    this.update_intervals();
441
                }
442
            }
443
        },
444
        
445
        handle_api_error: function(args) {
446
            if (arguments.length == 1) { arguments = _.toArray(arguments[0])};
447

    
448
            if (!_.last(arguments).display) {
449
                return;
450
            }
451

    
452
            this.error_state = true;
453
            
454
            var xhr = arguments[0];
455
            var args = util.parse_api_error.apply(util, arguments);
456
            
457
            // force logout if UNAUTHORIZED request arrives
458
            if (args.code == 401) { snf.ui.logout(); return };
459

    
460
            var error_entry = [args.ns, args.code, args.message, args.type, args.details, args];
461
            this.error_view.show_error.apply(this.error_view, error_entry);
462
        },
463

    
464
        handle_ui_error: function(data) {
465
            var msg = data.msg, code = data.code, err_obj = data.error;
466
            error = msg + "<br /><br />" + snf.util.stacktrace().replace("at", "<br /><br />at");
467
            params = { title: "UI error", extra_details: data.extra };
468
            params.allow_close = data.extra.allow_close === undefined ? true : data.extra.allow_close;
469
            this.error_view.show_error("UI", -1, msg, "JS Exception", error, params);
470
        },
471

    
472
        init_overlays: function() {
473
            this.create_vm_view = new views.CreateVMView();
474
            this.api_info_view = new views.ApiInfoView();
475
            //this.notice_view = new views.NoticeView();
476
        },
477
        
478
        show_loading_view: function() {
479
            $("#container #content").hide();
480
            $("#loading-view").show();
481
        },
482

    
483
        hide_loading_view: function() {
484
            $("#container #content").show();
485
            $("#loading-view").hide();
486
            $(".css-panes").show();
487
        },
488
        
489
        items_to_load: 4,
490
        completed_items: 0,
491
        check_status: function(loaded) {
492
            this.completed_items++;
493
            // images, flavors loaded
494
            if (this.completed_items == 2) {
495
                this.load_nets_and_vms();
496
            }
497

    
498
            if (this.completed_items == this.items_to_load) {
499
                this.update_status("Rendering layout...");
500
                var self = this;
501
                window.setTimeout(function(){
502
                    self.after_load();
503
                }, 10)
504
            }
505
        },
506

    
507
        load_nets_and_vms: function() {
508
            var self = this;
509
            this.update_status("Loading vms...");
510
            storage.vms.fetch({refresh:true, update:false, success: function(){
511
                self.update_status("VMS Loaded.");
512
                self.check_status();
513
            }});
514

    
515
            this.update_status("Loading networks...");
516
            storage.networks.fetch({refresh:true, update:false, success: function(){
517
                self.update_status("Networks loaded.");
518
                self.check_status();
519
            }});
520
        },  
521

    
522
        init_intervals: function() {
523
            this._networks = storage.networks.get_fetcher(snf.config.update_interval, 
524
                                                          snf.config.update_interval / 2, 
525
                                                          1, true, undefined);
526
            this._vms = storage.vms.get_fetcher(snf.config.update_interval, 
527
                                                snf.config.update_interval / 2, 
528
                                                1, true, undefined);
529
        },
530

    
531
        stop_intervals: function() {
532
            if (this._networks) { this._networks.stop(); }
533
            if (this._vms) { this._vms.stop(); }
534
            this.intervals_stopped = true;
535
        },
536

    
537
        update_intervals: function() {
538
            if (this._networks) {
539
                this._networks.stop();
540
                this._networks.start();
541
            } else {
542
                this.init_intervals();
543
            }
544

    
545
            if (this._vms) {
546
                this._vms.stop();
547
                this._vms.start();
548
            } else {
549
                this.init_intervals();
550
            }
551

    
552
            this.intervals_stopped = false;
553
        },
554

    
555
        after_load: function() {
556
            var self = this;
557
            this.update_status("Setting vms update interval...");
558
            this.init_intervals();
559
            this.update_intervals();
560
            this.update_status("Showing initial view...");
561
            
562
            // bypass update_hidden_views in initial view
563
            // rendering to force all views to get render
564
            // on their creation
565
            var uhv = snf.config.update_hidden_views;
566
            snf.config.update_hidden_views = true;
567
            this.initialize_views();
568
            snf.config.update_hidden_views = uhv;
569

    
570
            window.setTimeout(function() {
571
                self.update_status("Initializing overlays...");
572
                self.load_initialize_overlays();
573
            }, 20);
574
        },
575

    
576
        load_initialize_overlays: function() {
577
            this.init_overlays();
578
            // display initial view
579
            this.loaded = true;
580
            
581
            // application start point
582
            this.show_initial_view();
583

    
584
            this.check_empty();
585
        },
586

    
587
        load: function() {
588
            this.error_view = new views.ErrorView();
589
            this.feedback_view = new views.FeedbackView();
590
            this.invitations_view = new views.InvitationsView();
591
            var self = this;
592
            // initialize overlay views
593
            
594
            // display loading message
595
            this.show_loading_view();
596
            // sync load initial data
597
            this.update_status("Loading images...");
598
            storage.images.fetch({refresh:true, update:false, success: function(){
599
                self.check_status()
600
            }});
601
            this.update_status("Loading flavors...");
602
            storage.flavors.fetch({refresh:true, update:false, success:function(){
603
                self.check_status()
604
            }});
605
        },
606

    
607
        update_status: function(msg) {
608
            this.log.debug(msg)
609
            this.status = msg;
610
            $("#loading-view .info").removeClass("hidden")
611
            $("#loading-view .info").text(this.status);
612
        },
613

    
614
        initialize_views: function() {
615
            this.select_view = new views.SelectView(this, this.router);
616
            this.empty_view = new views.EmptyView();
617
            this.metadata_view = new views.MetadataView();
618
            this.multiple_actions_view = new views.MultipleActionsView();
619
            
620
            this.add_view("icon");
621
            this.add_view("list");
622
            this.add_view("single");
623
            this.add_view("networks");
624

    
625
            this.init_menu();
626
        },
627

    
628
        init_menu: function() {
629
            $(".usermenu .invitations").click(_.bind(function(){
630
                this.invitations_view.show();
631
            }, this));
632
            $(".usermenu .feedback").click(_.bind(function(){
633
                this.feedback_view.show();
634
            }, this));
635
        },
636
        
637
        // initial view based on user cookie
638
        show_initial_view: function() {
639
          this.set_vm_view_handlers();
640
          this.hide_loading_view();
641
          
642
          bb.history.start();
643

    
644
          this.trigger("initial");
645
        },
646

    
647
        show_vm_details: function(vm) {
648
            this.router.vm_details_view(vm.id);
649
        },
650

    
651
        set_vm_view_handlers: function() {
652
            var self = this;
653
            $("#createcontainer #create").click(function(e){
654
                e.preventDefault();
655
                self.router.vm_create_view();
656
            })
657
        },
658

    
659
        check_empty: function() {
660
            if (!this.loaded) { return }
661
            if (storage.vms.length == 0) {
662
                this.show_view("machines");
663
                this.router.show_welcome();
664
                this.empty_hidden = false;
665
            } else {
666
                this.hide_empty();
667
            }
668
        },
669

    
670
        show_empty: function() {
671
            if (!this.empty_hidden) { return };
672
            $("#machines-pane-top").addClass("empty");
673

    
674
            this.$(".panes").hide();
675
            this.$("#machines-pane").show();
676

    
677
            this.hide_views([]);
678
            this.empty_hidden = false;
679
            this.empty_view.show();
680
            this.select_view.update_layout();
681
            this.empty_hidden = false;
682
        },
683

    
684
        hide_empty: function() {
685
            if (this.empty_hidden) { return };
686
            $("#machines-pane-top").removeClass("empty");
687

    
688
            this.empty_view.hide(true);
689
            this.router.vms_index();
690
            this.empty_hidden = true;
691
            this.select_view.update_layout();
692
        },
693
        
694
        get_title: function(view_id) {
695
            var view_id = view_id || this.current_view_id;
696
            return this.views_titles[view_id];
697
        },
698

    
699
        // return class object for the given view or false if
700
        // the view is not registered
701
        get_class_for_view: function (view_id) {
702
            if (!this.views_classes[view_id]) {
703
                return false;
704
            }
705
            return this.views_classes[view_id];
706
        },
707

    
708
        view: function(view_id) {
709
            return this.views[view_id];
710
        },
711

    
712
        add_view: function(view_id) {
713
            if (!this.views[view_id]) {
714
                var cls = this.get_class_for_view(view_id);
715
                if (this.skip_errors) {
716
                    this.views[view_id] = new cls();
717
                    $(this.views[view_id]).bind("resize", _.bind(function() {
718
                        window.positionFooter();
719
                        this.multiple_actions_view.fix_position();
720
                    }, this));
721
                } else {
722
                    // catch ui errors
723
                    try {
724
                        this.views[view_id] = new cls();
725
                        $(this.views[view_id]).bind("resize", _.bind(function() {
726
                            window.positionFooter();
727
                            this.multiple_actions_view.fix_position();
728
                        }, this));
729
                    } catch (err) {snf.ui.trigger_error(-1, "Cannot add view", err)}
730
                }
731
            } else {
732
            }
733

    
734
            if (this.views[view_id].vms_view) {
735
                this.views[view_id].metadata_view = this.metadata_view;
736
            }
737
            return this.views[view_id];
738
        },
739
            
740
        hide_views: function(skip) {
741
            _.each(this.views, function(view) {
742
                if (skip.indexOf(view) === -1) {
743
                    $(view.el).hide();
744
                }
745
            }, this)
746
        },
747
        
748
        get: function(view_id) {
749
            return this.views[view_id];
750
        },
751
        
752
        session_view: function() {
753
            if (this.pane_view_from_session() > 0) {
754
                return this.views_pane_indexes[this.pane_view_from_session()];
755
            } else {
756
                return this.views_indexes[this.machine_view_from_session()];
757
            }
758
        },
759

    
760
        pane_view_from_session: function() {
761
            return $.cookie("pane_view") || 0;
762
        },
763

    
764
        machine_view_from_session: function() {
765
            return $.cookie("machine_view") || 0;
766
        },
767

    
768
        update_session: function() {
769
            $.cookie("pane_view", this.pane_ids[this.current_view_id]);
770
            if (this.current_view.vms_view) {
771
                $.cookie("machine_view", this.views_ids[this.current_view_id]);
772
            }
773
        },
774

    
775
        identify_view: function(view_id) {
776
            // machines view_id is an alias to
777
            // one of the 3 machines view
778
            // identify which one (if no cookie set defaults to icon)
779
            if (view_id == "machines") {
780
                var index = this.machine_view_from_session();
781
                view_id = this.views_indexes[index];
782
            }
783
            return view_id;
784
        },
785
        
786
        // switch to current view pane
787
        // if differs from the visible one
788
        show_view_pane: function() {
789
            if (this.current_view.pane != this.current_pane) {
790
                $(this.current_view.pane).show();
791
                $(this.current_pane).hide();
792
                this.current_pane = this.current_view.pane;
793
            }
794
        },
795
        
796
        show_view: function(view_id) {
797
            //var d = new Date;
798
            var ret = this._show_view(view_id);
799
            //console.log((new Date)-d)
800
            return ret;
801
        },
802

    
803
        _show_view: function(view_id) {
804
                // same view, visible
805
                // get out of here asap
806
                if (this.current_view && 
807
                    this.current_view.id == view_id && 
808
                    this.current_view.visible()) {
809
                    return;
810
                }
811
                
812
                // choose proper view_id
813
                view_id = this.identify_view(view_id);
814

    
815
                // add/create view and update current view
816
                var view = this.add_view(view_id);
817
                
818
                // set current view
819
                this.current_view = view;
820
                this.current_view_id = view_id;
821

    
822
                // hide all other views
823
                this.hide_views([this.current_view]);
824
                
825
                // FIXME: depricated
826
                $(".large-spinner").remove();
827

    
828
                storage.vms.reset_pending_actions();
829
                storage.networks.reset_pending_actions();
830
                storage.vms.stop_stats_update();
831

    
832
                // show current view
833
                this.show_view_pane();
834
                view.show();
835
                
836
                // update menus
837
                if (this.select_view) {
838
                    this.select_view.update_layout();
839
                }
840
                this.current_view.__update_layout();
841

    
842
                // update cookies
843
                this.update_session();
844
                
845
                // machines view subnav
846
                if (this.current_view.vms_view) {
847
                    $("#machines-pane").show();
848
                } else {
849
                    $("#machines-pane").hide();
850
                }
851
                
852
                // fix footer position
853
                // TODO: move footer handlers in
854
                // main view (from home.html)
855
                if (window.positionFooter) {
856
                    window.positionFooter();
857
                }
858

    
859
                // trigger view change event
860
                this.trigger("view:change", this.current_view.view_id);
861
                this.select_view.title.text(this.get_title());
862
                $(window).trigger("view:change");
863
                return view;
864
        },
865

    
866
        reset_vm_actions: function() {
867
        
868
        },
869
        
870
        // identify current view
871
        // based on views element visibility
872
        current_view_id: function() {
873
            var found = false;
874
            _.each(this.views, function(key, value) {
875
                if (value.visible()) {
876
                    found = value;
877
                }
878
            })
879
            return found;
880
        }
881

    
882
    });
883

    
884
    snf.ui.main = new views.MainView();
885
    
886
    snf.ui.logout = function() {
887
        $.cookie("X-Auth-Token", null);
888
        if (snf.config.logout_url !== undefined)
889
        {
890
            window.location = snf.config.logout_url;
891
        } else {
892
            window.location.reload();
893
        }
894
    }
895

    
896
    snf.ui.init = function() {
897
        if (snf.config.handle_window_exceptions) {
898
            window.onerror = function(msg, file, line) {
899
                snf.ui.trigger_error("CRITICAL", msg, {}, { file:file + ":" + line, allow_close: false });
900
            };
901
        }
902
        snf.ui.main.load();
903
    }
904

    
905
})(this);