Merge lp:~openerp-dev/openobject-client-web/trunk-cal-events-readonly into lp:openobject-client-web/trunk
- trunk-cal-events-readonly
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 3734 |
Proposed branch: | lp:~openerp-dev/openobject-client-web/trunk-cal-events-readonly |
Merge into: | lp:openobject-client-web/trunk |
Diff against target: |
774 lines (+206/-131) 10 files modified
addons/view_calendar/static/javascript/calendar_gantt.js (+78/-68) addons/view_calendar/static/javascript/calendar_month.js (+26/-16) addons/view_calendar/static/javascript/calendar_utils.js (+10/-1) addons/view_calendar/static/javascript/calendar_week.js (+48/-22) addons/view_calendar/widgets/_base.py (+27/-5) addons/view_calendar/widgets/templates/day.mako (+2/-2) addons/view_calendar/widgets/templates/gantt.mako (+1/-1) addons/view_calendar/widgets/templates/month.mako (+2/-2) addons/view_calendar/widgets/templates/week.mako (+12/-12) addons/view_calendar/widgets/widgets.py (+0/-2) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-client-web/trunk-cal-events-readonly |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Xavier (Open ERP) (community) | Approve | ||
OpenERP R&D Web Team | functional tests (different browsers), non regression tests | Pending | |
Review via email:
|
Commit message
Description of the change
Some events have their 'starting date' and 'end date' read only depending on their state. For example, you cannot edit crm.meeting dates if it's state is 'done'.
But the calendar was not taking care of this and you could drag and drop events regardless of their state.
This branch is supposed to fix that.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Xavier (Open ERP) (xmo-deactivatedaccount) wrote : | # |
- 3716. By Olivier Laurent (Open ERP)
-
[IMP] calendar: simplified the way we access the 'state' attribute from fields
PS: thanks to Xavier
- 3717. By Olivier Laurent (Open ERP)
-
[FIX] gantt: calendar objects with server side readonly date fields should not be movable
- 3718. By Olivier Laurent (Open ERP)
-
[FIX] calendar, gantt: MochiKit -> jQuery
- 3719. By Olivier Laurent (Open ERP)
-
[FIX] calendar, gantt: MochiKit -> jQuery
- 3720. By Olivier Laurent (Open ERP)
-
[IMP] calendar: removed '_is_event_
droppable' method
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Olivier Laurent (Open ERP) (olt) wrote : | # |
> * New code should avoid using Mochikit functions when possible, and use jQuery
> instead (hasElementClass, getNodeAttribute)
Ok. I did it but only for functions I added myself. I left the other one as is.
> * The call to self._is_
> final TinyEvent call
Did it.
> * In the templates, TinyEvent.droppable is accessed 6 times (I think) and
> every single time it's in a conditional to decide on the right class to set.
> Maybe TinyEvent should have an additional droppable_class property which would
> directly return the right class for the event, no?
I started by adding an attribute to the div but I ran into some problems, which were probably related to something else. Since it's not always easy to debug javascript, I moved that atrribute to a new class. Perhaps that in the mean time, my problems were solved but I left that class. Now that code is running with the class, I could probably move it to an attribute again.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Xavier (Open ERP) (xmo-deactivatedaccount) wrote : | # |
> Ok. I did it but only for functions I added myself. I left the other one as is.
Yep, sensible, didn't expect you to fix everything.
Note that (for next time around maybe) jQuery's `hasClass` works on element sets, so
jQuery(
could also have been written
jQuery(
> Did it.
OK
> I started by adding an attribute to the div but I ran into some problems, which were probably related to something else. Since it's not always easy to debug javascript, I moved that atrribute to a new class. Perhaps that in the mean time, my problems were solved but I left that class. Now that code is running with the class, I could probably move it to an attribute again.
Class is OK, I didn't mean a DOM attribute, just that the code
${evt.droppable and 'is-droppable' or 'is-not-droppable'}
is repeated several time, and thus that maybe instead of having `evt.droppable` we could have `evt.droppable_
- 3721. By Olivier Laurent (Open ERP)
-
[IMP] calendar, gantt: movability and resizeability (based on object 'state') are now separated
- 3722. By Olivier Laurent (Open ERP)
-
[IMP] calendar, gantt: minor modifs
Preview Diff
1 | === modified file 'addons/view_calendar/static/javascript/calendar_gantt.js' |
2 | --- addons/view_calendar/static/javascript/calendar_gantt.js 2010-10-08 06:38:34 +0000 |
3 | +++ addons/view_calendar/static/javascript/calendar_gantt.js 2010-10-27 09:48:00 +0000 |
4 | @@ -18,28 +18,28 @@ |
5 | }; |
6 | |
7 | GanttCalendar.prototype = { |
8 | - |
9 | + |
10 | __init__: function(options) { |
11 | - |
12 | + |
13 | this.options = MochiKit.Base.update({ |
14 | - |
15 | + |
16 | }, options || {}); |
17 | - |
18 | + |
19 | this.starts = MochiKit.DateTime.isoDate(getNodeAttribute('calGantt', 'dtStart')); |
20 | - |
21 | + |
22 | this.mode = openobject.dom.get('_terp_selected_mode').value; |
23 | this.range = parseInt(getNodeAttribute('calGantt', 'dtRange')) || 7; |
24 | |
25 | this.scale = 0; |
26 | this.header = new GanttCalendar.Header(this); |
27 | - |
28 | + |
29 | this.events = {}; |
30 | - this.groups = {}; |
31 | - |
32 | + this.groups = {}; |
33 | + |
34 | this._makeEvents(); |
35 | - |
36 | + |
37 | MochiKit.DOM.removeElement('calBodySect'); |
38 | - |
39 | + |
40 | var tbl = TABLE(null, |
41 | TBODY(null, |
42 | TR(null, |
43 | @@ -48,13 +48,13 @@ |
44 | TR(null, |
45 | TD({'width': 200, 'nowrap': 'nowrap'}, DIV({'id': 'calListC'})), |
46 | TD({}, DIV({'id': 'calGridC'}))))); |
47 | - |
48 | + |
49 | tbl.cellPadding = 0; |
50 | tbl.cellSpacing = 0; |
51 | - |
52 | + |
53 | tbl.style.width = '100%'; |
54 | tbl.style.height = '100%'; |
55 | - |
56 | + |
57 | MochiKit.DOM.appendChildNodes('calGantt', tbl); |
58 | |
59 | this.grid = new GanttCalendar.Grid(this); |
60 | @@ -65,7 +65,7 @@ |
61 | this.lc = openobject.dom.get('calListC'); |
62 | |
63 | this.attachSignals(); |
64 | - |
65 | + |
66 | }, |
67 | |
68 | __delete__: function() { |
69 | @@ -96,21 +96,21 @@ |
70 | }, |
71 | |
72 | onResize: function(evt) { |
73 | - |
74 | + |
75 | var h1 = getElementDimensions('calGroupC').h; |
76 | var h2 = openobject.dom.get('calGridC').clientHeight; |
77 | |
78 | setElementDimensions('calList', {h: h1 > h2 ? h1 : h2}); |
79 | setElementDimensions('calGrid', {h: h1 > h2 ? h1 : h2}); |
80 | }, |
81 | - |
82 | + |
83 | onScrollGrid: function(evt) { |
84 | this.lc.scrollTop = this.gc.scrollTop; |
85 | this.hc.scrollLeft = this.gc.scrollLeft; |
86 | }, |
87 | - |
88 | + |
89 | _makeEvents: function() { |
90 | - |
91 | + |
92 | this.events = {}; |
93 | this.groups = {}; |
94 | |
95 | @@ -118,7 +118,7 @@ |
96 | var groups = openobject.dom.select('div.calGroup', 'calGantt') || []; |
97 | |
98 | for (var i = 0; i < events.length; i++) { |
99 | - |
100 | + |
101 | var elem = events[i]; |
102 | var id = MochiKit.DOM.getNodeAttribute(elem, 'nRecordID'); |
103 | |
104 | @@ -142,7 +142,7 @@ |
105 | } |
106 | |
107 | for (var i = 0; i < groups.length; i++) { |
108 | - |
109 | + |
110 | var elem = groups[i]; |
111 | var id = MochiKit.DOM.getNodeAttribute(elem, 'nRecordID'); |
112 | var items = MochiKit.DOM.getNodeAttribute(elem, 'items'); |
113 | @@ -208,7 +208,7 @@ |
114 | return; |
115 | } |
116 | |
117 | - var dt = this.computeDates(element); |
118 | + var dt = this.computeDates(element); |
119 | |
120 | var pos = getElementPosition(element, 'calGrid'); |
121 | var dim = getElementDimensions(element); |
122 | @@ -243,25 +243,31 @@ |
123 | var dt = this.computeDates(element); |
124 | |
125 | var self = this; |
126 | - var req = saveCalendarRecord(id, toISOTimestamp(dt.starts), toISOTimestamp(dt.ends)); |
127 | - |
128 | - req.addCallback(function(obj) { |
129 | - |
130 | - if (obj.error) { |
131 | + |
132 | + var recordmoveinfo = getRecordMovability(element); |
133 | + if (recordmoveinfo.starts != toISOTimestamp(dt.starts) && recordmoveinfo.ends != toISOTimestamp(dt.ends)) { |
134 | + if (recordmoveinfo.is_not_movable) { |
135 | self.grid.adjust(); |
136 | - return error_display(obj.error); |
137 | + return error_display(_("This calendar object can no longer be moved !")); |
138 | + } else { |
139 | + var req = saveCalendarRecord(id, toISOTimestamp(dt.starts), toISOTimestamp(dt.ends)); |
140 | + |
141 | + req.addCallback(function(obj) { |
142 | + |
143 | + if (obj.error) { |
144 | + self.grid.adjust(); |
145 | + return error_display(obj.error); |
146 | + } |
147 | + |
148 | + self.events[id].starts = toISOTimestamp(dt.starts); |
149 | + self.events[id].ends = toISOTimestamp(dt.ends); |
150 | + |
151 | + setNodeAttribute(element, 'dtstart', toISOTimestamp(dt.starts)); |
152 | + setNodeAttribute(element, 'dtend', toISOTimestamp(dt.ends)); |
153 | + self.grid.adjust(); |
154 | + }); |
155 | } |
156 | - |
157 | - self.events[id].starts = toISOTimestamp(dt.starts); |
158 | - self.events[id].ends = toISOTimestamp(dt.ends); |
159 | - |
160 | - setNodeAttribute(element, 'dtstart', toISOTimestamp(dt.starts)); |
161 | - setNodeAttribute(element, 'dtend', toISOTimestamp(dt.ends)); |
162 | - |
163 | - //self.grid.adjust(); |
164 | - getCalendar(); |
165 | - }); |
166 | - |
167 | + } |
168 | }, |
169 | |
170 | onEventResized: function(resizable, evt) { |
171 | @@ -300,21 +306,26 @@ |
172 | se.setMinutes(m); |
173 | |
174 | var self = this; |
175 | - var req = saveCalendarRecord(id, toISOTimestamp(ds), toISOTimestamp(se)); |
176 | - |
177 | - req.addCallback(function(obj) { |
178 | - |
179 | - if (obj.error) { |
180 | + |
181 | + var recordmoveinfo = getRecordMovability(element); |
182 | + if (recordmoveinfo.is_not_resizeable) { |
183 | + self.grid.adjust(); |
184 | + return error_display(_("This calendar object can no longer be resized !")); |
185 | + } else { |
186 | + var req = saveCalendarRecord(id, toISOTimestamp(ds), toISOTimestamp(se)); |
187 | + |
188 | + req.addCallback(function(obj) { |
189 | + |
190 | + if (obj.error) { |
191 | + self.grid.adjust(); |
192 | + return error_display(obj.error); |
193 | + } |
194 | + |
195 | + self.events[id].ends = toISOTimestamp(se); |
196 | + setNodeAttribute(element, 'dtend', toISOTimestamp(se)); |
197 | self.grid.adjust(); |
198 | - return error_display(obj.error); |
199 | - } |
200 | - |
201 | - self.events[id].ends = toISOTimestamp(se); |
202 | - setNodeAttribute(element, 'dtend', toISOTimestamp(se)); |
203 | - |
204 | - //self.grid.adjust(); |
205 | - getCalendar(); |
206 | - }); |
207 | + }); |
208 | + } |
209 | } |
210 | }; |
211 | |
212 | @@ -388,11 +399,11 @@ |
213 | this.elements = [DIV({'class': 'calHeader'}, divs), DIV({'class': 'calHeader'}, subs)]; |
214 | }, |
215 | |
216 | - |
217 | + |
218 | __delete__: function() { |
219 | }, |
220 | |
221 | - adjust: function() { |
222 | + adjust: function() { |
223 | } |
224 | }; |
225 | |
226 | @@ -443,7 +454,7 @@ |
227 | }); |
228 | |
229 | appendChildNodes('calListC', DIV({'id': 'calList'}, elements)); |
230 | - |
231 | + |
232 | //XXX: MochiKit bug #140 (http://trac.mochikit.com/ticket/140) |
233 | MochiKit.Position.includeScrollOffsets = true; |
234 | |
235 | @@ -453,9 +464,9 @@ |
236 | 'only': ['calEventLabel'], |
237 | 'containment': elements |
238 | }); |
239 | - }); |
240 | + }); |
241 | }, |
242 | - |
243 | + |
244 | __delete__: function() { |
245 | forEach(this._signals, function(s) { |
246 | MochiKit.Signal.disconnect(s); |
247 | @@ -481,7 +492,6 @@ |
248 | }, |
249 | |
250 | onToggle: function(element, group, evt) { |
251 | - |
252 | var key = openobject.dom.get('_terp_model').value + '-' + group.model + '-' + group.id; |
253 | |
254 | var visible = this.stat[key]; |
255 | @@ -549,7 +559,7 @@ |
256 | GanttCalendar.Grid.prototype = { |
257 | |
258 | __init__: function(calendar) { |
259 | - |
260 | + |
261 | this.calendar = calendar; |
262 | this.starts = calendar.starts; |
263 | |
264 | @@ -562,9 +572,9 @@ |
265 | __delete__: function() { |
266 | |
267 | }, |
268 | - |
269 | + |
270 | _makeGrid: function() { |
271 | - |
272 | + |
273 | this.columns = []; |
274 | |
275 | var divs = []; |
276 | @@ -630,7 +640,7 @@ |
277 | GanttCalendar.GridColumn.prototype = { |
278 | |
279 | __init__: function(calendar, spec) { |
280 | - |
281 | + |
282 | this.calendar = calendar; |
283 | this.spec = spec; |
284 | |
285 | @@ -669,7 +679,7 @@ |
286 | |
287 | var group = calendar.groups[id]; |
288 | var events = calendar.events; |
289 | - |
290 | + |
291 | this.id = id; |
292 | this.title = group.title; |
293 | this.model = group.model; |
294 | @@ -682,7 +692,7 @@ |
295 | var self = this; |
296 | forEach(this.items, function(id) { |
297 | var evt = events[id]; |
298 | - |
299 | + |
300 | var div = DIV({ |
301 | 'nRecordID': id, |
302 | 'dtStart': evt.starts, |
303 | @@ -723,7 +733,7 @@ |
304 | calculate_usages: function() { |
305 | |
306 | this.bars = []; |
307 | - |
308 | + |
309 | if (!this.events.length) { |
310 | return; |
311 | } |
312 | @@ -789,7 +799,7 @@ |
313 | n += 1; |
314 | } |
315 | }); |
316 | - |
317 | + |
318 | div.style.backgroundColor = n == 1 ? "blue" : n > 1 ? "red" : ""; |
319 | |
320 | return div; |
321 | @@ -835,7 +845,7 @@ |
322 | forEach(this.events, function(e) { |
323 | e.adjust(); |
324 | }); |
325 | - |
326 | + |
327 | var w = 0; |
328 | |
329 | forEach(this.calendar.header.specs, function(spec) { |
330 | @@ -941,7 +951,7 @@ |
331 | } |
332 | |
333 | var x = Math.round(x / snap) * snap; |
334 | - |
335 | + |
336 | return [x + 1, y]; |
337 | } |
338 | }; |
339 | |
340 | === modified file 'addons/view_calendar/static/javascript/calendar_month.js' |
341 | --- addons/view_calendar/static/javascript/calendar_month.js 2010-09-28 12:02:18 +0000 |
342 | +++ addons/view_calendar/static/javascript/calendar_month.js 2010-10-27 09:48:00 +0000 |
343 | @@ -404,23 +404,33 @@ |
344 | e = toISOTimestamp(new Date(e)) |
345 | |
346 | var self = this; |
347 | - var req = saveCalendarRecord(id, s, e); |
348 | - |
349 | - req.addCallback(function(obj) { |
350 | - |
351 | - if (obj.error) { |
352 | - return error_display(obj.error); |
353 | + |
354 | + // check that the object was really modified to avoid unnecessary warning popups: |
355 | + var recordmoveinfo = getRecordMovability(draggable); |
356 | + if (recordmoveinfo.starts != s && recordmoveinfo.ends != e) { |
357 | + if (recordmoveinfo.is_not_movable){ |
358 | + self.calendar.onResize(); |
359 | + return error_display(_("This calendar object can no longer be moved !")); |
360 | + } else { |
361 | + var req = saveCalendarRecord(id, s, e); |
362 | + |
363 | + req.addCallback(function(obj) { |
364 | + |
365 | + if (obj.error) { |
366 | + return error_display(obj.error); |
367 | + } |
368 | + |
369 | + record.starts = s; |
370 | + record.ends = e; |
371 | + |
372 | + self.calendar.makeEvents(); |
373 | + }); |
374 | + req.addBoth(function(obj) { |
375 | + self.calendar.onResize(); |
376 | + }); |
377 | } |
378 | - |
379 | - record.starts = s; |
380 | - record.ends = e; |
381 | - |
382 | - self.calendar.makeEvents(); |
383 | - }); |
384 | - |
385 | - req.addBoth(function(obj) { |
386 | - self.calendar.onResize(); |
387 | - }); |
388 | + } |
389 | + self.calendar.onResize(); |
390 | }, |
391 | |
392 | makeEventContainers : function() { |
393 | |
394 | === modified file 'addons/view_calendar/static/javascript/calendar_utils.js' |
395 | --- addons/view_calendar/static/javascript/calendar_utils.js 2010-08-19 14:11:12 +0000 |
396 | +++ addons/view_calendar/static/javascript/calendar_utils.js 2010-10-27 09:48:00 +0000 |
397 | @@ -154,7 +154,6 @@ |
398 | } |
399 | |
400 | function saveCalendarRecord(record_id, starts, ends) { |
401 | - |
402 | var params = getFormParams('_terp_concurrency_info'); |
403 | MochiKit.Base.update(params, { |
404 | '_terp_id': record_id, |
405 | @@ -203,3 +202,13 @@ |
406 | '_terp_context': openobject.dom.get('_terp_context').value |
407 | }); |
408 | } |
409 | + |
410 | +function getRecordMovability(element) { |
411 | + return { |
412 | + starts: jQuery(element).attr('dtstart'), |
413 | + ends : jQuery(element).attr('dtend'), |
414 | + is_not_movable: jQuery(element, element.parentNode).hasClass('event-is-not-movable') |
415 | + is_not_resizeable: jQuery(element, element.parentNode).hasClass('event-is-not-resizeable') |
416 | + } |
417 | +} |
418 | + |
419 | |
420 | === modified file 'addons/view_calendar/static/javascript/calendar_week.js' |
421 | --- addons/view_calendar/static/javascript/calendar_week.js 2010-10-25 12:26:19 +0000 |
422 | +++ addons/view_calendar/static/javascript/calendar_week.js 2010-10-27 09:48:00 +0000 |
423 | @@ -84,7 +84,6 @@ |
424 | }, |
425 | |
426 | onResizeEnd : function(resizable, evt) { |
427 | - |
428 | var element = resizable.element; |
429 | |
430 | if (!hasElementClass(element, 'calEvent')) return; |
431 | @@ -98,10 +97,16 @@ |
432 | |
433 | var self = this; |
434 | |
435 | + // check that the object was really modified to avoid unnecessary warning popups: |
436 | + var recordmoveinfo = getRecordMovability(element); |
437 | + if (recordmoveinfo.is_not_resizeable) { |
438 | + self.dayGrid.adjust(); |
439 | + return error_display(_("This calendar object can no longer be resized !")); |
440 | + } |
441 | + |
442 | var req = saveCalendarRecord(id, toISOTimestamp(dt), toISOTimestamp(e)); |
443 | |
444 | req.addCallback(function(obj) { |
445 | - |
446 | if (obj.error) { |
447 | return error_display(obj.error); |
448 | } |
449 | @@ -245,7 +250,6 @@ |
450 | }, |
451 | |
452 | onDrop : function(draggable, droppable, evt) { |
453 | - |
454 | var dt = MochiKit.DateTime.isoDate(getNodeAttribute(droppable, 'dtDay')); |
455 | var id = getNodeAttribute(draggable, 'nRecordID'); |
456 | |
457 | @@ -263,23 +267,34 @@ |
458 | e = toISOTimestamp(new Date(e)) |
459 | |
460 | var self = this; |
461 | - var req = saveCalendarRecord(id, s, e); |
462 | - |
463 | - req.addCallback(function(obj) { |
464 | - |
465 | - if (obj.error) { |
466 | - return error_display(obj.error); |
467 | + |
468 | + var recordmoveinfo = getRecordMovability(draggable); |
469 | + |
470 | + // check that the object was really modified to avoid unnecessary warning popups: |
471 | + if (recordmoveinfo.starts != s && recordmoveinfo.ends != e) { |
472 | + if (recordmoveinfo.is_not_movable) { |
473 | + self.adjust(); |
474 | + return error_display(_("This calendar object can no longer be moved !")); |
475 | + } else { |
476 | + var req = saveCalendarRecord(id, s, e); |
477 | + |
478 | + req.addCallback(function(obj) { |
479 | + |
480 | + if (obj.error) { |
481 | + return error_display(obj.error); |
482 | + } |
483 | + |
484 | + record.starts = s; |
485 | + record.ends = e; |
486 | + |
487 | + self.makeEvents(); |
488 | + }); |
489 | + req.addBoth(function(obj) { |
490 | + self.adjust(); |
491 | + }); |
492 | } |
493 | - |
494 | - record.starts = s; |
495 | - record.ends = e; |
496 | - |
497 | - self.makeEvents(); |
498 | - }); |
499 | - |
500 | - req.addBoth(function(obj) { |
501 | - self.adjust(); |
502 | - }); |
503 | + } |
504 | + self.adjust(); |
505 | }, |
506 | |
507 | onMouseDown : function(evt) { |
508 | @@ -405,7 +420,7 @@ |
509 | grid: this, // reference to the grid |
510 | calendar: self.calendar, // reference to the calendar |
511 | events: [], // events in the day container |
512 | - rows: [] // mark used rows |
513 | + rows: [] // mark used rows |
514 | } |
515 | } |
516 | |
517 | @@ -638,10 +653,10 @@ |
518 | }, |
519 | |
520 | onDrop : function(draggable, droppable, evt) { |
521 | - |
522 | var dt = MochiKit.DateTime.isoDate(getNodeAttribute(droppable, 'dtDay')); |
523 | var id = getNodeAttribute(draggable, 'nRecordID'); |
524 | |
525 | + |
526 | var y = parseInt(draggable.style.top); |
527 | var h = parseInt(draggable.style.height) + 2; |
528 | |
529 | @@ -655,6 +670,17 @@ |
530 | e = new Date(e); |
531 | |
532 | var self = this; |
533 | + |
534 | + |
535 | + // check that the object was really modified to avoid unnecessary warning popups: |
536 | + var recordmoveinfo = getRecordMovability(draggable); |
537 | + if (recordmoveinfo.starts != toISOTimestamp(s) && recordmoveinfo.ends != toISOTimestamp(e)) { |
538 | + if (recordmoveinfo.is_not_movable) { |
539 | + self.adjust(); |
540 | + return error_display(_("This calendar object can no longer be moved !")); |
541 | + } |
542 | + } |
543 | + |
544 | var req = saveCalendarRecord(id, toISOTimestamp(s), toISOTimestamp(e)); |
545 | |
546 | req.addCallback(function(obj) { |
547 | @@ -676,7 +702,7 @@ |
548 | t.shift(); |
549 | t = t.join(' - '); |
550 | |
551 | - title.innerHTML = s.strftime('%I:%M %P') + ' - ' + t; |
552 | + title.innerHTML = s.strftime('%H:%M') + ' - ' + t; |
553 | }); |
554 | |
555 | req.addBoth(function(obj) { |
556 | |
557 | === modified file 'addons/view_calendar/widgets/_base.py' |
558 | --- addons/view_calendar/widgets/_base.py 2010-10-25 09:07:29 +0000 |
559 | +++ addons/view_calendar/widgets/_base.py 2010-10-27 09:48:00 +0000 |
560 | @@ -75,7 +75,7 @@ |
561 | record = {} |
562 | record_id = False |
563 | |
564 | - def __init__(self, record, starts, ends, title='', description='', dayspan=0, color=None): |
565 | + def __init__(self, record, starts, ends, title='', description='', dayspan=0, color=None, classes=None): |
566 | |
567 | super(TinyEvent, self).__init__() |
568 | |
569 | @@ -95,6 +95,8 @@ |
570 | self.create_uid = ustr(record.get('create_uid')) |
571 | self.write_uid = ustr(record.get('write_uid')) |
572 | self.write_date = ustr(record.get('write_date')) |
573 | + self.classes = classes and ' '.join(classes) or '' |
574 | + |
575 | |
576 | class ICalendar(TinyWidget): |
577 | """ Base Calendar calss |
578 | @@ -174,7 +176,7 @@ |
579 | self.info_fields = self.parse(root, view['fields']) |
580 | |
581 | fields = view['fields'] |
582 | - fields = fields.keys() + [self.date_start, self.date_stop, self.date_delay, self.color_field] |
583 | + fields = fields.keys() + [self.date_start, self.date_stop, self.date_delay, self.color_field, 'state'] |
584 | |
585 | fields = list(set([x for x in fields if x])) |
586 | |
587 | @@ -228,9 +230,11 @@ |
588 | proxy = rpc.RPCProxy(self.model) |
589 | |
590 | if self.date_stop: |
591 | + # use the correct algorithm: |
592 | domain = self.domain + [(self.date_start, '<=', days[-1].isoformat() + ' 23:59:59'), |
593 | (self.date_stop, '>=', days[0].isoformat() + ' 00:00:00')] |
594 | else: |
595 | + # cannot use the correct algorithm, use the old one: |
596 | first = days[0].month2.prev()[0] #HACK: add prev month |
597 | domain = self.domain + [(self.date_start, '>', first.isoformat()), |
598 | (self.date_start, '<', days[-1].next().isoformat())] |
599 | @@ -271,6 +275,7 @@ |
600 | ids = proxy.search(domain, 0, 0, order_by, ctx) |
601 | |
602 | result = proxy.read(ids, self.fields.keys()+['__last_update'], ctx) |
603 | + |
604 | self._update_concurrency_info(self.model, result) |
605 | self.concurrency_info = ConcurrencyInfo(self.model, ids) |
606 | if self.color_field: |
607 | @@ -310,7 +315,6 @@ |
608 | return result |
609 | |
610 | def get_event_widget(self, event): |
611 | - |
612 | title = '' # the title |
613 | description = [] # the description |
614 | if self.info_fields: |
615 | @@ -377,19 +381,37 @@ |
616 | |
617 | color_key = event.get(self.color_field) |
618 | color = self.colors.get(color_key) |
619 | + classes = self._get_classes(event) |
620 | |
621 | title = title.strip() |
622 | description = ', '.join(description).strip() |
623 | if isinstance(event['id'], int): |
624 | event_log = rpc.session.execute('object', 'execute', self.model, 'perm_read', [event['id']])[0] |
625 | - |
626 | + |
627 | event['create_date'] = event_log['create_date'] |
628 | event['create_uid'] = event_log['create_uid'][1] |
629 | if isinstance(event_log['write_uid'], tuple): |
630 | event_log['write_uid'] = event_log['write_uid'][1] |
631 | event['write_uid'] = event_log['write_uid'] |
632 | event['write_date'] = event_log['write_date'] |
633 | - return TinyEvent(event, starts, ends, title, description, dayspan=span, color=(color or None) and color[-1]) |
634 | + return TinyEvent(event, starts, ends, title, description, dayspan=span, color=(color or None) and color[-1], classes=classes) |
635 | + |
636 | + def _get_classes(self, event): |
637 | + """Get css classes which handle movable and/or resizable events""" |
638 | + classes = [] |
639 | + |
640 | + event_state = event.get('state') |
641 | + if event_state: |
642 | + # check if that event cannot be moved: |
643 | + if self.date_start and dict(self.fields[self.date_start].get('states', {}).get(event_state, [])).get('readonly'): |
644 | + classes.append('event-is-not-movable') |
645 | + # check if that event cannot be resized: |
646 | + date_to_check = self.date_stop or self.date_delay |
647 | + if date_to_check: |
648 | + if dict(self.fields[date_to_check].get('states', {}).get(event_state, [])).get('readonly'): |
649 | + classes.append('event-is-not-resizeable') |
650 | + |
651 | + return classes |
652 | |
653 | |
654 | class TinyCalendar(ICalendar): |
655 | |
656 | === modified file 'addons/view_calendar/widgets/templates/day.mako' |
657 | --- addons/view_calendar/widgets/templates/day.mako 2010-10-21 15:25:44 +0000 |
658 | +++ addons/view_calendar/widgets/templates/day.mako 2010-10-27 09:48:00 +0000 |
659 | @@ -63,7 +63,7 @@ |
660 | nWriteDate="${evt.write_date}" |
661 | nWriteId="${evt.write_uid}" |
662 | style="background-color: ${evt.color}" |
663 | - class="calEvent allDay">${evt.title}</div> |
664 | + class="calEvent allDay ${evt.classes}">${evt.title}</div> |
665 | % endif |
666 | % endfor |
667 | </div> |
668 | @@ -79,7 +79,7 @@ |
669 | nWriteDate="${evt.write_date}" |
670 | nWriteId="${evt.write_uid}" |
671 | style="background-color: ${evt.color}" |
672 | - class="calEvent noAllDay"> |
673 | + class="calEvent noAllDay ${evt.classes}"> |
674 | <div style="height: 10px;" class="calEventTitle">${evt.starts.strftime('%I:%M %P')} - ${evt.title}</div> |
675 | <div class="calEventDesc">${evt.description}</div> |
676 | <div class="calEventGrip"></div> |
677 | |
678 | === modified file 'addons/view_calendar/widgets/templates/gantt.mako' |
679 | --- addons/view_calendar/widgets/templates/gantt.mako 2010-10-21 15:25:44 +0000 |
680 | +++ addons/view_calendar/widgets/templates/gantt.mako 2010-10-27 09:48:00 +0000 |
681 | @@ -68,7 +68,7 @@ |
682 | /> |
683 | % endfor |
684 | % for evt in events: |
685 | - <div class="calEvent" |
686 | + <div class="calEvent ${evt.classes}" |
687 | nRecordID="${evt.record_id}" |
688 | nDaySpan="${evt.dayspan}" |
689 | dtStart="${str(evt.starts)}" |
690 | |
691 | === modified file 'addons/view_calendar/widgets/templates/month.mako' |
692 | --- addons/view_calendar/widgets/templates/month.mako 2010-10-21 15:25:44 +0000 |
693 | +++ addons/view_calendar/widgets/templates/month.mako 2010-10-27 09:48:00 +0000 |
694 | @@ -51,7 +51,7 @@ |
695 | <div id="calBodySect"> |
696 | % for evt in events: |
697 | % if evt.dayspan > 0: |
698 | - <div class="calEvent" |
699 | + <div class="calEvent ${evt.classes}" |
700 | nRecordID="${evt.record_id}" |
701 | nDaySpan="${evt.dayspan}" |
702 | dtStart="${str(evt.starts)}" |
703 | @@ -64,7 +64,7 @@ |
704 | style="background-color: ${evt.color}">${evt.title}</div> |
705 | % endif |
706 | % if evt.dayspan == 0: |
707 | - <div class="calEvent calEventInfo" |
708 | + <div class="calEvent calEventInfo ${evt.classes}" |
709 | nRecordID="${evt.record_id}" |
710 | nDaySpan="${evt.dayspan}" |
711 | dtStart="${str(evt.starts)}" |
712 | |
713 | === modified file 'addons/view_calendar/widgets/templates/week.mako' |
714 | --- addons/view_calendar/widgets/templates/week.mako 2010-10-21 15:25:44 +0000 |
715 | +++ addons/view_calendar/widgets/templates/week.mako 2010-10-27 09:48:00 +0000 |
716 | @@ -51,33 +51,33 @@ |
717 | <div id="calAllDaySect"> |
718 | % for evt in events: |
719 | % if evt.dayspan > 0: |
720 | - <div nRecordID="${evt.record_id}" |
721 | - nDaySpan="${evt.dayspan}" |
722 | - dtStart="${str(evt.starts)}" |
723 | - dtEnd="${str(evt.ends)}" |
724 | + <div nRecordID="${evt.record_id}" |
725 | + nDaySpan="${evt.dayspan}" |
726 | + dtStart="${str(evt.starts)}" |
727 | + dtEnd="${str(evt.ends)}" |
728 | title="${evt.description}" |
729 | nCreationDate="${evt.create_date}" |
730 | nCreationId="${evt.create_uid}" |
731 | nWriteDate="${evt.write_date}" |
732 | - nWriteId="${evt.write_uid}" |
733 | - style="background-color: ${evt.color};" |
734 | - class="calEvent allDay">${evt.title}</div> |
735 | + nWriteId="${evt.write_uid}" |
736 | + style="background-color: ${evt.color};" |
737 | + class="calEvent allDay ${evt.classes}">${evt.title}</div> |
738 | % endif |
739 | % endfor |
740 | </div> |
741 | <div id="calBodySect"> |
742 | % for evt in events: |
743 | % if evt.dayspan == 0: |
744 | - <div nRecordID="${evt.record_id}" |
745 | - dtStart="${str(evt.starts)}" |
746 | + <div nRecordID="${evt.record_id}" |
747 | + dtStart="${str(evt.starts)}" |
748 | dtEnd="${str(evt.ends)}" |
749 | nCreationDate="${evt.create_date}" |
750 | nCreationId="${evt.create_uid}" |
751 | nWriteDate="${evt.write_date}" |
752 | nWriteId="${evt.write_uid}" |
753 | - style="background-color: ${evt.color};" |
754 | - class="calEvent noAllDay"> |
755 | - <div style="height: 10px;" class="calEventTitle">${evt.starts.strftime('%I:%M %P')} - ${evt.title}</div> |
756 | + style="background-color: ${evt.color};" |
757 | + class="calEvent noAllDay ${evt.classes}"> |
758 | + <div style="height: 10px;" class="calEventTitle">${evt.starts.strftime('%H:%M')} - ${evt.title}</div> |
759 | <div class="calEventDesc">${evt.description}</div> |
760 | <div class="calEventGrip"></div> |
761 | </div> |
762 | |
763 | === modified file 'addons/view_calendar/widgets/widgets.py' |
764 | --- addons/view_calendar/widgets/widgets.py 2010-10-25 12:26:19 +0000 |
765 | +++ addons/view_calendar/widgets/widgets.py 2010-10-27 09:48:00 +0000 |
766 | @@ -142,8 +142,6 @@ |
767 | self.month = Month(y, m) |
768 | self.events = self.get_events(self.month.days) |
769 | |
770 | - |
771 | - |
772 | self.selected_day = _get_selection_day(Day(y, m, 1), self.selected_day, 'month') |
773 | |
774 | minical = MiniCalendar(self.selected_day) |
* New code should avoid using Mochikit functions when possible, and use jQuery instead (hasElementClass, getNodeAttribute) event_droppable could probably go directly into the final TinyEvent call
* The call to self._is_
* In the templates, TinyEvent.droppable is accessed 6 times (I think) and every single time it's in a conditional to decide on the right class to set. Maybe TinyEvent should have an additional droppable_class property which would directly return the right class for the event, no?