Statistics
| Branch: | Tag: | Revision:

root / ui / static / snf / js / ui / web / ui_main_view.js @ 75331d54

History | View | Annotate | Download (27.6 kB)

1
;(function(root){
2

    
3
    // root
4
    var root = root;
5
    
6
    // setup namepsaces
7
    var snf = root.synnefo = root.synnefo || {};
8
    var models = snf.models = snf.models || {}
9
    var storage = snf.storage = snf.storage || {};
10
    var ui = snf.ui = snf.ui || {};
11

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

    
14
    // shortcuts
15
    var bb = root.Backbone;
16
    var util = snf.util;
17
    
18
    // TODO: implement me
19
    views.NoticeView = views.Overlay.extend({});
20

    
21
    views.MultipleActionsView = views.View.extend({
22
        view_id: "multiple_actions",
23

    
24
        _actions: {},
25
        el: '#multiple_actions_container',
26
        
27
        initialize: function() {
28
            this.actions = {};
29
            views.MultipleActionsView.__super__.initialize.call(this);
30
            
31
            // view elements
32
            this.confirm_actions = this.$(".confirm_multiple_actions");
33
            this.confirm_actions_yes = this.$(".confirm_multiple_actions button.yes");
34
            this.confirm_actions_no = this.$(".confirm_multiple_actions button.no");
35
            this.confirm_reboot = this.$(".confirm_reboot_required");
36
            this.confirm_reboot_yes = this.$(".confirm_reboot_required button.yes");
37
            this.confirm_reboot_no = this.$(".confirm_reboot_required button.no");
38
            this.confirm_reboot_list = this.confirm_reboot.find(".reboot-machines-list");
39

    
40
            this.init_handlers();
41
            this.update_layout();
42
            
43
            // for heavy resize/scroll window events
44
            // do it `like a boss` 
45
            this.fix_position = _.throttle(this.fix_position, 100);
46
            this.update_layout = _.throttle(this.update_layout, 100);
47
            this.show_limit = 1;
48
        },
49

    
50
        init_handlers: function() {
51
            var self = this;
52

    
53
            $(window).resize(_.bind(function(){
54
                this.fix_position();
55
            }, this));
56

    
57
            $(window).scroll(_.bind(function(){
58
                this.fix_position();
59
            }, this));
60
            
61
            // confirm/cancel button handlers
62
            var self = this;
63
            this.confirm_actions_yes.click(function(){ self.do_all(); })
64
            this.confirm_actions_no.click(function(){
65
                self.reset_actions();
66
            });
67

    
68
            this.confirm_reboot_yes.click(function(){ self.do_reboot_all(); })
69
            this.confirm_reboot_no.click(function(){
70
                self.reset_reboots();
71
            });
72

    
73
            storage.vms.bind("change:pending_action", _.bind(this.handle_vm_change, this));
74
            storage.vms.bind("change:reboot_required", _.bind(this.handle_vm_change, this));
75

    
76
        },
77

    
78
        handle_vm_change: function(vm) {
79
            if (vm.has_pending_action()) {
80
                var action = vm.get("pending_action");
81
                this.add_action(vm, action);
82
            } else {
83
                this.remove_action(vm);
84
            }
85
            this.update_layout();
86
        },
87

    
88
        add_action: function(vm, action) {
89
            this._actions[vm.id] = {'vm': vm, 'action': action};
90
        },
91

    
92
        remove_action: function(vm) {
93
            delete this._actions[vm.id];
94
        },
95

    
96
        reset: function() {
97
            this._actions = {};
98
            this.update_layout();
99
        },
100
        
101
        reboot_vm: function(vm) {
102
            vm.call("reboot");
103
        },
104

    
105
        do_reboot_all: function() {
106
            _.each(storage.vms.get_reboot_required(), function(vm){
107
                this.reboot_vm(vm)
108
            }, this)  
109
        },
110

    
111
        do_all: function() {
112
            _.each(this._actions, function(action){
113
                action.vm.call(action.action);
114
            }, this)  
115
            this.reset_actions();
116
        },
117

    
118
        reset_reboots: function () {
119
            _.each(storage.vms.get_reboot_required(), function(vm) {vm.set({'reboot_required': false})}, this);
120
            this.update_layout();
121
        },
122

    
123
        reset_actions: function() {
124
            _.each(this._actions, _.bind(function(action){
125
                try {
126
                    action.vm.clear_pending_action();
127
                    this.remove_action(action.vm);
128
                } catch(err) {
129
                    console.error("vm " + action.vm.id + " failed to reset", err);
130
                }
131
            }, this))  
132
        },
133
        
134
        fix_position: function() {
135
            $('.confirm_multiple').removeClass('fixed');
136
            if (($(this.el).offset().top +$(this.el).height())> ($(window).scrollTop() + $(window).height())) {
137
                $('.confirm_multiple').addClass('fixed');
138
            }
139
        },
140
        
141
        check_notify_limit: function() {
142
            this.show_limit = 1;
143
            if (ui.main.current_view && ['networks', 'vm_list'].indexOf(ui.main.current_view.view_id) > -1) {
144
                this.show_limit = 0;
145
            }
146
        },
147
        
148
        update_reboot_required_list: function(vms) {
149
            this.confirm_reboot_list.empty();
150
        },
151

    
152
        update_reboot_required: function() {
153
            var vms = storage.vms.get_reboot_required();
154
            if (vms.length) {
155
                this.confirm_reboot.find(".actionLen").text(vms.length);
156
                this.update_reboot_required_list();
157
                this.confirm_reboot.show();
158
                $(this.el).show();
159
            } else {
160
                if (!this.actions_visible) {
161
                   $(this.el).hide();
162
                }
163
                this.confirm_reboot.hide();
164
            }
165
        },
166

    
167
        update_layout: function() {
168
            this.check_notify_limit();
169
            this.actions_visible = false;
170

    
171
            if (_.size(this._actions) > this.show_limit) {
172
                this.actions_visible = true;
173
                $(this.el).show();
174
                this.confirm_actions.show();
175
            } else {
176
                $(this.el).hide();
177
                this.confirm_actions.hide();
178
            }
179

    
180
            this.update_reboot_required();
181
            this.confirm_actions.find(".actionLen").text(_.size(this._actions));
182
            $(window).trigger("resize");
183
        }
184
    })
185
    
186
    // menu wrapper view
187
    views.SelectView = views.View.extend({
188
        
189
        initialize: function(view) {
190
            this.parent = view;
191

    
192
            this.pane_view_selector = $(".css-tabs");
193
            this.machine_view_selector = $("#view-select");
194
            this.el = $(".css-tabs");
195
            this.title = $(".tab-name");
196

    
197
            this.set_handlers();
198
            this.update_layout();
199

    
200
            views.SelectView.__super__.initialize.apply(this, arguments);
201
        },
202
        
203
        clear_active: function() {
204
            this.pane_view_selector.find("a").removeClass("active");
205
            this.machine_view_selector.find("a").removeClass("activelink");
206
        },
207
        
208
        // intercept menu links
209
        set_handlers: function() {
210
            var self = this;
211
            this.pane_view_selector.find("a").hover(function(){
212
                // FIXME: title from href ? omg
213
                self.title.text($(this).attr("href"));
214
            }, function(){
215
                self.title.text(self.parent.get_title());
216
            });
217

    
218
            this.pane_view_selector.find("a#machines_view_link").click(_.bind(function(ev){
219
                ev.preventDefault();
220
                this.parent.show_view("machines");
221
            }, this))
222
            this.pane_view_selector.find("a#networks_view_link").click(_.bind(function(ev){
223
                ev.preventDefault();
224
                this.parent.show_view("networks");
225
            }, this))
226
            this.pane_view_selector.find("a#disks_view_link").click(_.bind(function(ev){
227
                ev.preventDefault();
228
                this.parent.show_view("disks");
229
            }, this))
230
            
231
            this.machine_view_selector.find("a#machines_view_icon_link").click(_.bind(function(ev){
232
                ev.preventDefault();
233
                var d = $.now();
234
                this.parent.show_view("icon");
235
            }, this))
236
            this.machine_view_selector.find("a#machines_view_list_link").click(_.bind(function(ev){
237
                ev.preventDefault();
238
                this.parent.show_view("list");
239
            }, this))
240
            this.machine_view_selector.find("a#machines_view_single_link").click(_.bind(function(ev){
241
                ev.preventDefault();
242
                this.parent.show_view("single");
243
            }, this))
244
        },
245

    
246
        update_layout: function() {
247
            this.clear_active();
248

    
249
            var pane_index = this.parent.pane_ids[this.parent.current_view_id];
250
            $(this.pane_view_selector.find("a")).removeClass("active");
251
            $(this.pane_view_selector.find("a").get(pane_index)).addClass("active");
252
            
253
            if (this.parent.current_view && this.parent.current_view.vms_view) {
254

    
255
                if (storage.vms.length > 0) {
256
                    this.machine_view_selector.show();
257
                    var machine_index = this.parent.views_ids[this.parent.current_view_id];
258
                    $(this.machine_view_selector.find("a").get(machine_index)).addClass("activelink");
259
                } else {
260
                    this.machine_view_selector.hide();
261
                }
262
            } else {
263
                this.machine_view_selector.hide();
264
            }
265

    
266
        }
267
    });
268

    
269
    views.MainView = views.View.extend({
270
        el: 'body',
271
        view_id: 'main',
272
        
273
        // FIXME: titles belong to SelectView
274
        views_titles: {
275
            'icon': 'machines', 'single': 'machines', 
276
            'list': 'machines', 'networks': 'networks',
277
            'disks': 'disks'
278
        },
279

    
280
        // indexes registry
281
        views_indexes: {0: 'icon', 2:'single', 1: 'list', 3:'networks'},
282
        views_pane_indexes: {0:'single', 1:'networks', 2:'disks'},
283

    
284
        // views classes registry
285
        views_classes: {'icon': views.IconView, 'single': views.SingleView, 
286
            'list': views.ListView, 'networks': views.NetworksView},
287

    
288
        // view ids
289
        views_ids: {'icon':0, 'single':2, 'list':1, 'networks':3},
290

    
291
        // on which pane id each view exists
292
        // machine views (icon,single,list) are all on first pane
293
        pane_ids: {'icon':0, 'single':0, 'list':0, 'networks':1, 'disks':2},
294
    
295
        initialize: function(show_view) {
296
            if (!show_view) { show_view = 'icon' };
297
            
298
            // fallback to browser error reporting (true for debug)
299
            this.skip_errors = true
300

    
301
            // reset views
302
            this.views = {};
303

    
304
            this.el = $("#app");
305
            // reset main view status
306
            this._loaded = false;
307
            this.status = "Initializing...";
308

    
309
            // initialize handlers
310
            this.init_handlers();
311

    
312
            // identify initial view from user cookies
313
            // this view will be visible after loading of
314
            // main view
315
            this.initial_view = this.session_view();
316

    
317
            views.MainView.__super__.initialize.call(this);
318

    
319
            $(window).focus(_.bind(this.handle_window_focus, this, "focus"));
320
            $(window).blur(_.bind(this.handle_window_focus, this, "out"));
321

    
322
            this.focused = true;
323
        },
324

    
325
        handle_window_focus: function(focus) {
326
            if (!snf.config.delay_on_blur) { return };
327

    
328
            if (focus === "focus") {
329
                this.focused = true;
330
                this.set_interval_timeouts(snf.config.update_interval);
331
            } else {
332
                this.focused = false;
333
                this.set_interval_timeouts(snf.config.blur_delay);
334
            }
335
        },
336

    
337
        set_interval_timeouts: function(time) {
338
            _.each([this._networks, this._vms], function(fetcher){
339
                if (!fetcher) { return };
340
                fetcher.timeout = time;
341
                fetcher.stop().start();
342
            })
343
        },
344
        
345
        vms_handlers_registered: false,
346

    
347
        // register event handlers
348
        // 
349
        // vms storage events to identify if vms list 
350
        // is empty and display empty view if user viewing
351
        // a machine view
352
        //
353
        // api/ui error event handlers
354
        init_handlers: function() {
355
            // vm handlers
356
            storage.vms.bind("remove", _.bind(this.check_empty, this));
357
            storage.vms.bind("add", _.bind(this.check_empty, this));
358
            storage.vms.bind("change", _.bind(this.check_empty, this));
359
            storage.vms.bind("reset", _.bind(this.check_empty, this));
360
            
361
            // api calls handlers
362
            synnefo.api.bind("error", _.bind(this.handle_api_error, this));
363
            synnefo.api.bind("change:error_state", _.bind(this.handle_api_error_state, this));
364
            synnefo.ui.bind("error", _.bind(this.handle_ui_error, this));
365
        },
366
        
367
        handle_api_error_state: function(state) {
368
            if (snf.api.error_state === snf.api.STATES.ERROR) {
369
                this.stop_intervals();
370
            } else {
371
                if (this.intervals_stopped) {
372
                    this.update_intervals();
373
                }
374
            }
375
        },
376
        
377
        handle_api_error: function(args) {
378
            if (arguments.length == 1) { arguments = _.toArray(arguments[0])};
379

    
380
            if (!_.last(arguments).display) {
381
                return;
382
            }
383

    
384
            this.error_state = true;
385
            
386
            var xhr = arguments[0];
387
            var args = util.parse_api_error.apply(util, arguments);
388
            
389
            // force logout if UNAUTHORIZED request arrives
390
            if (args.code == 401) { snf.ui.logout(); return };
391

    
392
            var error_entry = [args.ns, args.code, args.message, args.type, args.details, args];
393
            this.error_view.show_error.apply(this.error_view, error_entry);
394
        },
395

    
396
        handle_ui_error: function(data) {
397
            var msg = data.msg, code = data.code, err_obj = data.error;
398
            error = msg + "<br /><br />" + snf.util.stacktrace().replace("at", "<br /><br />at");
399
            params = { title: "UI error", extra_details: data.extra };
400
            params.allow_close = data.extra.allow_close === undefined ? true : data.extra.allow_close;
401
            this.error_view.show_error("UI", -1, msg, "JS Exception", error, params);
402
        },
403

    
404
        init_overlays: function() {
405
            this.create_vm_view = new views.CreateVMView();
406
            //this.notice_view = new views.NoticeView();
407
        },
408
        
409
        show_loading_view: function() {
410
            $("#container #content").hide();
411
            $("#loading-view").show();
412
        },
413

    
414
        hide_loading_view: function() {
415
            $("#container #content").show();
416
            $("#loading-view").hide();
417
            $(".css-panes").show();
418
        },
419
        
420
        items_to_load: 4,
421
        completed_items: 0,
422
        check_status: function(loaded) {
423
            this.completed_items++;
424
            // images, flavors loaded
425
            if (this.completed_items == 2) {
426
                this.load_nets_and_vms();
427
            }
428

    
429
            if (this.completed_items == this.items_to_load) {
430
                this.update_status("Rendering layout");
431
                var self = this;
432
                window.setTimeout(function(){
433
                    self.after_load();
434
                }, 100)
435
            }
436
        },
437

    
438
        load_nets_and_vms: function() {
439
            var self = this;
440
            this.update_status("Loading vms...");
441
            storage.vms.fetch({refresh:true, update:false, success: function(){
442
                self.update_status("VMS Loaded.");
443
                self.check_status();
444
            }});
445

    
446
            this.update_status("Loading networks...");
447
            storage.networks.fetch({refresh:true, update:false, success: function(){
448
                self.update_status("Networks loaded.");
449
                self.check_status();
450
            }});
451
        },  
452

    
453
        init_intervals: function() {
454
            this._networks = storage.networks.get_fetcher(snf.config.update_interval, 
455
                                                          snf.config.update_interval / 2, 
456
                                                          1, true, undefined);
457
            this._vms = storage.vms.get_fetcher(snf.config.update_interval, 
458
                                                snf.config.update_interval / 2, 
459
                                                1, true, undefined);
460
        },
461

    
462
        stop_intervals: function() {
463
            if (this._networks) { this._networks.stop(); }
464
            if (this._vms) { this._vms.stop(); }
465
            this.intervals_stopped = true;
466
        },
467

    
468
        update_intervals: function() {
469
            if (this._networks) {
470
                this._networks.stop();
471
                this._networks.start();
472
            } else {
473
                this.init_intervals();
474
            }
475

    
476
            if (this._vms) {
477
                this._vms.stop();
478
                this._vms.start();
479
            } else {
480
                this.init_intervals();
481
            }
482

    
483
            this.intervals_stopped = false;
484
        },
485

    
486
        after_load: function() {
487
            this.update_status("Setting vms update interval...");
488
            this.init_intervals();
489
            this.update_intervals();
490
            this.update_status("Loaded");
491
            // FIXME: refactor needed
492
            // initialize views
493
            
494
            // bypass update_hidden_views in initial view
495
            // rendering to force all views to get render
496
            // on their creation
497
            var uhv = snf.config.update_hidden_views;
498
            snf.config.update_hidden_views = true;
499
            this.initialize_views()
500

    
501
            this.update_status("Initializing overlays...");
502
            this.init_overlays();
503
            // display initial view
504
            this.loaded = true;
505
            this.show_initial_view();
506
            this.check_empty();
507
            snf.config.update_hidden_views = uhv;
508
        },
509

    
510
        load: function() {
511
            this.error_view = new views.ErrorView();
512
            this.feedback_view = new views.FeedbackView();
513
            var self = this;
514
            // initialize overlay views
515
            
516
            // display loading message
517
            this.show_loading_view();
518
            // sync load initial data
519
            this.update_status("Loading images...");
520
            storage.images.fetch({refresh:true, update:false, success: function(){
521
                self.check_status()
522
            }});
523
            this.update_status("Loading flavors...");
524
            storage.flavors.fetch({refresh:true, update:false, success:function(){
525
                self.check_status()
526
            }});
527
        },
528

    
529
        update_status: function(msg) {
530
            this.log.debug(msg)
531
            this.status = msg;
532
            $("#loading-view .info").removeClass("hidden")
533
            $("#loading-view .info").text(this.status);
534
        },
535

    
536
        initialize_views: function() {
537
            this.empty_view = new views.EmptyView();
538
            this.select_view = new views.SelectView(this);
539
            this.metadata_view = new views.MetadataView();
540
            this.multiple_actions_view = new views.MultipleActionsView();
541
            
542
            this.add_view("icon");
543
            this.add_view("list");
544
            this.add_view("single");
545
            this.add_view("networks");
546

    
547
            this.init_menu();
548
        },
549

    
550
        init_menu: function() {
551
            $(".usermenu .feedback").click(_.bind(function(){
552
                this.feedback_view.show();
553
            }, this));
554
        },
555
        
556
        // initial view based on user cookie
557
        show_initial_view: function() {
558
          this.set_vm_view_handlers();
559
          this.hide_loading_view();
560
          this.show_view(this.initial_view);
561
          this.trigger("initial");
562
        },
563

    
564
        show_vm_details: function(vm) {
565
            snf.ui.main.show_view("single")
566
            snf.ui.main.current_view.show_vm(vm);
567
        },
568

    
569
        set_vm_view_handlers: function() {
570
            $("#createcontainer #create").click(_.bind(function(){
571
                this.create_vm_view.show();
572
            }, this))
573
        },
574

    
575
        check_empty: function() {
576
            if (!this.loaded) { return }
577
            if (storage.vms.length == 0) {
578
                this.show_view("machines");
579
                this.show_empty();
580
            } else {
581
                this.hide_empty();
582
            }
583
            this.select_view.update_layout();
584
        },
585

    
586
        show_empty: function() {
587
            $("#machines-pane-top").addClass("empty");
588

    
589
            this.$(".panes").hide();
590
            this.$("#machines-pane").show();
591

    
592
            this.hide_views([]);
593
            this.empty_view.show();
594
        },
595

    
596
        hide_empty: function() {
597
            $("#machines-pane-top").removeClass("empty");
598

    
599
            this.empty_view = new views.EmptyView();
600
            this.empty_view.hide();
601
            if (this.current_view && !this.current_view.visible()) { 
602
                this.current_view.show(); 
603
            }
604
        },
605
        
606
        get_title: function(view_id) {
607
            var view_id = view_id || this.current_view_id;
608
            return this.views_titles[view_id];
609
        },
610

    
611
        // return class object for the given view or false if
612
        // the view is not registered
613
        get_class_for_view: function (view_id) {
614
            if (!this.views_classes[view_id]) {
615
                return false;
616
            }
617
            return this.views_classes[view_id];
618
        },
619

    
620
        view: function(view_id) {
621
            return this.views[view_id];
622
        },
623

    
624
        add_view: function(view_id) {
625
            if (!this.views[view_id]) {
626
                var cls = this.get_class_for_view(view_id);
627
                if (this.skip_errors) {
628
                    this.views[view_id] = new cls();
629
                    $(this.views[view_id]).bind("resize", _.bind(function() {
630
                        window.positionFooter();
631
                        this.multiple_actions_view.fix_position();
632
                    }, this));
633
                } else {
634
                    // catch ui errors
635
                    try {
636
                        this.views[view_id] = new cls();
637
                        $(this.views[view_id]).bind("resize", _.bind(function() {
638
                            window.positionFooter();
639
                            this.multiple_actions_view.fix_position();
640
                        }, this));
641
                    } catch (err) {snf.ui.trigger_error(-1, "Cannot add view", err)}
642
                }
643
            } else {
644
            }
645

    
646
            if (this.views[view_id].vms_view) {
647
                this.views[view_id].metadata_view = this.metadata_view;
648
            }
649
            return this.views[view_id];
650
        },
651
            
652
        hide_views: function(skip) {
653
            _.each(this.views, function(view) {
654
                if (skip.indexOf(view) === -1) {
655
                    $(view.el).hide();
656
                }
657
            }, this)
658
        },
659
        
660
        get: function(view_id) {
661
            return this.views[view_id];
662
        },
663
        
664
        session_view: function() {
665
            if (this.pane_view_from_session() > 0) {
666
                return this.views_pane_indexes[this.pane_view_from_session()];
667
            } else {
668
                return this.views_indexes[this.machine_view_from_session()];
669
            }
670
        },
671

    
672
        pane_view_from_session: function() {
673
            return $.cookie("pane_view") || 0;
674
        },
675

    
676
        machine_view_from_session: function() {
677
            return $.cookie("machine_view") || 0;
678
        },
679

    
680
        update_session: function() {
681
            $.cookie("pane_view", this.pane_ids[this.current_view_id]);
682
            if (this.current_view.vms_view) {
683
                $.cookie("machine_view", this.views_ids[this.current_view_id]);
684
            }
685
        },
686

    
687
        identify_view: function(view_id) {
688
            // machines view_id is an alias to
689
            // one of the 3 machines view
690
            // identify which one (if no cookie set defaults to icon)
691
            if (view_id == "machines") {
692
                var index = this.machine_view_from_session();
693
                view_id = this.views_indexes[index];
694
            }
695
            return view_id;
696
        },
697
        
698
        // switch to current view pane
699
        // if differs from the visible one
700
        show_view_pane: function() {
701
            if (this.current_view.pane != this.current_pane) {
702
                $(this.current_view.pane).show();
703
                $(this.current_pane).hide();
704
                this.current_pane = this.current_view.pane;
705
            }
706
        },
707
        
708
        show_view: function(view_id) {
709
            //var d = new Date;
710
            var ret = this._show_view(view_id);
711
            //console.log((new Date)-d)
712
            return ret;
713
        },
714

    
715
        _show_view: function(view_id) {
716
            try {
717
                // same view, visible
718
                // get out of here asap
719
                if (this.current_view && 
720
                    this.current_view.id == view_id && 
721
                    this.current_view.visible()) {
722
                    return;
723
                }
724
                
725
                // choose proper view_id
726
                view_id = this.identify_view(view_id);
727

    
728
                // add/create view and update current view
729
                var view = this.add_view(view_id);
730
                
731
                // set current view
732
                this.current_view = view;
733
                this.current_view_id = view_id;
734

    
735
                // hide all other views
736
                this.hide_views([this.current_view]);
737
                
738
                // FIXME: depricated
739
                $(".large-spinner").remove();
740

    
741
                storage.vms.reset_pending_actions();
742
                storage.vms.stop_stats_update();
743

    
744
                // show current view
745
                this.show_view_pane();
746
                view.show();
747
                
748
                // update menus
749
                if (this.select_view) {
750
                    this.select_view.update_layout();
751
                }
752
                this.current_view.__update_layout();
753

    
754
                // update cookies
755
                this.update_session();
756
                
757
                // machines view subnav
758
                if (this.current_view.vms_view) {
759
                    $("#machines-pane").show();
760
                } else {
761
                    $("#machines-pane").hide();
762
                }
763
                
764
                // fix footer position
765
                // TODO: move footer handlers in
766
                // main view (from home.html)
767
                if (window.positionFooter) {
768
                    window.positionFooter();
769
                }
770

    
771
                // trigger view change event
772
                this.trigger("view:change", this.current_view.view_id);
773
                this.select_view.title.text(this.get_title());
774
                $(window).trigger("view:change");
775
                return view;
776
            } catch (err) {
777
                snf.ui.trigger_error(-2, "Cannot show view: " + view_id, err);
778
            }
779
        },
780

    
781
        reset_vm_actions: function() {
782
        
783
        },
784
        
785
        // identify current view
786
        // based on views element visibility
787
        current_view_id: function() {
788
            var found = false;
789
            _.each(this.views, function(key, value) {
790
                if (value.visible()) {
791
                    found = value;
792
                }
793
            })
794
            return found;
795
        }
796

    
797
    });
798

    
799
    snf.ui.main = new views.MainView();
800
    
801
    snf.ui.logout = function() {
802
        $.cookie("X-Auth-Token", null);
803
        if (snf.config.logout_url !== undefined)
804
        {
805
            window.location = snf.config.logout_url;
806
        } else {
807
            window.location.reload();
808
        }
809
    }
810

    
811
    snf.ui.init = function() {
812
        if (snf.config.handle_window_exceptions) {
813
            window.onerror = function(msg, file, line) {
814
                snf.ui.trigger_error("CRITICAL", msg, {}, { file:file + ":" + line, allow_close: false });
815
            };
816
        }
817
        snf.ui.main.load();
818
    }
819

    
820
})(this);