Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_error_view.js @ 435bb7fb

History | View | Annotate | Download (10.9 kB)

1
// Copyright 2011 GRNET S.A. All rights reserved.
2
// 
3
// Redistribution and use in source and binary forms, with or
4
// without modification, are permitted provided that the following
5
// conditions are met:
6
// 
7
//   1. Redistributions of source code must retain the above
8
//      copyright notice, this list of conditions and the following
9
//      disclaimer.
10
// 
11
//   2. Redistributions in binary form must reproduce the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer in the documentation and/or other materials
14
//      provided with the distribution.
15
// 
16
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
// POSSIBILITY OF SUCH DAMAGE.
28
// 
29
// The views and conclusions contained in the software and
30
// documentation are those of the authors and should not be
31
// interpreted as representing official policies, either expressed
32
// or implied, of GRNET S.A.
33
// 
34

    
35
;(function(root){
36

    
37
    // root
38
    var root = root;
39
    
40
    // setup namepsaces
41
    var snf = root.synnefo = root.synnefo || {};
42
    var models = snf.models = snf.models || {}
43
    var storage = snf.storage = snf.storage || {};
44
    var ui = snf.ui = snf.ui || {};
45
    var util = snf.util = snf.util || {};
46

    
47
    var views = snf.views = snf.views || {}
48

    
49
    // shortcuts
50
    var bb = root.Backbone;
51

    
52
    views.ErrorView = views.Overlay.extend({
53
        
54
        view_id: "error_view",
55
        content_selector: "#error-overlay-content",
56
        css_class: 'overlay-error',
57
        overlay_id: "error-overlay",
58
        error_stack: {},
59

    
60
        initialize: function() {
61
            views.ErrorView.__super__.initialize.apply(this, arguments);
62
            var self = this;
63

    
64
            this.error_state = false;
65

    
66
            this.$(".actions .show-details, .actions .hide-details").click(function() {
67
                self.$(".error-details").toggle();
68
                self.$(".show-details").toggle();
69
                self.$(".hide-details").toggle();
70
            });
71

    
72
            this.$(".key.details").click(function() {
73
                $(this).next().toggle();
74
                if (!$(this).next().is(":visible")) {
75
                    $(this).addClass("expand");
76
                } else {
77
                    $(this).removeClass("expand");
78
                }
79
            })
80

    
81
            this.$(".actions .report-error").click(_.bind(function() {
82
                this.report_error();
83
            }, this));
84

    
85
            this.$(".actions .hide-details").hide();
86

    
87
            this.$(".reload-app").click(function(){
88
                window.location.reload(true);
89
            });
90

    
91
            this.$(".show-next").click(_.bind(function(){
92
                this.show_next_error();
93
            }, this));
94

    
95
            this.$(".show-prev").click(_.bind(function(){
96
                this.show_prev_error();
97
            }, this));
98

    
99
            this.displaying_error = false;
100
            this.error_stack_index = [];
101
            this.error_stack = {};
102
        },
103

    
104
        error_object: function() {
105
            return {ns:this.ns, code:this.code, message:this.message, details:this.details};
106
        },
107

    
108
        report_error: function() {
109
            this.feedback_view = this.feedback_view || ui.main.feedback_view;
110
            this.hide(false);
111
            this.displaying_error = true;
112

    
113
            window.setTimeout(_.bind(function() {
114
                this.feedback_view.show(this.get_report_message(), true, {error: this.error_object()});
115
            }, this), 400);
116
        },
117

    
118
        get_report_message: function() {
119
            var fdb_msg =   "Error report\n" +
120
                "-------------------" + "\n" +
121
                "Code: " + this.code + "\n" + 
122
                "Type: " + this.type + "\n" +
123
                "Message: " + this.message + "\n" +
124
                "Module: " + this.ns + "\n" +
125
                "Details: " + this.details + "\n\n" +
126
                "Please describe the actions that triggered the error:\n"
127
            
128
            return fdb_msg;
129
        },
130
        
131
        show_error: function(ns, code, message, type, details, error_options) {
132
            
133
            var error_entry = [ns, code, message, type, details, error_options];
134
            var last_error_key = this.update_errors_stack(error_entry);
135
            
136
            if (!this.is_visible && !this.displaying_error) {
137
                this.current_error = last_error_key;
138
                this.display_error.call(this, last_error_key);
139
                this.show();
140
            }
141

    
142
            this.update_errors_stack();
143
        },
144

    
145
        update_errors_stack: function(entry) {
146
            if (snf.api.error_state != snf.api.STATES.ERROR) { 
147
                this.error_stack = {};
148
                this.error_stack_index = [];
149
            };
150

    
151
            var stack_key = (new Date()).getTime();
152
            this.error_stack[stack_key] = entry;
153
            this.error_stack_index.push(stack_key);
154
            this.errors_occured = this.error_stack_index.length;
155
            
156
            this.$(".error-nav").hide();
157
            //this.update_errors_stack_layout();
158
            return stack_key;
159
        },
160

    
161
        is_last_error: function(stack_key) {
162
            return this.error_stack_index.indexOf(stack_key) == this.error_stack_index.length - 1;
163
        },
164

    
165
        is_first_error: function(stack_key) {
166
            return this.error_stack_index.indexOf(stack_key) == 0;
167
        },
168

    
169
        update_errors_stack_layout: function() {
170
            if (!this.current_error) { return };
171

    
172
            if (this.errors_occured <= 1) {
173
                this.$(".error-nav").hide();
174
            } else {
175
                this.$(".error-nav").show();
176
            };
177
            
178
            if (this.is_last_error(this.current_error)) {
179
                this.$(".show-next").hide();
180
            } else {
181
                this.$(".show-next").show();
182
            }
183

    
184
            if (this.is_first_error(this.current_error)) {
185
                this.$(".show-prev").hide();
186
            } else {
187
                this.$(".show-prev").show();
188
            }
189
        },
190

    
191
        show_next_error: function() {
192
        },
193

    
194
        show_prev_error: function() {
195
        },
196

    
197
        display_error: function(stack_key) {
198
            var err = this.error_stack[stack_key];
199
            var ns = err[0], code = err[1], message = err[2], type = err[3], details = err[4], error_options = err[5]
200

    
201
            this.error_options = {'allow_report': true, 'allow_reload': true, 
202
                'extra_details': {}, 'non_critical': false, 
203
                'allow_details': false,
204
                'allow_close': true };
205
            
206
            if (error_options) {
207
                this.error_options = _.extend(this.error_options, error_options);
208
            }
209

    
210
            this.code = code;
211
            this.ns = ns;
212
            this.type = type;
213
            this.details = details ? (details.toString ? details.toString() : details) : undefined;
214
            this.message = message;
215
            this.title = error_options.title || undefined;
216

    
217
            this.update_details();
218
            
219
            if (error_options.non_critical) {
220
                this.el.addClass("non-critical");
221
                this.error_options.allow_details = false;
222
            } else {
223
                this.el.removeClass("non-critical");
224
                this.error_options.allow_details = true;
225
            }
226
            
227
            if (APP_DEBUG) {
228
                this.error_options.allow_details = true;
229
            }
230
            
231
            this.$(".actions .show-details").click();
232
            this.$(".error-details").hide();
233
            this.$(".key.details").click();
234
            this.$(".error-more-details").hide();
235
        },
236

    
237
        update_details: function() {
238
            var title = "Application error";
239
            if (this.ns && this.type) {
240
                title = this.title || this.type + " Error";
241
            }
242

    
243
            this.$(".overlay-header .title").text(title);
244
            this.$(".error-code").text(this.code || "");
245
            this.$(".error-type").text(this.type || "");
246
            this.$(".error-module").text(this.ns || "");
247
            this.$(".message p").text(this.message || "");
248
            this.$(".error-more-details p").html($("<pre />", {text:this.details}) || "no info");
249

    
250
            this.$(".extra-details").remove();
251
            _.each(this.error_options.extra_details, function(value, key){
252
                var opt = $(('<span class="extra-details key">{0}</span>' +
253
                            '<span class="extra-details value">{1}</span>').format(key, value))
254
                this.$(".value.error-type").after(opt);
255
            })
256

    
257
        },
258

    
259
        beforeOpen: function() {
260
            this.$(".error-details").hide();
261
            this.$(".key.details").addClass("expand");
262
            this.$(".show-details").show();
263
            this.$(".hide-details").hide();
264
            
265
            if (this.error_options.allow_details) {
266
                this.$(".show-details").show();
267
            } else {
268
                this.$(".show-details").hide();
269
            }
270

    
271
            if (this.error_options.allow_report) {
272
                this.$(".report-error").show();
273
            } else {
274
                this.$(".report-error").hide();
275
            }
276

    
277
            if (this.error_options.allow_reload) {
278
                this.$(".reload-app").show();
279
            } else {
280
                this.$(".reload-app").hide();
281
            }
282

    
283
            if (this.error_options.allow_close) {
284
                this.$(".closeme").show();
285
            } else {
286
                this.$(".closeme").hide();
287
            }
288

    
289
        },
290

    
291
        onOpen: function() {
292
            this.displaying_error = true;
293
            var self = this;
294

    
295
            this.$(".closeme").unbind("click");
296
            this.$(".closeme").bind("click", function(){
297
                self.hide("reset");
298
            })
299
        },
300

    
301
        hide: function(reset_state) {
302
            if (reset_state === "reset") {
303
                // delay reset error state for fade out
304
                window.setTimeout(_.bind(function(){
305
                    this.displaying_error = false;
306
                    this.error_stack = {};
307
                    snf.api.trigger("reset");
308
                }, this), 500);
309
            } else {
310
                this.displaying_error = false;
311
            }
312
            views.ErrorView.__super__.hide.apply(this);
313
        },
314

    
315
        onClose: function(reset_state) {
316
            this.trigger("close", this);
317
        }
318
    });
319

    
320
})(this);