Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / examples / calendar / src / EventEditWindow.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  * @class Ext.calendar.EventEditWindow
9  * @extends Ext.Window
10  * <p>A custom window containing a basic edit form used for quick editing of events.</p>
11  * <p>This window also provides custom events specific to the calendar so that other calendar components can be easily
12  * notified when an event has been edited via this component.</p>
13  * @constructor
14  * @param {Object} config The config object
15  */
16 Ext.calendar.EventEditWindow = function(config) {
17     var formPanelCfg = {
18         xtype: 'form',
19         labelWidth: 65,
20         frame: false,
21         bodyStyle: 'background:transparent;padding:5px 10px 10px;',
22         bodyBorder: false,
23         border: false,
24         items: [{
25             id: 'title',
26             name: Ext.calendar.EventMappings.Title.name,
27             fieldLabel: 'Title',
28             xtype: 'textfield',
29             anchor: '100%'
30         },
31         {
32             xtype: 'daterangefield',
33             id: 'date-range',
34             anchor: '100%',
35             fieldLabel: 'When'
36         }]
37     };
38
39     if (config.calendarStore) {
40         this.calendarStore = config.calendarStore;
41         delete config.calendarStore;
42
43         formPanelCfg.items.push({
44             xtype: 'calendarpicker',
45             id: 'calendar',
46             name: 'calendar',
47             anchor: '100%',
48             store: this.calendarStore
49         });
50     }
51
52     Ext.calendar.EventEditWindow.superclass.constructor.call(this, Ext.apply({
53         titleTextAdd: 'Add Event',
54         titleTextEdit: 'Edit Event',
55         width: 600,
56         autocreate: true,
57         border: true,
58         closeAction: 'hide',
59         modal: false,
60         resizable: false,
61         buttonAlign: 'left',
62         savingMessage: 'Saving changes...',
63         deletingMessage: 'Deleting event...',
64
65         fbar: [{
66             xtype: 'tbtext',
67             text: '<a href="#" id="tblink">Edit Details...</a>'
68         },
69         '->', {
70             text: 'Save',
71             disabled: false,
72             handler: this.onSave,
73             scope: this
74         },
75         {
76             id: 'delete-btn',
77             text: 'Delete',
78             disabled: false,
79             handler: this.onDelete,
80             scope: this,
81             hideMode: 'offsets'
82         },
83         {
84             text: 'Cancel',
85             disabled: false,
86             handler: this.onCancel,
87             scope: this
88         }],
89         items: formPanelCfg
90     },
91     config));
92 };
93
94 Ext.extend(Ext.calendar.EventEditWindow, Ext.Window, {
95     // private
96     newId: 10000,
97
98     // private
99     initComponent: function() {
100         Ext.calendar.EventEditWindow.superclass.initComponent.call(this);
101
102         this.formPanel = this.items.items[0];
103
104         this.addEvents({
105             /**
106              * @event eventadd
107              * Fires after a new event is added
108              * @param {Ext.calendar.EventEditWindow} this
109              * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was added
110              */
111             eventadd: true,
112             /**
113              * @event eventupdate
114              * Fires after an existing event is updated
115              * @param {Ext.calendar.EventEditWindow} this
116              * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was updated
117              */
118             eventupdate: true,
119             /**
120              * @event eventdelete
121              * Fires after an event is deleted
122              * @param {Ext.calendar.EventEditWindow} this
123              * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was deleted
124              */
125             eventdelete: true,
126             /**
127              * @event eventcancel
128              * Fires after an event add/edit operation is canceled by the user and no store update took place
129              * @param {Ext.calendar.EventEditWindow} this
130              * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was canceled
131              */
132             eventcancel: true,
133             /**
134              * @event editdetails
135              * Fires when the user selects the option in this window to continue editing in the detailed edit form
136              * (by default, an instance of {@link Ext.calendar.EventEditForm}. Handling code should hide this window
137              * and transfer the current event record to the appropriate instance of the detailed form by showing it
138              * and calling {@link Ext.calendar.EventEditForm#loadRecord loadRecord}.
139              * @param {Ext.calendar.EventEditWindow} this
140              * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} that is currently being edited
141              */
142             editdetails: true
143         });
144     },
145
146     // private
147     afterRender: function() {
148         Ext.calendar.EventEditWindow.superclass.afterRender.call(this);
149
150         this.el.addClass('ext-cal-event-win');
151
152         Ext.get('tblink').on('click',
153         function(e) {
154             e.stopEvent();
155             this.updateRecord();
156             this.fireEvent('editdetails', this, this.activeRecord);
157         },
158         this);
159     },
160
161     /**
162      * Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden.
163          * @param {Ext.data.Record/Object} o Either a {@link Ext.data.Record} if showing the form
164          * for an existing event in edit mode, or a plain object containing a StartDate property (and 
165          * optionally an EndDate property) for showing the form in add mode. 
166      * @param {String/Element} animateTarget (optional) The target element or id from which the window should
167      * animate while opening (defaults to null with no animation)
168      * @return {Ext.Window} this
169      */
170     show: function(o, animateTarget) {
171         // Work around the CSS day cell height hack needed for initial render in IE8/strict:
172         var anim = (Ext.isIE8 && Ext.isStrict) ? null: animateTarget;
173
174         Ext.calendar.EventEditWindow.superclass.show.call(this, anim,
175         function() {
176             Ext.getCmp('title').focus(false, 100);
177         });
178         Ext.getCmp('delete-btn')[o.data && o.data[Ext.calendar.EventMappings.EventId.name] ? 'show': 'hide']();
179
180         var rec,
181         f = this.formPanel.form;
182
183         if (o.data) {
184             rec = o;
185             this.isAdd = !!rec.data[Ext.calendar.EventMappings.IsNew.name];
186             if (this.isAdd) {
187                 // Enable adding the default record that was passed in
188                 // if it's new even if the user makes no changes
189                 rec.markDirty();
190                 this.setTitle(this.titleTextAdd);
191             }
192             else {
193                 this.setTitle(this.titleTextEdit);
194             }
195
196             f.loadRecord(rec);
197         }
198         else {
199             this.isAdd = true;
200             this.setTitle(this.titleTextAdd);
201
202             var M = Ext.calendar.EventMappings,
203             eventId = M.EventId.name,
204             start = o[M.StartDate.name],
205             end = o[M.EndDate.name] || start.add('h', 1);
206
207             rec = new Ext.calendar.EventRecord();
208             rec.data[M.EventId.name] = this.newId++;
209             rec.data[M.StartDate.name] = start;
210             rec.data[M.EndDate.name] = end;
211             rec.data[M.IsAllDay.name] = !!o[M.IsAllDay.name] || start.getDate() != end.clone().add(Date.MILLI, 1).getDate();
212             rec.data[M.IsNew.name] = true;
213
214             f.reset();
215             f.loadRecord(rec);
216         }
217
218         if (this.calendarStore) {
219             Ext.getCmp('calendar').setValue(rec.data[Ext.calendar.EventMappings.CalendarId.name]);
220         }
221         Ext.getCmp('date-range').setValue(rec.data);
222         this.activeRecord = rec;
223
224         return this;
225     },
226
227     // private
228     roundTime: function(dt, incr) {
229         incr = incr || 15;
230         var m = parseInt(dt.getMinutes(), 10);
231         return dt.add('mi', incr - (m % incr));
232     },
233
234     // private
235     onCancel: function() {
236         this.cleanup(true);
237         this.fireEvent('eventcancel', this);
238     },
239
240     // private
241     cleanup: function(hide) {
242         if (this.activeRecord && this.activeRecord.dirty) {
243             this.activeRecord.reject();
244         }
245         delete this.activeRecord;
246
247         if (hide === true) {
248             // Work around the CSS day cell height hack needed for initial render in IE8/strict:
249             //var anim = afterDelete || (Ext.isIE8 && Ext.isStrict) ? null : this.animateTarget;
250             this.hide();
251         }
252     },
253
254     // private
255     updateRecord: function() {
256         var f = this.formPanel.form,
257         dates = Ext.getCmp('date-range').getValue(),
258         M = Ext.calendar.EventMappings;
259
260         f.updateRecord(this.activeRecord);
261         this.activeRecord.set(M.StartDate.name, dates[0]);
262         this.activeRecord.set(M.EndDate.name, dates[1]);
263         this.activeRecord.set(M.IsAllDay.name, dates[2]);
264         this.activeRecord.set(M.CalendarId.name, this.formPanel.form.findField('calendar').getValue());
265     },
266
267     // private
268     onSave: function() {
269         if (!this.formPanel.form.isValid()) {
270             return;
271         }
272         this.updateRecord();
273
274         if (!this.activeRecord.dirty) {
275             this.onCancel();
276             return;
277         }
278
279         this.fireEvent(this.isAdd ? 'eventadd': 'eventupdate', this, this.activeRecord);
280     },
281
282     // private
283     onDelete: function() {
284         this.fireEvent('eventdelete', this, this.activeRecord);
285     }
286 });