Revision 12a0db5d

b/ui/static/snf/js/ui/web/ui_model_views.js
1
;(function(root){
2

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

  
14
    var views = snf.views = snf.views || {}
15

  
16
    // shortcuts
17
    var bb = root.Backbone;
18
    
19
    // Reusable collection view
20
    // Helpers handling list/edit functionality of a specific Collection object
21
    views.CollectionView = views.View.extend({
22

  
23
        collection: undefined,
24
        
25
        id_tpl: 'model-item-{0}',
26
        list_tpl: '#model-item-tpl',
27
        
28
        force_reset_before_fetch: true,
29
        auto_append_actions: true,
30

  
31
        initialize: function(options) {
32
            views.CollectionView.__super__.initialize.apply(this, arguments);
33
            _.bindAll(this);
34

  
35
            this.loading = this.$(".loading-models");
36
            this.content = this.$(".content");
37
            this.list = this.$(".model-list .items-list");
38
            this.list_cont = this.$(".model-list");
39
            this.form = this.$(".model-form");
40
            this.empty_msg = this.$(".items-empty-msg");
41
            
42
            this.init_collection_handlers();
43
            this.init_handlers();
44
            this.close_form();
45
            this.content.hide();
46
            this.loading.show();
47
            this.update_models();
48
            this.items = [];
49
            this.submiting = false;
50
        },
51
        
52
        update_models: function() {
53
            this.collection.fetch({success:this.handle_reset});
54
        },
55
        
56
        init_handlers: function() {
57
            this.$(".add-new").click(_.bind(this.show_form, this, undefined));
58

  
59
            this.form.find(".form-action.cancel").click(this.close_form);
60
            this.form.find(".form-action.submit").click(this.submit_form);
61
            
62
            var self = this;
63
            this.form.find("form").submit(function(e){
64
                e.preventDefault();
65
                self.submit_form();
66
                return false;
67
            });
68

  
69
            this.$(".quick-add").click(_.bind(this.show_form, this, undefined));
70
        },
71

  
72
        init_collection_handlers: function() {
73
            this.collection.bind("reset", this.handle_reset);
74
        },
75

  
76
        reset_handlers: function() {
77
            this.collection.unbind("reset", this.handle_reset);
78
        },
79
            
80
        set_items: function(models) {
81
            this.items = _.map(models, function(m) { return m.id });
82
        },
83

  
84
        handle_reset: function(collection, models) {
85
            this.loading.hide();
86
            this.content.show();
87

  
88
            if (this.force_reset_before_update) {
89
                this.reset_list();
90
            }
91

  
92
            this.update_list(this.collection.models);
93
            this.update_removed(this.items, this.collection.models);
94

  
95
            this.set_items(this.collection.models);
96
        },
97

  
98
        show_form: function(model) {
99
            var create = (model === undefined ? true : false);
100
        
101
            if (create) {
102
                this.form.find(".new-title").show();
103
                this.form.find(".edit-title").hide();
104
            } else {
105
                this.form.find(".new-title").hide();
106
                this.form.find(".edit-title").show();
107
            }
108

  
109
            var model = model || new this.collection.model();
110
            this.list_cont.hide();
111

  
112
            this.reset_form(model);
113
            if (!snf.util.canReadFile()) {
114
                this.form.find(".fromfile-field").hide();
115
            }
116
            this.form.show();
117

  
118
            this.editing = true;
119
            this.editing_id = model.id;
120
            this.creating = create ? true : false;
121

  
122
            $(this.form.find("input").get(0)).focus();
123
            this.reset_form_errors();
124
        },
125

  
126
        reset_form: function(model) {
127
            if (!model) {
128
                this.form.find("input, textarea").val("");
129
                return;
130
            }
131

  
132
            this.update_form_from_model(model);
133
        },
134
        
135
        show_list_msg: function(type, msg) {
136
            this.list_messages = this.list_messages || this.$(".list-messages");
137
            var el = $('<div class="{0}">{1}</div>'.format(type, msg));
138
            this.list_messages.append(el);
139
            window.setTimeout(function(){
140
                el.fadeOut(300).delay(300).remove();
141
            }, this.message_timeout || 4000)
142
        },
143
        
144
        get_fields_map: function() {
145
            return {};
146
        },
147
        
148
        reset_form_errors: function() {
149
            this.form.find(".form-field").removeClass("error");
150
            this.form.find(".form-field .errors").empty();
151
        },
152

  
153
        show_form_errors: function(errors) {
154
            this.reset_form_errors();
155
            var fields_map = this.get_fields_map();
156
            this.form_messages = this.form_messages || this.$(".form-messages");
157
            
158
            _.each(errors.errors, _.bind(function(error, key){
159
                var field = this.form.find(fields_map[key]).closest(".form-field");
160
                field.addClass("error");
161
                _.each(error, function(error_msg) {
162
                    var error_el = $('<div class="error">{0}</div>'.format(error_msg));
163
                    field.find(".errors").append(error_el);
164
                });
165
            }, this));
166
            //var el = $('<div class="error">{1}</div>'.format(type, msg));
167
            //this.list_messages.append(el);
168
        },
169

  
170
        clean_form_errors: function() {
171
        },
172
        
173
        submit_form: function() {
174
            if (this.submiting) { return };
175
            var errlist = this.validate_data(this.get_form_data());
176
            if (errlist.empty()) {
177
                this.save_model(this.get_form_data());
178
            } else {
179
                this.show_form_errors(errlist);
180
            }
181
        },
182

  
183
        close_form: function() {
184
            this.editing = false;
185
            this.editing_id = undefined;
186
            this.creating = false;
187

  
188
            this.form.hide();
189
            this.list_cont.show();
190
            this.list_cont.find("h3").show();
191
        },
192

  
193
        create_model_element: function(model) {
194
            var el = this.$(this.list_tpl).clone();
195

  
196
            el.removeClass("hidden");
197
            el.addClass("model-item");
198
            el.attr("id", "item-content-" + this.id_tpl.format(model.id));
199

  
200
            if (this.auto_append_actions) {
201
                this.append_actions(el, model);
202
            }
203

  
204
            return el;
205
        },
206

  
207
        append_actions: function(el, model) {
208
            var actions = $('<div class="item-actions">' +
209
                            '<div class="item-action remove">remove</div>' + 
210
                            '<div class="item-action confirm-remove confirm">' +
211
                            '<span class="text">confirm</span>' + 
212
                            '<span class="cancel-remove cancel">cancel</span></div>' + 
213
                            '<div class="item-action edit">edit</div>' +
214
                            '</div>');
215
            el.append(actions);
216
        },
217

  
218
        bind_list_item_actions: function(el, model) {
219
            el.find(".item-actions .edit").click(_.bind(this.show_form, this, model));
220
            el.find(".item-actions .remove").click(_.bind(this.show_confirm_remove, this, el, model));
221
            el.find(".item-actions .confirm-remove .do-confirm").click(_.bind(this.delete_model, this, model)).hide();
222
            el.find(".item-actions .confirm-remove .cancel-remove").click(_.bind(this.cancel_confirm_remove, 
223
                                                                        this, el, model)).hide();
224
            
225
            // initialize download link
226
            snf.util.promptSaveFile(el.find(".item-actions .download"), model.get_filename(), model.get("content"))
227
        },
228

  
229
        show_confirm_remove: function(el, model) {
230
            var confirmed = confirm(this.confirm_delete_msg || "Are you sure you want to delete this entry ?");
231
            if (confirmed) {
232
                this.delete_model(model);
233
            }
234
            //el.closest(".model-item").addClass("pending-delete");
235
        },
236

  
237
        cancel_confirm_remove: function(el, model) {
238
            el.closest(".model-item").removeClass("pending-delete");
239
        },
240

  
241
        new_list_el: function(model) {
242
            var list_el = $("<li></li>");
243
            el = this.create_model_element(model);
244
            list_el.attr("id", this.id_tpl.format(model.id));
245
            list_el.addClass("model-item");
246
            this.update_list_item(el, model, true);
247
            list_el.append(el);
248
            this.bind_list_item_actions(list_el, model);
249
            return list_el;
250
        },
251

  
252
        item_el: function(id) {
253
            return this.$("#" + this.id_tpl.format(id));
254
        },
255

  
256
        item_exists: function(model) {
257
            return this.item_el(model.id).length > 0;
258
        },
259

  
260
        reset_list: function() {
261
            this.list.find("model-item").remove();
262
        },
263
        
264
        save_model: function(data) {
265
            this.form.find("form-action.submit").addClass("in-progress");
266
            this.submiting = true;
267

  
268
            var options = {
269
                success: _.bind(function(){
270
                    this.update_models();
271
                    this.close_form();
272
                    this.show_list_msg("success", this.create_success_msg || "Entry created");
273
                }, this),
274

  
275
                error: _.bind(function(){
276
                    this.show_form_errors({'': this.create_failed_msg || 'Entry submition failed'})
277
                }, this),
278

  
279
                complete: _.bind(function(){
280
                    this.submiting = false;
281
                    this.form.find("form-action.submit").addClass("in-progress");
282
                }, this)
283
            }
284

  
285
            if (this.editing_id && this.collection.get(this.editing_id)) {
286
                var model = this.collection.get(this.editing_id);
287
                model.save(data, options);
288
            } else {
289
                this.collection.create(data, options);
290
            }
291
        },
292

  
293
        delete_model: function(model) {
294
            this.item_el(model.id).addClass("in-progress").addClass("deleting");
295
            var self = this;
296
            model.destroy({success:this.update_models, error: function() {
297
                    self.show_list_msg("error", "Remove failed");
298
                    self.item_el(model.id).removeClass("in-progress").removeClass("deleting");
299
                }});
300
        },
301
        
302
        update_removed: function(ids, models) {
303
            var newids = _.map(models, function(m) { return m.id });
304
            _.each(_.difference(ids, newids), _.bind(function(id){
305
                this.item_el(id).remove();
306
            }, this));
307
        },
308

  
309
        update_list: function(models, reset) {
310
            var reset = reset || false;
311
            if (reset) { this.reset_list() };
312
            
313
            // handle removed items
314
            _.each(models, _.bind(function(model) {
315
                if (this.item_exists(model)) { 
316
                    this.update_list_item(this.item_el(model.id), model);
317
                    return;
318
                };
319
                this.list.append(this.new_list_el(model))
320
            }, this));
321

  
322
            this.check_empty();
323
        },
324

  
325
        check_empty: function() {
326
            if (this.collection.length == 0) {
327
                this.empty_msg.show();
328
                this.list.find(".header").hide();
329
                this.el.addClass("empty");
330
            } else {
331
                this.empty_msg.hide();
332
                this.list.find(".header").show();
333
                this.el.removeClass("empty");
334
            }
335
        },
336

  
337
        reset: function (){}
338

  
339
    });
340
})(this);
b/ui/templates/home.html
45 45
        <script src="{{ SYNNEFO_JS_URL}}ui/ie_fixes.js"></script>
46 46
    <![endif]-->
47 47
    
48
    <script src="{{ SYNNEFO_JS_URL}}utils.js"></script>
49
    <script src="{{ SYNNEFO_JS_URL}}sync.js"></script>
50
    <script src="{{ SYNNEFO_JS_URL}}models.js"></script>
51
    <script src="{{ SYNNEFO_JS_URL}}views.js"></script>
52

  
53
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_vms_base_view.js"></script>
54
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_error_view.js"></script>
55
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_icon_view.js"></script>
56
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_single_view.js"></script>
57
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_list_view.js"></script>
58
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_networks_view.js"></script>
59
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_metadata_view.js"></script>
60
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_feedback_view.js"></script>
61
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_invitations_view.js"></script>
62
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_create_view.js"></script>
63
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_connect_view.js"></script>
64
    <script src="{{ SYNNEFO_JS_WEB_URL}}ui_main_view.js"></script>
48
    <script src="{{ SYNNEFO_JS_URL }}utils.js"></script>
49
    <script src="{{ SYNNEFO_JS_URL }}sync.js"></script>
50
    <script src="{{ SYNNEFO_JS_URL }}models.js"></script>
51
    <script src="{{ SYNNEFO_JS_URL }}views.js"></script>
52

  
53
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_vms_base_view.js"></script>
54
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_model_views.js"></script>
55
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_error_view.js"></script>
56
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_icon_view.js"></script>
57
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_single_view.js"></script>
58
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_list_view.js"></script>
59
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_networks_view.js"></script>
60
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_metadata_view.js"></script>
61
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_feedback_view.js"></script>
62
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_invitations_view.js"></script>
63
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_create_view.js"></script>
64
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_connect_view.js"></script>
65
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_public_keys_view.js"></script>
66
    <script src="{{ SYNNEFO_JS_WEB_URL }}ui_main_view.js"></script>
65 67

  
66 68
    <!-- the following views require refactor -->
67 69
    <script src="{{ SYNNEFO_JS_URL }}invitations.js"></script>

Also available in: Unified diff