Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_main_view.js @ 101e6604

History | View | Annotate | Download (30.9 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) {
256
            this.parent = view;
257

    
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.parent.show_view("machines");
287
            }, this))
288
            this.pane_view_selector.find("a#networks_view_link").click(_.bind(function(ev){
289
                ev.preventDefault();
290
                this.parent.show_view("networks");
291
            }, this))
292
            this.pane_view_selector.find("a#disks_view_link").click(_.bind(function(ev){
293
                ev.preventDefault();
294
                this.parent.show_view("disks");
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.parent.show_view("icon");
301
            }, this))
302
            this.machine_view_selector.find("a#machines_view_list_link").click(_.bind(function(ev){
303
                ev.preventDefault();
304
                this.parent.show_view("list");
305
            }, this))
306
            this.machine_view_selector.find("a#machines_view_single_link").click(_.bind(function(ev){
307
                ev.preventDefault();
308
                this.parent.show_view("single");
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.empty_hidden = true;
365
            // fallback to browser error reporting (true for debug)
366
            this.skip_errors = true
367

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

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

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

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

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

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

    
389
            this.focused = true;
390
        },
391

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
551
            this.intervals_stopped = false;
552
        },
553

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

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

    
575
        load_initialize_overlays: function() {
576
            this.init_overlays();
577
            // display initial view
578
            this.loaded = true;
579
            this.show_initial_view();
580
            this.check_empty();
581
        },
582

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

    
603
        update_status: function(msg) {
604
            this.log.debug(msg)
605
            this.status = msg;
606
            $("#loading-view .info").removeClass("hidden")
607
            $("#loading-view .info").text(this.status);
608
        },
609

    
610
        initialize_views: function() {
611
            this.empty_view = new views.EmptyView();
612
            this.select_view = new views.SelectView(this);
613
            this.metadata_view = new views.MetadataView();
614
            this.multiple_actions_view = new views.MultipleActionsView();
615
            
616
            this.add_view("icon");
617
            this.add_view("list");
618
            this.add_view("single");
619
            this.add_view("networks");
620

    
621
            this.init_menu();
622
        },
623

    
624
        init_menu: function() {
625
            $(".usermenu .invitations").click(_.bind(function(){
626
                this.invitations_view.show();
627
            }, this));
628
            $(".usermenu .feedback").click(_.bind(function(){
629
                this.feedback_view.show();
630
            }, this));
631
        },
632
        
633
        // initial view based on user cookie
634
        show_initial_view: function() {
635
          this.set_vm_view_handlers();
636
          this.hide_loading_view();
637
          this.show_view(this.initial_view);
638
          this.trigger("initial");
639
        },
640

    
641
        show_vm_details: function(vm) {
642
            snf.ui.main.show_view("single")
643
            snf.ui.main.current_view.show_vm(vm);
644
        },
645

    
646
        set_vm_view_handlers: function() {
647
            $("#createcontainer #create").click(_.bind(function(){
648
                this.create_vm_view.show();
649
            }, this))
650
        },
651

    
652
        check_empty: function() {
653
            if (!this.loaded) { return }
654
            if (storage.vms.length == 0) {
655
                this.show_view("machines");
656
                this.show_empty();
657
                this.empty_hidden = false;
658
            } else {
659
                this.hide_empty();
660
            }
661
        },
662

    
663
        show_empty: function() {
664
            if (!this.empty_hidden) { return };
665
            $("#machines-pane-top").addClass("empty");
666

    
667
            this.$(".panes").hide();
668
            this.$("#machines-pane").show();
669

    
670
            this.hide_views([]);
671
            this.empty_hidden = false;
672
            this.empty_view.show();
673
            this.select_view.update_layout();
674
            this.empty_hidden = false;
675
        },
676

    
677
        hide_empty: function() {
678
            if (this.empty_hidden) { return };
679
            $("#machines-pane-top").removeClass("empty");
680

    
681
            this.empty_view.hide(true);
682
            if (this.current_view && !this.current_view.visible()) { 
683
                this.current_view.show(); 
684
            }
685
            this.empty_hidden = true;
686
            this.select_view.update_layout();
687
        },
688
        
689
        get_title: function(view_id) {
690
            var view_id = view_id || this.current_view_id;
691
            return this.views_titles[view_id];
692
        },
693

    
694
        // return class object for the given view or false if
695
        // the view is not registered
696
        get_class_for_view: function (view_id) {
697
            if (!this.views_classes[view_id]) {
698
                return false;
699
            }
700
            return this.views_classes[view_id];
701
        },
702

    
703
        view: function(view_id) {
704
            return this.views[view_id];
705
        },
706

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

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

    
755
        pane_view_from_session: function() {
756
            return $.cookie("pane_view") || 0;
757
        },
758

    
759
        machine_view_from_session: function() {
760
            return $.cookie("machine_view") || 0;
761
        },
762

    
763
        update_session: function() {
764
            $.cookie("pane_view", this.pane_ids[this.current_view_id]);
765
            if (this.current_view.vms_view) {
766
                $.cookie("machine_view", this.views_ids[this.current_view_id]);
767
            }
768
        },
769

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

    
798
        _show_view: function(view_id) {
799
                // same view, visible
800
                // get out of here asap
801
                if (this.current_view && 
802
                    this.current_view.id == view_id && 
803
                    this.current_view.visible()) {
804
                    return;
805
                }
806
                
807
                // choose proper view_id
808
                view_id = this.identify_view(view_id);
809

    
810
                // add/create view and update current view
811
                var view = this.add_view(view_id);
812
                
813
                // set current view
814
                this.current_view = view;
815
                this.current_view_id = view_id;
816

    
817
                // hide all other views
818
                this.hide_views([this.current_view]);
819
                
820
                // FIXME: depricated
821
                $(".large-spinner").remove();
822

    
823
                storage.vms.reset_pending_actions();
824
                storage.networks.reset_pending_actions();
825
                storage.vms.stop_stats_update();
826

    
827
                // show current view
828
                this.show_view_pane();
829
                view.show();
830
                
831
                // update menus
832
                if (this.select_view) {
833
                    this.select_view.update_layout();
834
                }
835
                this.current_view.__update_layout();
836

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

    
854
                // trigger view change event
855
                this.trigger("view:change", this.current_view.view_id);
856
                this.select_view.title.text(this.get_title());
857
                $(window).trigger("view:change");
858
                return view;
859
        },
860

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

    
877
    });
878

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

    
891
    snf.ui.init = function() {
892
        if (snf.config.handle_window_exceptions) {
893
            window.onerror = function(msg, file, line) {
894
                snf.ui.trigger_error("CRITICAL", msg, {}, { file:file + ":" + line, allow_close: false });
895
            };
896
        }
897
        snf.ui.main.load();
898
    }
899

    
900
})(this);