/** * @class Ext.ensible.cal.EventEditWindow * @extends Ext.Window *

A custom window containing a basic edit form used for quick editing of events.

*

This window also provides custom events specific to the calendar so that other calendar components can be easily * notified when an event has been edited via this component.

*

The default configs are as follows:


titleTextAdd: 'Add Event',
titleTextEdit: 'Edit Event',
width: 600,
border: true,
closeAction: 'hide',
modal: false,
resizable: false,
buttonAlign: 'left',
labelWidth: 65,
detailsLinkText: 'Edit Details...',
savingMessage: 'Saving changes...',
deletingMessage: 'Deleting event...',
saveButtonText: 'Save',
deleteButtonText: 'Delete',
cancelButtonText: 'Cancel',
titleLabelText: 'Title',
datesLabelText: 'When',
calendarLabelText: 'Calendar',
editDetailsLinkClass: 'edit-dtl-link',
bodyStyle: 'padding:5px 10px;',
enableEditDetails: true
* @constructor * @param {Object} config The config object */ Ext.ensible.cal.EventEditWindow = Ext.extend(Ext.Window, { titleTextAdd: 'Add Event', titleTextEdit: 'Edit Event', width: 600, border: true, closeAction: 'hide', modal: false, resizable: false, buttonAlign: 'left', labelWidth: 65, detailsLinkText: 'Edit Details...', savingMessage: 'Saving changes...', deletingMessage: 'Deleting event...', saveButtonText: 'Save', deleteButtonText: 'Delete', cancelButtonText: 'Cancel', titleLabelText: 'Title', datesLabelText: 'When', calendarLabelText: 'Calendar', editDetailsLinkClass: 'edit-dtl-link', bodyStyle: 'padding:5px 10px;', enableEditDetails: true, // private initComponent: function(){ this.addEvents({
/** * @event eventadd * Fires after a new event is added * @param {Ext.ensible.cal.EventEditWindow} this * @param {Ext.ensible.cal.EventRecord} rec The new {@link Ext.ensible.cal.EventRecord record} that was added * @param {Ext.Element} el The target element */ eventadd: true,
/** * @event eventupdate * Fires after an existing event is updated * @param {Ext.ensible.cal.EventEditWindow} this * @param {Ext.ensible.cal.EventRecord} rec The new {@link Ext.ensible.cal.EventRecord record} that was updated * @param {Ext.Element} el The target element */ eventupdate: true,
/** * @event eventdelete * Fires after an event is deleted * @param {Ext.ensible.cal.EventEditWindow} this * @param {Ext.ensible.cal.EventRecord} rec The new {@link Ext.ensible.cal.EventRecord record} that was deleted * @param {Ext.Element} el The target element */ eventdelete: true,
/** * @event eventcancel * Fires after an event add/edit operation is canceled by the user and no store update took place * @param {Ext.ensible.cal.EventEditWindow} this * @param {Ext.ensible.cal.EventRecord} rec The new {@link Ext.ensible.cal.EventRecord record} that was canceled * @param {Ext.Element} el The target element */ eventcancel: true,
/** * @event editdetails * Fires when the user selects the option in this window to continue editing in the detailed edit form * (by default, an instance of {@link Ext.ensible.cal.EventEditForm}. Handling code should hide this window * and transfer the current event record to the appropriate instance of the detailed form by showing it * and calling {@link Ext.ensible.cal.EventEditForm#loadRecord loadRecord}. * @param {Ext.ensible.cal.EventEditWindow} this * @param {Ext.ensible.cal.EventRecord} rec The {@link Ext.ensible.cal.EventRecord record} that is currently being edited * @param {Ext.Element} el The target element */ editdetails: true }); this.fbar = ['->',{ text:this.saveButtonText, disabled:false, handler:this.onSave, scope:this },{ id:this.id+'-delete-btn', text:this.deleteButtonText, disabled:false, handler:this.onDelete, scope:this, hideMode:'offsets' },{ text:this.cancelButtonText, disabled:false, handler:this.onCancel, scope:this }]; if(this.enableEditDetails !== false){ this.fbar.unshift({ xtype: 'tbtext', text: ''+this.detailsLinkText+'' }); } Ext.ensible.cal.EventEditWindow.superclass.initComponent.call(this); }, // private onRender : function(ct, position){ this.deleteBtn = Ext.getCmp(this.id+'-delete-btn'); this.titleField = new Ext.form.TextField({ name: Ext.ensible.cal.EventMappings.Title.name, fieldLabel: this.titleLabelText, anchor: '100%' }); this.dateRangeField = new Ext.ensible.cal.DateRangeField({ anchor: '95%', fieldLabel: this.datesLabelText }); var items = [this.titleField, this.dateRangeField]; if(this.calendarStore){ this.calendarField = new Ext.ensible.cal.CalendarCombo({ name: Ext.ensible.cal.EventMappings.CalendarId.name, anchor: '100%', fieldLabel: this.calendarLabelText, store: this.calendarStore }); items.push(this.calendarField); } this.formPanel = new Ext.FormPanel({ labelWidth: this.labelWidth, frame: false, bodyBorder: false, border: false, items: items }); this.add(this.formPanel); Ext.ensible.cal.EventEditWindow.superclass.onRender.call(this, ct, position); }, // private afterRender: function(){ Ext.ensible.cal.EventEditWindow.superclass.afterRender.call(this); this.el.addClass('ext-cal-event-win'); this.el.select('.'+this.editDetailsLinkClass).on('click', this.onEditDetailsClick, this); }, // private onEditDetailsClick: function(e){ e.stopEvent(); this.updateRecord(true); this.fireEvent('editdetails', this, this.activeRecord, this.animateTarget); },
/** * Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden. * @param {Ext.data.Record/Object} o Either a {@link Ext.data.Record} if showing the form * for an existing event in edit mode, or a plain object containing a StartDate property (and * optionally an EndDate property) for showing the form in add mode. * @param {String/Element} animateTarget (optional) The target element or id from which the window should * animate while opening (defaults to null with no animation) * @return {Ext.Window} this */ show: function(o, animateTarget){ // Work around the CSS day cell height hack needed for initial render in IE8/strict: var anim = (Ext.isIE8 && Ext.isStrict) ? null : animateTarget, M = Ext.ensible.cal.EventMappings; Ext.ensible.cal.EventEditWindow.superclass.show.call(this, anim, function(){ this.titleField.focus(false, 100); }); this.deleteBtn[o.data && o.data[M.EventId.name] ? 'show' : 'hide'](); var rec, f = this.formPanel.form; if(o.data){ rec = o; //this.isAdd = !!rec.data[Ext.ensible.cal.EventMappings.IsNew.name]; if(rec.phantom){ // Enable adding the default record that was passed in // if it's new even if the user makes no changes //rec.markDirty(); this.setTitle(this.titleTextAdd); } else{ this.setTitle(this.titleTextEdit); } f.loadRecord(rec); } else{ //this.isAdd = true; this.setTitle(this.titleTextAdd); var start = o[M.StartDate.name], end = o[M.EndDate.name] || start.add('h', 1); rec = new Ext.ensible.cal.EventRecord(); //rec.data[M.EventId.name] = this.newId++; rec.data[M.StartDate.name] = start; rec.data[M.EndDate.name] = end; rec.data[M.IsAllDay.name] = !!o[M.IsAllDay.name] || start.getDate() != end.clone().add(Date.MILLI, 1).getDate(); f.reset(); f.loadRecord(rec); } if(this.calendarStore){ this.calendarField.setValue(rec.data[M.CalendarId.name]); } this.dateRangeField.setValue(rec.data); this.activeRecord = rec; this.el.setStyle('z-index', 12000); return this; }, // private roundTime: function(dt, incr){ incr = incr || 15; var m = parseInt(dt.getMinutes()); return dt.add('mi', incr - (m % incr)); }, // private onCancel: function(){ this.cleanup(true); this.fireEvent('eventcancel', this, this.animateTarget); }, // private cleanup: function(hide){ if(this.activeRecord){ this.activeRecord.reject(); } delete this.activeRecord; if(hide===true){ // Work around the CSS day cell height hack needed for initial render in IE8/strict: //var anim = afterDelete || (Ext.isIE8 && Ext.isStrict) ? null : this.animateTarget; this.hide(); } }, // private updateRecord: function(keepEditing){ var dates = this.dateRangeField.getValue(), M = Ext.ensible.cal.EventMappings, rec = this.activeRecord, form = this.formPanel.form, fs = rec.fields, dirty = false; rec.beginEdit(); //TODO: This block is copied directly from BasicForm.updateRecord. // Unfortunately since that method internally calls begin/endEdit all // updates happen and the record dirty status is reset internally to // that call. We need the dirty status, plus currently the DateRangeField // does not map directly to the record values, so for now we'll duplicate // the setter logic here (we need to be able to pick up any custom-added // fields generically). Need to revisit this later and come up with a better solution. fs.each(function(f){ var field = form.findField(f.name); if(field){ var value = field.getValue(); if (value.getGroupValue) { value = value.getGroupValue(); } else if (field.eachItem) { value = []; field.eachItem(function(item){ value.push(item.getValue()); }); } rec.set(f.name, value); } }, this); rec.set(M.StartDate.name, dates[0]); rec.set(M.EndDate.name, dates[1]); rec.set(M.IsAllDay.name, dates[2]); dirty = rec.dirty; if(!keepEditing){ rec.endEdit(); } return dirty; }, // private onSave: function(){ if(!this.formPanel.form.isValid()){ return; } if(!this.updateRecord()){ this.onCancel(); return; } this.fireEvent(this.activeRecord.phantom ? 'eventadd' : 'eventupdate', this, this.activeRecord, this.animateTarget); }, // private onDelete: function(){ this.fireEvent('eventdelete', this, this.activeRecord, this.animateTarget); } }); Ext.reg('extensible.eventeditwindow', Ext.ensible.cal.EventEditWindow);