Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / ui / web / ui_metadata_view.js @ 0dee4086

History | View | Annotate | Download (9.6 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

    
53
    views.MetadataView = views.Overlay.extend({
54
        
55
        view_id: "metadata_view",
56
        content_selector: "#metadata-overlay-content",
57
        css_class: 'overlay-metadata overlay-info',
58
        overlay_id: "metadata-overlay",
59

    
60
        subtitle: "",
61
        title: "Manage tags",
62

    
63
        initialize: function(options) {
64
            views.MetadataView.__super__.initialize.apply(this);
65
            _.bindAll(this);
66

    
67
            this.current_vm = undefined;
68
            this.list = this.$(".options-list");
69
            this.tpl = this.$("li.meta-object-tpl");
70
            this.editor = this.$(".editor");
71

    
72
            this.pre_init_handlers();
73
        },
74

    
75
        pre_init_handlers: function() {
76
            this.$(".editor .cancel").click(_.bind(function(){
77
                this.close_editor();
78
            }, this))
79
            this.$(".editor .create").click(_.bind(function(){
80
                this.submit_editor();
81
            }, this));
82
        },
83

    
84
        show: function(vm) {
85
            this.current_vm = vm;
86
            this.current_vm.bind("change", this.handle_vm_change);
87
            views.MetadataView.__super__.show.apply(this);
88
        },
89

    
90
        get_meta: function() {
91
            return this.current_vm.get('metadata');
92
        },
93
        
94
        get_meta_el: function(key, value) {
95
            return this.tpl.clone();
96
        },
97

    
98
        beforeOpen: function() {
99
            this.update_layout();
100
        },
101

    
102
        update_layout: function() {
103
            if (!this.editing) {
104
                this.editor.hide();
105
            }
106

    
107
            this.update_vm_details();
108
            // update metadata
109
            this.list.empty();
110
            _.each(this.get_meta(), _.bind(function(value, key) {
111
                var el = this.get_meta_el();
112
                el.find(".title").text(util.truncate(key, 15)).attr("title", key);
113
                el.find(".value").text(util.truncate(value, 15)).attr("title", value);
114
                el.data('meta', {'key':key, 'value':value});
115
                this.list.append(el);
116
                $(el).data({key:key, value:value});
117
            }, this));
118

    
119
            this.list.append('<li class="options-object create">' + 
120
                             '<div class="options-object-cont">' +
121
                             '<span class="title">Add new</span>' + 
122
                             '<span class="value">tag</span>' + 
123
                             '</div>' + 
124
                             '</li>')
125

    
126
            this.list.show();
127
            this.init_handlers();
128
        },
129
        
130
        meta_from_el: function(el) {
131
            return el.closest("li").data("meta");
132
        },
133
    
134
        show_editor: function(meta, el) {
135
            this.editing = true;
136

    
137
            this.editor.find("label").removeClass("error");
138
            if (meta) {
139
                this.editor.find(".predefined").hide();
140
                this.editor.find("input.meta-key").val(meta.key).attr("disabled", true);
141
                this.editor.find("input.meta-value").val(meta.value);
142
            } else {
143
                this.editor.find(".predefined").show();
144
                this.editor.find("input.meta-key").val("").attr("disabled", false);
145
                this.editor.find("input.meta-value").val("");
146
            }
147
            this.$(".editor").fadeIn(200);
148

    
149
            if (meta) {
150
                this.editor.find("input.meta-value").focus().select();
151
            } else {
152
                this.editor.find("input.meta-key").focus();
153
            }
154
            
155
            // remove predefined for existing keys
156
            var existing_keys = this.current_vm.get_meta_keys();
157
            if (!meta) {
158
                this.editor.find(".predefined-meta-key").each(function(i, el){
159
                    if (_.contains(existing_keys, $(el).text())) {
160
                        $(el).hide();
161
                    } else {
162
                        $(el).show();
163
                    }
164
                })
165
            }
166
        },
167

    
168
        update_vm_details: function() {
169
            // show proper title
170
            this.set_subtitle(this.current_vm.escape("name") + snf.ui.helpers.vm_icon_tag(this.current_vm, "small"));
171
        },
172

    
173
        validate: function(meta) {
174
            if (!meta) { return false };
175
            if ((meta.key && meta.key != "") && (meta.value && meta.value != "")) {
176
                return true;
177
            }
178
            return false;
179
        },
180

    
181
        get_editor_values: function() {
182
            var meta = {};
183
            meta.key = this.editor.find("input.meta-key").val();
184
            meta.value = this.editor.find("input.meta-value").val();
185

    
186
            meta.key = _(meta.key).trim();
187
            meta.value = _(meta.value).trim();
188
            return meta;
189
        },
190
    
191
        submit_editor: function() {
192
            if (!this.editing) { return };
193
            this.editing = false;
194
            var meta = this.get_editor_values();
195
            if (this.validate(meta)) {
196
                this.$(".editor .create").addClass('in-progress');
197
                this.current_vm.save_meta(meta, _.bind(function() {
198
                    this.close_editor();
199
                    this.$(".editor .create").removeClass('in-progress');
200
                }, this));
201
            } else {
202
                this.editing = true;
203
                this.editor.find(".form-field label").addClass("error");
204
            }
205

    
206
        },
207

    
208
        remove_meta: function(key) {
209
            this.current_vm.remove_meta(key);
210
        },
211

    
212
        close_editor: function() {
213
            this.$(".editor").fadeOut(100);
214
            this.editing = false;
215
        },
216

    
217
        init_handlers: function() {
218
            var self = this;
219
            this.list.find(".remove").click(function(e){
220
                e.preventDefault();
221
                var meta = self.meta_from_el($(this));
222
                self.remove_meta(meta.key);
223
                $(this).parent().parent().parent().remove();
224
            });
225

    
226
            this.list.find(".edit").click(function(e) {
227
                e.preventDefault();
228
                var meta = self.meta_from_el($(this));
229
                self.show_editor(meta, $(this));
230
            })
231

    
232
            //this.list.find(".options-object").dblclick(function(e) {
233
                //e.preventDefault();
234
                //var meta = self.meta_from_el($(this));
235
                //self.show_editor(meta, $(this));
236
            //})
237

    
238
            this.list.find("li.create").click(function(){
239
                self.show_create();
240
            })
241
            
242
            this.editor.find("input").keyup(_.bind(function(e){
243
                e.keyCode = e.keyCode || e.which;
244
                if (e.keyCode == 13) { this.submit_editor() };    
245
                if (e.keyCode == 27) { this.close_editor() };    
246
            }, this));
247

    
248
            this.editor.find(".predefined-meta-key").click(function() {
249
                self.editor.find("input.meta-key").val($(this).text());
250
                self.editor.find("input.meta-value").focus();
251
            })
252

    
253
        },
254

    
255
        show_create: function() {
256
            this.$(".editor .create").removeClass('in-progress');
257
            this.show_editor();
258
        },
259

    
260
        unbind_vm_handlers: function() {
261
            if (!this.current_vm) { return }
262
            this.current_vm.unbind("change", this.handle_vm_change);
263
        },
264

    
265
        handle_vm_change: function(vm) {
266
            // if overlay has been closed and for
267
            // some reason change event still triggers
268
            // force event unbind
269
            if (!this.current_vm) {
270
                vm.unbind("change", this.handle_vm_change);
271
                return;
272
            } 
273

    
274
            this.update_vm_details();
275
            this.update_layout();
276
        },
277

    
278
        onClose: function() {
279
            this.editing = false;
280
            this.unbind_vm_handlers();
281
            this.current_vm = undefined;
282
        }
283
    });
284
    
285
})(this);