|
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);
|