root / ui / static / snf / js / ui / web / ui_model_views.js @ c72a830d
History | View | Annotate | Download (12.3 kB)
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 |
this.form.find(".form-messages").empty(); |
152 |
}, |
153 |
|
154 |
show_form_errors: function(errors) { |
155 |
this.reset_form_errors();
|
156 |
var fields_map = this.get_fields_map(); |
157 |
this.form_messages = this.form_messages || this.$(".form-messages"); |
158 |
|
159 |
_.each(errors.errors, _.bind(function(error, key){
|
160 |
var field = this.form.find(fields_map[key]).closest(".form-field"); |
161 |
field.addClass("error");
|
162 |
_.each(error, function(error_msg) {
|
163 |
var error_el = $('<div class="error">{0}</div>'.format(error_msg)); |
164 |
field.find(".errors").append(error_el);
|
165 |
}); |
166 |
}, this));
|
167 |
|
168 |
var msg = errors['']; |
169 |
if (msg) {
|
170 |
var el = $('<div class="error">{0}</div>'.format(msg)); |
171 |
this.$(".form-messages").append(el); |
172 |
} |
173 |
}, |
174 |
|
175 |
clean_form_errors: function() { |
176 |
|
177 |
}, |
178 |
|
179 |
submit_form: function() { |
180 |
if (this.submiting) { return }; |
181 |
var errlist = this.validate_data(this.get_form_data()); |
182 |
if (errlist.empty()) {
|
183 |
this.save_model(this.get_form_data()); |
184 |
} else {
|
185 |
this.show_form_errors(errlist);
|
186 |
} |
187 |
}, |
188 |
|
189 |
close_form: function() { |
190 |
this.editing = false; |
191 |
this.editing_id = undefined; |
192 |
this.creating = false; |
193 |
|
194 |
this.form.hide();
|
195 |
this.list_cont.show();
|
196 |
this.list_cont.find("h3").show(); |
197 |
}, |
198 |
|
199 |
create_model_element: function(model) { |
200 |
var el = this.$(this.list_tpl).clone(); |
201 |
|
202 |
el.removeClass("hidden");
|
203 |
el.addClass("model-item");
|
204 |
el.attr("id", "item-content-" + this.id_tpl.format(model.id)); |
205 |
|
206 |
if (this.auto_append_actions) { |
207 |
this.append_actions(el, model);
|
208 |
} |
209 |
|
210 |
return el;
|
211 |
}, |
212 |
|
213 |
append_actions: function(el, model) { |
214 |
var actions = $('<div class="item-actions">' + |
215 |
'<div class="item-action remove">remove</div>' +
|
216 |
'<div class="item-action confirm-remove confirm">' +
|
217 |
'<span class="text">confirm</span>' +
|
218 |
'<span class="cancel-remove cancel">cancel</span></div>' +
|
219 |
'<div class="item-action edit">edit</div>' +
|
220 |
'</div>');
|
221 |
el.append(actions); |
222 |
}, |
223 |
|
224 |
bind_list_item_actions: function(el, model) { |
225 |
el.find(".item-actions .edit").click(_.bind(this.show_form, this, model)); |
226 |
el.find(".item-actions .remove").click(_.bind(this.show_confirm_remove, this, el, model)); |
227 |
el.find(".item-actions .confirm-remove .do-confirm").click(_.bind(this.delete_model, this, model)).hide(); |
228 |
el.find(".item-actions .confirm-remove .cancel-remove").click(_.bind(this.cancel_confirm_remove, |
229 |
this, el, model)).hide();
|
230 |
|
231 |
// initialize download link
|
232 |
snf.util.promptSaveFile(el.find(".item-actions .download"), model.get_filename(), model.get("content")) |
233 |
}, |
234 |
|
235 |
show_confirm_remove: function(el, model) { |
236 |
var confirmed = confirm(this.confirm_delete_msg || "Are you sure you want to delete this entry ?"); |
237 |
if (confirmed) {
|
238 |
this.delete_model(model);
|
239 |
} |
240 |
//el.closest(".model-item").addClass("pending-delete");
|
241 |
}, |
242 |
|
243 |
cancel_confirm_remove: function(el, model) { |
244 |
el.closest(".model-item").removeClass("pending-delete"); |
245 |
}, |
246 |
|
247 |
new_list_el: function(model) { |
248 |
var list_el = $("<li></li>"); |
249 |
el = this.create_model_element(model);
|
250 |
list_el.attr("id", this.id_tpl.format(model.id)); |
251 |
list_el.addClass("model-item");
|
252 |
this.update_list_item(el, model, true); |
253 |
list_el.append(el); |
254 |
this.bind_list_item_actions(list_el, model);
|
255 |
return list_el;
|
256 |
}, |
257 |
|
258 |
item_el: function(id) { |
259 |
return this.$("#" + this.id_tpl.format(id)); |
260 |
}, |
261 |
|
262 |
item_exists: function(model) { |
263 |
return this.item_el(model.id).length > 0; |
264 |
}, |
265 |
|
266 |
reset_list: function() { |
267 |
this.list.find("model-item").remove(); |
268 |
}, |
269 |
|
270 |
save_model: function(data) { |
271 |
this.form.find("form-action.submit").addClass("in-progress"); |
272 |
this.submiting = true; |
273 |
|
274 |
var options = {
|
275 |
success: _.bind(function(){ |
276 |
this.update_models();
|
277 |
this.close_form();
|
278 |
this.show_list_msg("success", this.create_success_msg || "Entry created"); |
279 |
}, this),
|
280 |
|
281 |
error: _.bind(function(data, xhr){ |
282 |
var resp_error = ""; |
283 |
// try to parse response
|
284 |
try {
|
285 |
json_resp = JSON.parse(xhr.responseText); |
286 |
resp_error = json_resp.errors[json_resp.non_field_key].join("<br />");
|
287 |
} catch (err) {}
|
288 |
|
289 |
var form_error = resp_error != "" ? |
290 |
this.create_failed_msg + " ({0})".format(resp_error) : |
291 |
this.create_failed_msg;
|
292 |
|
293 |
this.show_form_errors({'': form_error || 'Entry submition failed'}) |
294 |
}, this),
|
295 |
|
296 |
complete: _.bind(function(){ |
297 |
this.submiting = false; |
298 |
this.form.find("form-action.submit").addClass("in-progress"); |
299 |
}, this),
|
300 |
|
301 |
skip_api_error: true |
302 |
} |
303 |
|
304 |
if (this.editing_id && this.collection.get(this.editing_id)) { |
305 |
var model = this.collection.get(this.editing_id); |
306 |
model.save(data, options); |
307 |
} else {
|
308 |
this.collection.create(data, options);
|
309 |
} |
310 |
}, |
311 |
|
312 |
delete_model: function(model) { |
313 |
this.item_el(model.id).addClass("in-progress").addClass("deleting"); |
314 |
var self = this; |
315 |
model.destroy({success:this.update_models, error: function() { |
316 |
self.show_list_msg("error", "Remove failed"); |
317 |
self.item_el(model.id).removeClass("in-progress").removeClass("deleting"); |
318 |
}}); |
319 |
}, |
320 |
|
321 |
update_removed: function(ids, models) { |
322 |
var newids = _.map(models, function(m) { return m.id }); |
323 |
_.each(_.difference(ids, newids), _.bind(function(id){
|
324 |
this.item_el(id).remove();
|
325 |
}, this));
|
326 |
}, |
327 |
|
328 |
update_list: function(models, reset) { |
329 |
var reset = reset || false; |
330 |
if (reset) { this.reset_list() }; |
331 |
|
332 |
// handle removed items
|
333 |
_.each(models, _.bind(function(model) {
|
334 |
if (this.item_exists(model)) { |
335 |
this.update_list_item(this.item_el(model.id), model); |
336 |
return;
|
337 |
}; |
338 |
this.list.append(this.new_list_el(model)) |
339 |
}, this));
|
340 |
|
341 |
this.check_empty();
|
342 |
}, |
343 |
|
344 |
check_empty: function() { |
345 |
if (this.collection.length == 0) { |
346 |
this.empty_msg.show();
|
347 |
this.list.find(".header").hide(); |
348 |
this.el.addClass("empty"); |
349 |
} else {
|
350 |
this.empty_msg.hide();
|
351 |
this.list.find(".header").show(); |
352 |
this.el.removeClass("empty"); |
353 |
} |
354 |
}, |
355 |
|
356 |
reset: function (){} |
357 |
|
358 |
}); |
359 |
})(this);
|