Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / examples / calendar / src / dd / CalendarDD.js
1 /*!
2  * Ext JS Library 3.3.1
3  * Copyright(c) 2006-2010 Sencha Inc.
4  * licensing@sencha.com
5  * http://www.sencha.com/license
6  */
7 /*
8  * Internal drag zone implementation for the calendar components. This provides base functionality
9  * and is primarily for the month view -- DayViewDD adds day/week view-specific functionality.
10  */
11 Ext.calendar.DragZone = Ext.extend(Ext.dd.DragZone, {
12     ddGroup: 'CalendarDD',
13     eventSelector: '.ext-cal-evt',
14
15     constructor: function(el, config) {
16         if (!Ext.calendar._statusProxyInstance) {
17             Ext.calendar._statusProxyInstance = new Ext.calendar.StatusProxy();
18         }
19         this.proxy = Ext.calendar._statusProxyInstance;
20         Ext.calendar.DragZone.superclass.constructor.call(this, el, config);
21     },
22
23     getDragData: function(e) {
24         // Check whether we are dragging on an event first
25         var t = e.getTarget(this.eventSelector, 3);
26         if (t) {
27             var rec = this.view.getEventRecordFromEl(t);
28             return {
29                 type: 'eventdrag',
30                 ddel: t,
31                 eventStart: rec.data[Ext.calendar.EventMappings.StartDate.name],
32                 eventEnd: rec.data[Ext.calendar.EventMappings.EndDate.name],
33                 proxy: this.proxy
34             };
35         }
36
37         // If not dragging an event then we are dragging on
38         // the calendar to add a new event
39         t = this.view.getDayAt(e.getPageX(), e.getPageY());
40         if (t.el) {
41             return {
42                 type: 'caldrag',
43                 start: t.date,
44                 proxy: this.proxy
45             };
46         }
47         return null;
48     },
49
50     onInitDrag: function(x, y) {
51         if (this.dragData.ddel) {
52             var ghost = this.dragData.ddel.cloneNode(true),
53             child = Ext.fly(ghost).child('dl');
54
55             Ext.fly(ghost).setWidth('auto');
56
57             if (child) {
58                 // for IE/Opera
59                 child.setHeight('auto');
60             }
61             this.proxy.update(ghost);
62             this.onStartDrag(x, y);
63         }
64         else if (this.dragData.start) {
65             this.onStartDrag(x, y);
66         }
67         this.view.onInitDrag();
68         return true;
69     },
70
71     afterRepair: function() {
72         if (Ext.enableFx && this.dragData.ddel) {
73             Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || 'c3daf9');
74         }
75         this.dragging = false;
76     },
77
78     getRepairXY: function(e) {
79         if (this.dragData.ddel) {
80             return Ext.Element.fly(this.dragData.ddel).getXY();
81         }
82     },
83
84     afterInvalidDrop: function(e, id) {
85         Ext.select('.ext-dd-shim').hide();
86     }
87 });
88
89 /*
90  * Internal drop zone implementation for the calendar components. This provides base functionality
91  * and is primarily for the month view -- DayViewDD adds day/week view-specific functionality.
92  */
93 Ext.calendar.DropZone = Ext.extend(Ext.dd.DropZone, {
94     ddGroup: 'CalendarDD',
95     eventSelector: '.ext-cal-evt',
96
97     // private
98     shims: [],
99
100     getTargetFromEvent: function(e) {
101         var dragOffset = this.dragOffset || 0,
102         y = e.getPageY() - dragOffset,
103         d = this.view.getDayAt(e.getPageX(), y);
104
105         return d.el ? d: null;
106     },
107
108     onNodeOver: function(n, dd, e, data) {
109         var D = Ext.calendar.Date,
110         start = data.type == 'eventdrag' ? n.date: D.min(data.start, n.date),
111         end = data.type == 'eventdrag' ? n.date.add(Date.DAY, D.diffDays(data.eventStart, data.eventEnd)) :
112         D.max(data.start, n.date);
113
114         if (!this.dragStartDate || !this.dragEndDate || (D.diffDays(start, this.dragStartDate) != 0) || (D.diffDays(end, this.dragEndDate) != 0)) {
115             this.dragStartDate = start;
116             this.dragEndDate = end.clearTime().add(Date.DAY, 1).add(Date.MILLI, -1);
117             this.shim(start, end);
118
119             var range = start.format('n/j');
120             if (D.diffDays(start, end) > 0) {
121                 range += '-' + end.format('n/j');
122             }
123             var msg = String.format(data.type == 'eventdrag' ? this.moveText: this.createText, range);
124             data.proxy.updateMsg(msg);
125         }
126         return this.dropAllowed;
127     },
128
129     shim: function(start, end) {
130         this.currWeek = -1;
131         var dt = start.clone(),
132             i = 0,
133             shim,
134             box,
135             cnt = Ext.calendar.Date.diffDays(dt, end) + 1;
136
137         Ext.each(this.shims,
138             function(shim) {
139                 if (shim) {
140                     shim.isActive = false;
141                 }
142             }
143         );
144
145         while (i++<cnt) {
146             var dayEl = this.view.getDayEl(dt);
147
148             // if the date is not in the current view ignore it (this
149             // can happen when an event is dragged to the end of the
150             // month so that it ends outside the view)
151             if (dayEl) {
152                 var wk = this.view.getWeekIndex(dt);
153                 shim = this.shims[wk];
154
155                 if (!shim) {
156                     shim = this.createShim();
157                     this.shims[wk] = shim;
158                 }
159                 if (wk != this.currWeek) {
160                     shim.boxInfo = dayEl.getBox();
161                     this.currWeek = wk;
162                 }
163                 else {
164                     box = dayEl.getBox();
165                     shim.boxInfo.right = box.right;
166                     shim.boxInfo.width = box.right - shim.boxInfo.x;
167                 }
168                 shim.isActive = true;
169             }
170             dt = dt.add(Date.DAY, 1);
171         }
172
173         Ext.each(this.shims,
174         function(shim) {
175             if (shim) {
176                 if (shim.isActive) {
177                     shim.show();
178                     shim.setBox(shim.boxInfo);
179                 }
180                 else if (shim.isVisible()) {
181                     shim.hide();
182                 }
183             }
184         });
185     },
186
187     createShim: function() {
188         if (!this.shimCt) {
189             this.shimCt = Ext.get('ext-dd-shim-ct');
190             if (!this.shimCt) {
191                 this.shimCt = document.createElement('div');
192                 this.shimCt.id = 'ext-dd-shim-ct';
193                 Ext.getBody().appendChild(this.shimCt);
194             }
195         }
196         var el = document.createElement('div');
197         el.className = 'ext-dd-shim';
198         this.shimCt.appendChild(el);
199
200         return new Ext.Layer({
201             shadow: false,
202             useDisplay: true,
203             constrain: false
204         },
205         el);
206     },
207
208     clearShims: function() {
209         Ext.each(this.shims,
210         function(shim) {
211             if (shim) {
212                 shim.hide();
213             }
214         });
215     },
216
217     onContainerOver: function(dd, e, data) {
218         return this.dropAllowed;
219     },
220
221     onCalendarDragComplete: function() {
222         delete this.dragStartDate;
223         delete this.dragEndDate;
224         this.clearShims();
225     },
226
227     onNodeDrop: function(n, dd, e, data) {
228         if (n && data) {
229             if (data.type == 'eventdrag') {
230                 var rec = this.view.getEventRecordFromEl(data.ddel),
231                 dt = Ext.calendar.Date.copyTime(rec.data[Ext.calendar.EventMappings.StartDate.name], n.date);
232
233                 this.view.onEventDrop(rec, dt);
234                 this.onCalendarDragComplete();
235                 return true;
236             }
237             if (data.type == 'caldrag') {
238                 this.view.onCalendarEndDrag(this.dragStartDate, this.dragEndDate,
239                 this.onCalendarDragComplete.createDelegate(this));
240                 //shims are NOT cleared here -- they stay visible until the handling
241                 //code calls the onCalendarDragComplete callback which hides them.
242                 return true;
243             }
244         }
245         this.onCalendarDragComplete();
246         return false;
247     },
248
249     onContainerDrop: function(dd, e, data) {
250         this.onCalendarDragComplete();
251         return false;
252     },
253
254     destroy: function() {
255         Ext.calendar.DropZone.superclass.destroy.call(this);
256         Ext.destroy(this.shimCt);
257     }
258 });
259