root / snf-app / synnefo / ui / static / snf / js / ui / web / ui_model_views.js @ 483c9197
History | View | Annotate | Download (12.8 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.create_disabled = false; |
50 |
this.submiting = false; |
51 |
}, |
52 |
|
53 |
update_models: function() { |
54 |
this.collection.fetch({success:this.handle_reset}); |
55 |
}, |
56 |
|
57 |
init_handlers: function() { |
58 |
this.$(".add-new").click(_.bind(this.show_form, this, undefined)); |
59 |
|
60 |
this.form.find(".form-action.cancel").click(this.close_form); |
61 |
this.form.find(".form-action.submit").click(this.submit_form); |
62 |
|
63 |
var self = this; |
64 |
this.form.find("form").submit(function(e){ |
65 |
e.preventDefault(); |
66 |
self.submit_form(); |
67 |
return false; |
68 |
}); |
69 |
|
70 |
this.$(".quick-add").click(_.bind(this.show_form, this, undefined)); |
71 |
}, |
72 |
|
73 |
init_collection_handlers: function() { |
74 |
this.collection.bind("reset", this.handle_reset); |
75 |
}, |
76 |
|
77 |
reset_handlers: function() { |
78 |
this.collection.unbind("reset", this.handle_reset); |
79 |
}, |
80 |
|
81 |
set_items: function(models) { |
82 |
this.items = _.map(models, function(m) { return m.id }); |
83 |
}, |
84 |
|
85 |
handle_reset: function(collection, models) { |
86 |
this.loading.hide();
|
87 |
this.content.show();
|
88 |
|
89 |
if (this.force_reset_before_update) { |
90 |
this.reset_list();
|
91 |
} |
92 |
|
93 |
this.update_list(this.collection.models); |
94 |
this.update_removed(this.items, this.collection.models); |
95 |
|
96 |
this.set_items(this.collection.models); |
97 |
}, |
98 |
|
99 |
show_form: function(model) { |
100 |
if (this.create_disabled) { return }; |
101 |
var create = (model === undefined || model.id === undefined ? true : false); |
102 |
|
103 |
if (create) {
|
104 |
this.form.find(".new-title").show(); |
105 |
this.form.find(".edit-title").hide(); |
106 |
} else {
|
107 |
this.form.find(".new-title").hide(); |
108 |
this.form.find(".edit-title").show(); |
109 |
} |
110 |
|
111 |
var model = model || new this.collection.model(); |
112 |
this.list_cont.hide();
|
113 |
|
114 |
this.reset_form(model);
|
115 |
if (!snf.util.canReadFile()) {
|
116 |
this.form.find(".fromfile-field").hide(); |
117 |
} |
118 |
this.form.show();
|
119 |
|
120 |
this.editing = true; |
121 |
this.editing_id = model.id;
|
122 |
this.creating = create ? true : false; |
123 |
|
124 |
$(this.form.find("input").get(0)).focus(); |
125 |
this.reset_form_errors();
|
126 |
}, |
127 |
|
128 |
reset_form: function(model) { |
129 |
if (!model) {
|
130 |
this.form.find("input, textarea").val(""); |
131 |
return;
|
132 |
} |
133 |
|
134 |
this.update_form_from_model(model);
|
135 |
}, |
136 |
|
137 |
show_list_msg: function(type, msg) { |
138 |
this.list_messages = this.list_messages || this.$(".list-messages"); |
139 |
var el = $('<div class="{0}">{1}</div>'.format(type, msg)); |
140 |
this.list_messages.append(el);
|
141 |
window.setTimeout(function(){
|
142 |
el.fadeOut(300).delay(300).remove(); |
143 |
}, this.message_timeout || 4000) |
144 |
}, |
145 |
|
146 |
get_fields_map: function() { |
147 |
return {};
|
148 |
}, |
149 |
|
150 |
reset_form_errors: function() { |
151 |
this.form.find(".form-field").removeClass("error"); |
152 |
this.form.find(".form-field .errors").empty(); |
153 |
this.form.find(".form-messages").empty(); |
154 |
}, |
155 |
|
156 |
show_form_errors: function(errors) { |
157 |
this.reset_form_errors();
|
158 |
var fields_map = this.get_fields_map(); |
159 |
this.form_messages = this.form_messages || this.$(".form-messages"); |
160 |
|
161 |
_.each(errors.errors, _.bind(function(error, key){
|
162 |
var field = this.form.find(fields_map[key]).closest(".form-field"); |
163 |
field.addClass("error");
|
164 |
_.each(error, function(error_msg) {
|
165 |
var error_el = $('<div class="error">{0}</div>'.format(error_msg)); |
166 |
field.find(".errors").append(error_el);
|
167 |
}); |
168 |
}, this));
|
169 |
|
170 |
var msg = errors['']; |
171 |
if (msg) {
|
172 |
var el = $('<div class="error">{0}</div>'.format(msg)); |
173 |
this.$(".form-messages").append(el); |
174 |
} |
175 |
}, |
176 |
|
177 |
clean_form_errors: function() { |
178 |
|
179 |
}, |
180 |
|
181 |
submit_form: function() { |
182 |
if (this.submiting) { return }; |
183 |
var errlist = this.validate_data(this.get_form_data()); |
184 |
if (errlist.empty()) {
|
185 |
this.save_model(this.get_form_data()); |
186 |
} else {
|
187 |
this.show_form_errors(errlist);
|
188 |
} |
189 |
}, |
190 |
|
191 |
close_form: function() { |
192 |
this.editing = false; |
193 |
this.editing_id = undefined; |
194 |
this.creating = false; |
195 |
|
196 |
this.form.hide();
|
197 |
this.list_cont.show();
|
198 |
this.list_cont.find("h3").show(); |
199 |
}, |
200 |
|
201 |
create_model_element: function(model) { |
202 |
var el = this.$(this.list_tpl).clone(); |
203 |
|
204 |
el.removeClass("hidden");
|
205 |
el.addClass("model-item");
|
206 |
el.attr("id", "item-content-" + this.id_tpl.format(model.id)); |
207 |
|
208 |
if (this.auto_append_actions) { |
209 |
this.append_actions(el, model);
|
210 |
} |
211 |
|
212 |
return el;
|
213 |
}, |
214 |
|
215 |
append_actions: function(el, model) { |
216 |
var actions = $('<div class="item-actions">' + |
217 |
'<div class="item-action remove">remove</div>' +
|
218 |
'<div class="item-action confirm-remove confirm">' +
|
219 |
'<span class="text">confirm</span>' +
|
220 |
'<span class="cancel-remove cancel">cancel</span></div>' +
|
221 |
'<div class="item-action edit">edit</div>' +
|
222 |
'</div>');
|
223 |
el.append(actions); |
224 |
}, |
225 |
|
226 |
bind_list_item_actions: function(el, model) { |
227 |
el.find(".item-actions .edit").click(_.bind(this.show_form, this, model)); |
228 |
el.find(".item-actions .remove").click(_.bind(this.show_confirm_remove, this, el, model)); |
229 |
el.find(".item-actions .confirm-remove .do-confirm").click(_.bind(this.delete_model, this, model)).hide(); |
230 |
el.find(".item-actions .confirm-remove .cancel-remove").click(_.bind(this.cancel_confirm_remove, |
231 |
this, el, model)).hide();
|
232 |
|
233 |
// initialize download link
|
234 |
snf.util.promptSaveFile(el.find(".item-actions .download"), model.get_filename(), model.get("content")) |
235 |
}, |
236 |
|
237 |
show_confirm_remove: function(el, model) { |
238 |
var confirmed = confirm(this.confirm_delete_msg || "Are you sure you want to delete this entry ?"); |
239 |
if (confirmed) {
|
240 |
this.delete_model(model);
|
241 |
} |
242 |
//el.closest(".model-item").addClass("pending-delete");
|
243 |
}, |
244 |
|
245 |
cancel_confirm_remove: function(el, model) { |
246 |
el.closest(".model-item").removeClass("pending-delete"); |
247 |
}, |
248 |
|
249 |
new_list_el: function(model) { |
250 |
var list_el = $("<li></li>"); |
251 |
el = this.create_model_element(model);
|
252 |
list_el.attr("id", this.id_tpl.format(model.id)); |
253 |
list_el.addClass("model-item");
|
254 |
this.update_list_item(el, model, true); |
255 |
list_el.append(el); |
256 |
this.bind_list_item_actions(list_el, model);
|
257 |
return list_el;
|
258 |
}, |
259 |
|
260 |
item_el: function(id) { |
261 |
return this.$("#" + this.id_tpl.format(id)); |
262 |
}, |
263 |
|
264 |
item_exists: function(model) { |
265 |
return this.item_el(model.id).length > 0; |
266 |
}, |
267 |
|
268 |
reset_list: function() { |
269 |
this.list.find("model-item").remove(); |
270 |
}, |
271 |
|
272 |
save_model: function(data) { |
273 |
this.form.find("form-action.submit").addClass("in-progress"); |
274 |
this.submiting = true; |
275 |
var created = this.creating; |
276 |
var options = {
|
277 |
success: _.bind(function(){ |
278 |
this.update_models();
|
279 |
this.close_form();
|
280 |
if (created) {
|
281 |
this.show_list_msg("success", this.create_success_msg || "Entry created"); |
282 |
} else {
|
283 |
this.show_list_msg("success", this.update_success_msg || "Entry updated"); |
284 |
} |
285 |
}, this),
|
286 |
|
287 |
error: _.bind(function(data, xhr){ |
288 |
var resp_error = ""; |
289 |
// try to parse response
|
290 |
try {
|
291 |
json_resp = JSON.parse(xhr.responseText); |
292 |
resp_error = json_resp.errors[json_resp.non_field_key].join("<br />");
|
293 |
} catch (err) {}
|
294 |
|
295 |
var form_error = resp_error != "" ? |
296 |
this.create_failed_msg + " ({0})".format(resp_error) : |
297 |
this.create_failed_msg;
|
298 |
|
299 |
this.show_form_errors({'': form_error || 'Entry submition failed'}) |
300 |
}, this),
|
301 |
|
302 |
complete: _.bind(function(){ |
303 |
this.submiting = false; |
304 |
this.form.find("form-action.submit").addClass("in-progress"); |
305 |
}, this),
|
306 |
|
307 |
skip_api_error: true |
308 |
} |
309 |
|
310 |
if (this.editing_id && this.collection.get(this.editing_id)) { |
311 |
var model = this.collection.get(this.editing_id); |
312 |
model.save(data, options); |
313 |
} else {
|
314 |
this.collection.create(data, options);
|
315 |
} |
316 |
}, |
317 |
|
318 |
delete_model: function(model) { |
319 |
this.item_el(model.id).addClass("in-progress").addClass("deleting"); |
320 |
var self = this; |
321 |
model.destroy({success:this.update_models, error: function() { |
322 |
self.show_list_msg("error", "Remove failed"); |
323 |
self.item_el(model.id).removeClass("in-progress").removeClass("deleting"); |
324 |
}}); |
325 |
}, |
326 |
|
327 |
update_removed: function(ids, models) { |
328 |
var newids = _.map(models, function(m) { return m.id }); |
329 |
_.each(_.difference(ids, newids), _.bind(function(id){
|
330 |
this.item_el(id).remove();
|
331 |
}, this));
|
332 |
}, |
333 |
|
334 |
update_list: function(models, reset) { |
335 |
var reset = reset || false; |
336 |
if (reset) { this.reset_list() }; |
337 |
|
338 |
// handle removed items
|
339 |
_.each(models, _.bind(function(model) {
|
340 |
if (this.item_exists(model)) { |
341 |
this.update_list_item(this.item_el(model.id), model); |
342 |
return;
|
343 |
}; |
344 |
var item_el = this.new_list_el(model); |
345 |
this.list.prepend(item_el);
|
346 |
this.trigger("item:add", this.list, item_el, model); |
347 |
}, this));
|
348 |
|
349 |
this.check_empty();
|
350 |
}, |
351 |
|
352 |
check_empty: function() { |
353 |
if (this.collection.length == 0) { |
354 |
this.empty_msg.show();
|
355 |
this.list.find(".header").hide(); |
356 |
this.el.addClass("empty"); |
357 |
} else {
|
358 |
this.empty_msg.hide();
|
359 |
this.list.find(".header").show(); |
360 |
this.el.removeClass("empty"); |
361 |
} |
362 |
}, |
363 |
|
364 |
reset: function (){} |
365 |
|
366 |
}); |
367 |
})(this);
|