Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_error_view.js @ 0b416fc7

History | View | Annotate | Download (11.4 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
                "API Message: " + this.api_message + "\n" +
125
                "Module: " + this.ns + "\n" +
126
                "Details: " + this.details + "\n\n" +
127
                "Please describe the actions that triggered the error:\n"
128
            
129
            return fdb_msg;
130
        },
131
        
132
        show_error: function(ns, code, message, api_message, type, details, error_options) {
133
            
134
            var error_entry = [ns, code, message, api_message, type, details, error_options];
135
            var last_error_key = this.update_errors_stack(error_entry);
136
            
137
            if (!this.is_visible && !this.displaying_error) {
138
                this.current_error = last_error_key;
139
                this.display_error.call(this, last_error_key);
140
                this.show();
141
            }
142

    
143
            this.update_errors_stack();
144
        },
145

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

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

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

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

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

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

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

    
192
        show_next_error: function() {
193
        },
194

    
195
        show_prev_error: function() {
196
        },
197

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

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

    
213
            this.code = code;
214
            this.ns = ns;
215
            this.type = type;
216
            this.details = details ? (details.toString ? details.toString() : details) : undefined;
217
            this.message = message;
218
            this.api_message = api_message;
219
            this.title = _.escape(error_options.title) || undefined;
220

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

    
241
        update_details: function() {
242
            var title = "Application error";
243
            if (this.ns && this.type) {
244
                title = this.title || this.type + " Error";
245
            }
246

    
247
            this.$(".overlay-header .title").text(title);
248
            this.$(".error-code").text(this.code || "");
249
            this.$(".error-type").text(this.type || "");
250
            this.$(".error-module").text(this.ns || "");
251
            if (this.api_message) {
252
              this.$(".message p").html($(
253
                "<span>{0}</span><br /><span class='api-message'>{1}</span>".format(
254
                _.escape(this.message), 
255
                _.escape(this.api_message))));
256
            } else {
257
              this.$(".message p").text(this.message || "");
258
            }
259
            this.$(".error-more-details p").html($("<pre />", {text:this.details}) || "no info");
260

    
261
            this.$(".extra-details").remove();
262
            _.each(this.error_options.extra_details, function(value, key){
263
                var opt = $(('<span class="extra-details key">{0}</span>' +
264
                            '<span class="extra-details value">{1}</span>').format(key, value))
265
                this.$(".value.error-type").after(opt);
266
            })
267

    
268
        },
269

    
270
        beforeOpen: function() {
271
            this.$(".error-details").hide();
272
            this.$(".key.details").addClass("expand");
273
            this.$(".show-details").show();
274
            this.$(".hide-details").hide();
275
            
276
            if (this.error_options.allow_details) {
277
                this.$(".show-details").show();
278
            } else {
279
                this.$(".show-details").hide();
280
            }
281

    
282
            if (this.error_options.allow_report) {
283
                this.$(".report-error").show();
284
            } else {
285
                this.$(".report-error").hide();
286
            }
287

    
288
            if (this.error_options.allow_reload) {
289
                this.$(".reload-app").show();
290
            } else {
291
                this.$(".reload-app").hide();
292
            }
293

    
294
            if (this.error_options.allow_close) {
295
                this.$(".closeme").show();
296
            } else {
297
                this.$(".closeme").hide();
298
            }
299

    
300
        },
301

    
302
        onOpen: function() {
303
            this.displaying_error = true;
304
            var self = this;
305

    
306
            this.$(".closeme").unbind("click");
307
            this.$(".closeme").bind("click", function(){
308
                self.hide("reset");
309
            })
310
        },
311

    
312
        hide: function(reset_state) {
313
            if (reset_state === "reset") {
314
                // delay reset error state for fade out
315
                window.setTimeout(_.bind(function(){
316
                    this.displaying_error = false;
317
                    this.error_stack = {};
318
                    snf.api.trigger("reset");
319
                }, this), 500);
320
            } else {
321
                this.displaying_error = false;
322
            }
323
            views.ErrorView.__super__.hide.apply(this);
324
        },
325

    
326
        onClose: function(reset_state) {
327
            this.trigger("close", this);
328
        }
329
    });
330

    
331
})(this);