Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (11.2 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 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
        initialize: function() {
65
            this.log = new snf.logging.logger("SNF-VIEWS:" + this.view_id);
66
        },
67
    
68
        // is the view visible ?
69
        visible: function(){
70
            return $(this.el).is(":visible");
71
        },
72
        
73
        // hide view
74
        hide: function(force) {
75
            if (!this.visible() && !force) { return this };
76
            return $(this.el).hide();
77
        },
78
        
79
        // show view
80
        show: function() {
81
            if (this.visible()) { return this };
82
            $(this.el).show();
83
            if (this.show_view) { this.show_view.apply(this, arguments)};
84
        },
85

    
86
        sel: function(id) {
87
            return this.$(this.selectors[id]);
88
        },
89

    
90
        // animations
91
        fadeIn: function(time, callback) {
92
            $(this.el).fadeIn(time, callback);
93
            return this.show();
94
        },
95

    
96
        fadeOut: function(time, callback) {
97
            $(this.el).fadeOut(time, callback);
98
            return this.hide();
99
        }
100
    });
101
    
102
    
103
    // overlays registry
104
    views._overlay_index = [];
105

    
106
    // overlay view helper
107
    views.Overlay = views.View.extend({
108
        view_id: 'overlay',
109
        tpl_selector: '#generic-overlay-tpl',
110
        css_class: 'overlay',
111
        oneInstance: true,
112
        fixed: false,
113

    
114
        initialize: function(options, selector) {
115
            this.defaults = {
116
                load: false,
117
                closeOnClick: false,
118
                closeOnEsc: false,
119
                mask: {
120
                    color: "#444",
121
                    loadSpeed: snf.config.overlay_speed || 0,
122
                    opacity: 0.7
123
                },
124
                speed: snf.config.overlay_speed || 200
125
            }
126
            
127
            this.tpl_selector = selector || this.tpl_selector;
128
            views.Overlay.__super__.initialize.apply(this);
129
            views._overlay_index.push(this);
130

    
131
            this.options = _.extend(this.defaults, options);
132
            this.options.clone = this.options.clone == undefined ? true : this.options.clone;
133
            this.options.fixed = this.fixed;
134

    
135
            this.options.onOpen = this.options.onOpen || function() {};
136
            this.options.onClose = this.options.onClose || function() {};
137
            this.options.beforeOpen = this.options.beforeOpen || function() {};
138
            this.options.beforeClose = this.options.beforeClose || function() {};
139
            this.el = this.create_element();
140
            this.el.hide();
141
        
142
            var ajax_params = _.clone(this.options);
143

    
144
            ajax_params.onBeforeLoad = _.bind(this._beforeOpen, this);
145
            ajax_params.onLoad = _.bind(this._onOpen, this);
146
            ajax_params.onBeforeClose = _.bind(this._beforeClose, this);
147
            ajax_params.onClose = _.bind(this._onClose, this);
148
            ajax_params.oneInstance = this.oneInstance;
149
            // create overlay
150
            // TODO: does this return overlay object ?? (to avoid the next code line)
151
            $(this.el).overlay(ajax_params);
152

    
153
            this.overlay = $(this.el).overlay();
154
            this.append_css = this.options ? this.options.css_class ? this.options.css_class : "" : "";
155

    
156
            this.is_visible = false;
157
            return this;
158
        },
159

    
160
        create_element: function() {
161
            var el = undefined;
162
            if (this.options.clone) {
163
                el = $(this.tpl_selector).clone();
164
            } else {
165
                el = $(this.tpl_selector);
166
            }
167
            
168
            // append content
169
            if (this.content_selector) {
170
                var content = $(this.content_selector).clone();
171
                content.addClass("content");
172
                
173
                if ($(el).find(".content").length) {
174
                    $(el).find(".content").replaceWith(content);
175
                }
176
                content.removeClass("hidden");
177
            }
178

    
179
            if (this.overlay_id) {
180
            }
181

    
182
            $(el).addClass("overlay");
183
            if (this.css_class) {
184
                $(el).addClass(this.css_class);
185
            }
186
            
187
            if (this.options.clone) {
188
                $("body").append(el);
189
            }
190

    
191
            return el;
192
        },
193

    
194
        set_title: function(title) {
195
            if (title || this.title) {
196
                $(this.el).find(".overlay-header .title").html(title || this.title)
197
            }
198
        },
199

    
200
        set_subtitle: function(subtitle) {
201
            if (subtitle || this.subtitle) {
202
                $(this.el).find(".overlay-header .subtitle").html(subtitle || this.subtitle)
203
            }
204
        },
205

    
206
        _beforeOpen: function() {
207
            this.is_visible = true;
208
            if (this.append_css) {
209
                $(this.el).addClass(this.append_css);
210
            }
211

    
212
            this.set_title();
213
            this.set_subtitle();
214
            
215
            this.beforeOpen.apply(this, arguments);
216
            this.options.beforeOpen.apply(this, arguments);
217
        },
218

    
219
        _onOpen: function() {
220
            // clear previously bound click events
221
            $(this.el).find(".closeme").unbind("click");
222

    
223
            if ($(this.el).find(".closeme").length) {
224
                $(this.el).find(".closeme").click(_.bind(function(){
225
                    this.hide();
226
                }, this))
227
            }
228
            this.onOpen.apply(this, arguments);
229
            this.options.onOpen.apply(this, arguments);
230
        },
231

    
232
        _beforeClose: function() {
233
            this.is_visible = false;
234
            this.beforeClose.apply(this, arguments);
235
            this.options.beforeClose.apply(this, arguments);
236
        },
237

    
238
        _onClose: function() {
239
            if (this.append_css) {
240
                $(this.el).removeClass(this.append_css);
241
            }
242
            this.onClose.apply(this, arguments);
243
            this.options.onClose.apply(this, arguments);
244
        },
245

    
246
        beforeOpen: function () {},
247
        onOpen: function () {},
248
        beforeClose: function () {},
249
        onClose: function () {},
250

    
251
        show: function() {
252
            // close opened overlays
253
            var hidden = false;
254
            _.each(views._overlay_index, function(ovr){
255
                if (ovr == this) { return };
256
                if (ovr.visible()) {
257
                    hidden = true;
258
                    ovr.hide();
259
                }
260
            })
261

    
262
            // do we need to wait for other overlays to close ???
263
            if (hidden) { delay = 300; } else { delay = 0; }
264

    
265
            this.is_visible = true;
266
            window.setTimeout(_.bind(function(){ this.overlay.load() }, this), delay)
267
            return this;
268
        },
269

    
270
        hide: function() {
271
            if (!this.overlay.isOpened()) {
272
                // if its not opened events wont trigger
273
                this._onClose()
274
            } else {
275
                this.overlay.close();
276
            }
277
            return this;
278
        }
279
    });
280

    
281
    
282
    // overlay view helper
283
    views.VMOverlay = views.Overlay.extend({
284

    
285
        initialize: function() {
286
            views.VMOverlay.__super__.initialize.apply(this);
287
            this.vm = undefined;
288
            this.view_id_tpl = this.view_id;
289

    
290
            _.bindAll(this, "_handle_vm_change", "_handle_vm_remove");
291
        },
292

    
293
        set_vm: function(vm) {
294
            if (this.vm) { this.unbind_vm_handlers };
295
            this.vm = vm;
296
            this.view_id = this.view_id + "_" + vm.id;
297
            this.bind_vm_handlers();
298
        },
299

    
300
        bind_vm_handlers: function() {
301
            this.log.debug("binding handlers");
302
            this.vm.bind("change", this._handle_vm_change);
303
            storage.vms.bind("remove", this._handle_vm_remove);
304
        },
305
        
306
        unbind_vm_handlers: function() {
307
            this.log.debug("unbinding handlers", this.vm);
308
            if (!this.vm) { return };
309
            this.vm.unbind("change", this._handle_vm_change);
310
            storage.vms.unbind("remove", this._handle_vm_remove);
311
        },
312
        
313
        _update_vm_details: function() { 
314
            if (!this.vm) { console.error("invalid view state"); return }
315
            this.set_subtitle(this.vm.escape("name") + snf.ui.helpers.vm_icon_tag(this.vm, "small"));
316
            this.update_vm_details() 
317
        },
318

    
319
        update_vm_details: function() {},
320
        handle_vm_remove: function() {},
321
        handle_vm_change: function () {},
322
        
323
        _handle_vm_remove: function(vm, collection) {
324
            if (this.vm && vm.id == this.vm.id) {
325
                this.hide();
326
            }
327
            this.handle_vm_remove();
328
        },
329
        
330
        _handle_vm_change: function(vm) {
331
            this._update_vm_details();
332
            this.handle_vm_change(vm);
333
        },
334
        
335
        beforeClose: function() {
336
            this.unbind_vm_handlers();
337
            this.vm = undefined;
338
        },
339

    
340
        show: function(vm) {
341
            this.set_vm(vm);
342
            views.VMOverlay.__super__.show.apply(this, arguments);
343
            this._update_vm_details();
344
        }
345

    
346
    });
347

    
348
    snf.config.update_hidden_views = true;
349

    
350
})(this);