Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / views.js @ 198b546d

History | View | Annotate | Download (11.8 kB)

1
// Copyright 2014 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 views = snf.views = snf.views || {}
45
    var util = snf.util = snf.util || {}
46

    
47
    // shortcuts
48
    var bb = root.Backbone;
49
    
50
    // logging
51
    var logger = new snf.logging.logger("SNF-VIEWS");
52
    var debug = _.bind(logger.debug, logger);
53
    
54
    // Base view object
55
    views.View = bb.View.extend({
56
        // the main element of the view
57
        // view delegates show, visible, hide etc to this element
58
        view_id: false,
59

    
60
        el: '#app',
61
        data_from: false,
62
        selectors: {},
63
        
64
        pre_show: function() {},
65
        post_show: function() {},
66
        pre_hide: function() {},
67
        post_hide: function() {},
68

    
69
        initialize: function(options) {
70
            views.View.__super__.initialize.apply(this, [options]);
71
            this.log = new snf.logging.logger("SNF-VIEWS:" + this.view_id);
72
            this.parent_view = options && options.parent_view;
73
        },
74
        
75
        destroy: function() {
76
          this.hide(true);
77
          $(this.el).remove();
78
        },
79

    
80
        // is the view visible ?
81
        visible: function(){
82
            return $(this.el).is(":visible");
83
        },
84
        
85
        // hide view
86
        hide: function(force) {
87
            if (!this.visible() && !force) { return this };
88
            this.pre_hide();
89
            var ret = $(this.el).hide();
90
            this.post_hide();
91
            return ret;
92
        },
93
        
94
        // show view
95
        show: function(force) {
96
            if (this.visible() && !force) { return this };
97
            this.pre_show();
98
            $(this.el).show();
99
            if (this.show_view) { this.show_view.apply(this, arguments)};
100
            this.post_show();
101
        },
102

    
103
        sel: function(id) {
104
            return this.$(this.selectors[id]);
105
        },
106

    
107
        // animations
108
        fadeIn: function(time, callback) {
109
            $(this.el).fadeIn(time, callback);
110
            return this.show();
111
        },
112

    
113
        fadeOut: function(time, callback) {
114
            $(this.el).fadeOut(time, callback);
115
            return this.hide();
116
        }
117
    });
118
    
119
    
120
    // overlays registry
121
    views._overlay_index = [];
122

    
123
    // overlay view helper
124
    views.Overlay = views.View.extend({
125
        view_id: 'overlay',
126
        tpl_selector: '#generic-overlay-tpl',
127
        css_class: 'overlay',
128
        oneInstance: true,
129
        fixed: false,
130

    
131
        initialize: function(options, selector) {
132
            this.defaults = {
133
                load: false,
134
                closeOnClick: false,
135
                closeOnEsc: false,
136
                mask: {
137
                    color: "#444",
138
                    loadSpeed: snf.config.overlay_speed || 0,
139
                    opacity: 0.7
140
                },
141
                speed: snf.config.overlay_speed || 200
142
            }
143
            
144
            this.tpl_selector = selector || this.tpl_selector;
145
            views.Overlay.__super__.initialize.apply(this);
146
            views._overlay_index.push(this);
147

    
148
            this.options = _.extend(this.defaults, options);
149
            this.options.clone = this.options.clone == undefined ? true : this.options.clone;
150
            this.options.fixed = this.fixed;
151

    
152
            this.options.onOpen = this.options.onOpen || function() {};
153
            this.options.onClose = this.options.onClose || function() {};
154
            this.options.beforeOpen = this.options.beforeOpen || function() {};
155
            this.options.beforeClose = this.options.beforeClose || function() {};
156
            this.el = this.create_element();
157
            this.el.hide();
158
        
159
            var ajax_params = _.clone(this.options);
160

    
161
            ajax_params.onBeforeLoad = _.bind(this._beforeOpen, this);
162
            ajax_params.onLoad = _.bind(this._onOpen, this);
163
            ajax_params.onBeforeClose = _.bind(this._beforeClose, this);
164
            ajax_params.onClose = _.bind(this._onClose, this);
165
            ajax_params.oneInstance = this.oneInstance;
166
            // create overlay
167
            // TODO: does this return overlay object ?? (to avoid the next code line)
168
            $(this.el).overlay(ajax_params);
169

    
170
            this.overlay = $(this.el).overlay();
171
            this.append_css = this.options ? this.options.css_class ? this.options.css_class : "" : "";
172

    
173
            this.is_visible = false;
174
            return this;
175
        },
176

    
177
        create_element: function() {
178
            var el = undefined;
179
            if (this.options.clone) {
180
                el = $(this.tpl_selector).clone();
181
            } else {
182
                el = $(this.tpl_selector);
183
            }
184
            
185
            // append content
186
            if (this.content_selector) {
187
                var content = $(this.content_selector).clone();
188
                content.addClass("content");
189
                
190
                if ($(el).find(".content").length) {
191
                    $(el).find(".content").replaceWith(content);
192
                }
193
                content.removeClass("hidden");
194
            }
195

    
196
            if (this.overlay_id) {
197
            }
198

    
199
            $(el).addClass("overlay");
200
            if (this.css_class) {
201
                $(el).addClass(this.css_class);
202
            }
203
            
204
            if (this.options.clone) {
205
                $("body").append(el);
206
            }
207

    
208
            return el;
209
        },
210

    
211
        set_title: function(title) {
212
            if (title || this.title) {
213
                $(this.el).find(".overlay-header .title").html(title || this.title)
214
            }
215
        },
216

    
217
        set_subtitle: function(subtitle) {
218
            if (subtitle || this.subtitle) {
219
                $(this.el).find(".overlay-header .subtitle").html(subtitle || this.subtitle)
220
            }
221
        },
222

    
223
        _beforeOpen: function() {
224
            this.is_visible = true;
225
            if (this.append_css) {
226
                $(this.el).addClass(this.append_css);
227
            }
228

    
229
            this.set_title();
230
            this.set_subtitle();
231
            
232
            this.beforeOpen.apply(this, arguments);
233
            this.options.beforeOpen.apply(this, arguments);
234
        },
235

    
236
        _onOpen: function() {
237
            // clear previously bound click events
238
            $(this.el).find(".closeme").unbind("click");
239

    
240
            if ($(this.el).find(".closeme").length) {
241
                $(this.el).find(".closeme").click(_.bind(function(){
242
                    this.hide();
243
                }, this))
244
            }
245
            this.onOpen.apply(this, arguments);
246
            this.options.onOpen.apply(this, arguments);
247
        },
248

    
249
        _beforeClose: function() {
250
            this.is_visible = false;
251
            this.beforeClose.apply(this, arguments);
252
            this.options.beforeClose.apply(this, arguments);
253
        },
254

    
255
        _onClose: function() {
256
            if (this.append_css) {
257
                $(this.el).removeClass(this.append_css);
258
            }
259
            this.onClose.apply(this, arguments);
260
            this.options.onClose.apply(this, arguments);
261
        },
262

    
263
        beforeOpen: function () {},
264
        onOpen: function () {},
265
        beforeClose: function () {},
266
        onClose: function () {},
267

    
268
        show: function() {
269
            // close opened overlays
270
            var hidden = false;
271
            _.each(views._overlay_index, function(ovr){
272
                if (ovr == this) { return };
273
                if (ovr.visible()) {
274
                    hidden = true;
275
                    ovr.hide();
276
                }
277
            })
278

    
279
            // do we need to wait for other overlays to close ???
280
            if (hidden) { delay = 300; } else { delay = 0; }
281

    
282
            this.is_visible = true;
283
            window.setTimeout(_.bind(function(){ this.overlay.load(); this.trigger('show') }, this), delay)
284
            return this;
285
        },
286

    
287
        hide: function() {
288
            if (!this.overlay.isOpened()) {
289
                // if its not opened events wont trigger
290
                this._onClose()
291
            } else {
292
                this.overlay.close();
293
            }
294
            return this;
295
        }
296
    });
297

    
298
    
299
    // overlay view helper
300
    views.VMOverlay = views.Overlay.extend({
301

    
302
        initialize: function() {
303
            views.VMOverlay.__super__.initialize.apply(this);
304
            this.vm = undefined;
305
            this.view_id_tpl = this.view_id;
306

    
307
            _.bindAll(this, "_handle_vm_change", "_handle_vm_remove");
308
        },
309

    
310
        set_vm: function(vm) {
311
            if (this.vm) { this.unbind_vm_handlers };
312
            this.vm = vm;
313
            this.view_id = this.view_id + "_" + vm.id;
314
            this.bind_vm_handlers();
315
        },
316

    
317
        bind_vm_handlers: function() {
318
            this.log.debug("binding handlers");
319
            this.vm.bind("change", this._handle_vm_change);
320
            storage.vms.bind("remove", this._handle_vm_remove);
321
        },
322
        
323
        unbind_vm_handlers: function() {
324
            this.log.debug("unbinding handlers", this.vm);
325
            if (!this.vm) { return };
326
            this.vm.unbind("change", this._handle_vm_change);
327
            storage.vms.unbind("remove", this._handle_vm_remove);
328
        },
329
        
330
        _update_vm_details: function() { 
331
            if (!this.vm) { console.error("invalid view state"); return }
332
            var name = _.escape(util.truncate(this.vm.get("name"), 70));
333
            this.set_subtitle(name + snf.ui.helpers.vm_icon_tag(this.vm, "small"));
334
            this.update_vm_details() 
335
        },
336

    
337
        update_vm_details: function() {},
338
        handle_vm_remove: function() {},
339
        handle_vm_change: function () {},
340
        
341
        _handle_vm_remove: function(vm, collection) {
342
            if (this.vm && vm.id == this.vm.id) {
343
                this.hide();
344
            }
345
            this.handle_vm_remove();
346
        },
347
        
348
        _handle_vm_change: function(vm) {
349
            this._update_vm_details();
350
            this.handle_vm_change(vm);
351
        },
352
        
353
        beforeClose: function() {
354
            this.unbind_vm_handlers();
355
            this.vm = undefined;
356
        },
357

    
358
        show: function(vm) {
359
            this.set_vm(vm);
360
            views.VMOverlay.__super__.show.apply(this, arguments);
361
            this._update_vm_details();
362
        }
363

    
364
    });
365

    
366
    snf.config.update_hidden_views = true;
367

    
368
})(this);