From bb2b02c3f2e9782f8ee0b437ed63b6231475f167 Mon Sep 17 00:00:00 2001 From: Brian Moeskau Date: Sun, 27 Mar 2016 12:20:25 -0500 Subject: [PATCH 1/5] Initial rendering, still work in progress --- Extensible-config.js | 86 ++-- src/calendar/CalendarPanel.js | 574 ++++++++++++----------- src/calendar/data/EventStore.js | 20 +- src/calendar/data/MemoryCalendarStore.js | 16 +- src/calendar/data/MemoryEventStore.js | 8 +- src/calendar/dd/DayDragZone.js | 20 +- src/calendar/dd/DropZone.js | 13 +- src/calendar/dd/StatusProxy.js | 36 +- src/calendar/form/EventDetails.js | 84 ++-- src/calendar/form/EventWindow.js | 130 +++-- src/calendar/form/field/CalendarCombo.js | 48 +- src/calendar/view/AbstractCalendar.js | 437 +++++++++-------- src/calendar/view/DayBody.js | 79 ++-- src/calendar/view/Month.js | 64 +-- src/calendar/view/MonthDayDetail.js | 48 +- src/data/Model.js | 43 +- src/form/field/DateRange.js | 16 +- 17 files changed, 879 insertions(+), 843 deletions(-) diff --git a/Extensible-config.js b/Extensible-config.js index 478793d1..2b7853ef 100644 --- a/Extensible-config.js +++ b/Extensible-config.js @@ -1,5 +1,5 @@ Extensible = { - version: '1.6.0' + version: '1.7.0' }; /** * ================================================================================================= @@ -61,7 +61,7 @@ Extensible.Config = { * * @config {String} extJsRoot */ - extJsRoot: 'http://cdn.sencha.com/ext/gpl/4.2.0/', + extJsRoot: 'http://cdn.sencha.com/ext/gpl/5.1.0/', /** * The root path to the Extensible framework (defaults to the current url of this script file, @@ -119,7 +119,12 @@ Extensible.Config = { * work consistently with all Ext 4.x versions (just uses the Ext default English strings). As long * as you are using 4.1+ feel free to enable this by setting the value to any supported locale code. */ - language: null + language: null, + + /** + * Name of theme used. Supported values are: 'neptune', nepture-touch', 'crisp', 'crisp-touch'. + */ + theme: 'neptune' }, /** @@ -136,6 +141,7 @@ Extensible.Config = { me.extensibleRoot = config.extensibleRoot || me.defaults.extensibleRoot || me.getSdkPath(); me.cacheExtensible = config.cacheExtensible || me.defaults.cacheExtensible; me.language = config.language || me.defaults.language; + me.theme = config.theme || me.defaults.theme; me.adjustPaths(); me.writeIncludes(); @@ -169,44 +175,46 @@ Extensible.Config = { // private -- write out the CSS and script includes to the document writeIncludes: function() { var me = this, - cacheBuster = '?_dc=' + (me.cacheExtensible ? Extensible.version : (+new Date)), - suffixExt = '', - suffixExtensible = ''; - - switch (me.mode) { - case 'debug': - suffixExt = '-all-debug'; - suffixExtensible = '-all-debug'; - break; - - case 'release': - suffixExt = '-all'; - suffixExtensible = '-all' - // For release we want to refresh the cache on first load, but allow caching - // after that, so use the version number instead of a unique string - cacheBuster = '?_dc=' + Extensible.version; - break; - - default: - // IE does not work in dynamic mode for the Extensible examples currently - // based on how it (mis)handles loading of scripts when mixing includes - // and in-page scripts. Make sure IE always uses the regular debug versions. - if (me.isIE) { - suffixExt = '-all-debug'; - suffixExtensible = '-all-debug'; - } - else { - suffixExt = '-debug'; - suffixExtensible = '-bootstrap'; - } - } + cacheBuster = '?_dc=' + (me.cacheExtensible ? Extensible.version : (+new Date)); - me.includeStylesheet(me.extJsRoot + 'resources/css/ext-all.css'); - me.includeStylesheet(me.extensibleRoot + 'resources/css/extensible-all.css' + cacheBuster); - me.includeStylesheet(me.extensibleRoot + 'examples/examples.css?_dc=' + Extensible.version); + // Include style sheets + me.includeStylesheet(me.extJsRoot + '/build/packages/ext-theme-' + me.theme + + '/build/resources/ext-theme-' + me.theme + '-all.css'); - me.includeScript(me.extJsRoot + 'ext' + suffixExt + '.js'); - me.includeScript(me.extensibleRoot + 'lib/extensible' + suffixExtensible + '.js' + cacheBuster); + if (me.mode === 'release') { + me.includeStylesheet(me.extensibleRoot + 'resources/css/extensible-all.css' + cacheBuster); + } + else { + me.includeStylesheet(me.extensibleRoot + 'resources/css/calendar.css' + cacheBuster); + me.includeStylesheet(me.extensibleRoot + 'resources/css/calendar-colors.css' + cacheBuster); + me.includeStylesheet(me.extensibleRoot + 'resources/css/recurrence.css' + cacheBuster); + } + me.includeStylesheet(me.extensibleRoot + 'examples/examples.css' + cacheBuster); + + // Include JS files + if (me.mode === 'debug' || me.isIE) { + // IE does not work in dynamic mode for the Extensible examples currently + // based on how it (mis)handles loading of scripts when mixing includes + // and in-page scripts. Make sure IE always uses the regular debug versions. + me.includeScript(me.extJsRoot + 'build/ext-all-debug.js'); + me.includeScript(me.extensibleRoot + 'lib/extensible-all-debug.js' + cacheBuster); + } + else if (me.mode === 'release') { + // For release we want to refresh the cache on first load, but allow caching + // after that, so use the version number instead of a unique string + cacheBuster = '?_dc=' + Extensible.version; + me.includeScript(me.extJsRoot + 'build/ext-all.js'); + me.includeScript(me.extensibleRoot + 'lib/extensible-all.js' + cacheBuster); + } + else { + if (me.mode === 'dynamic-extensible') { + me.includeScript(me.extJsRoot + 'build/ext-all-debug.js'); + } + else { + me.includeScript(me.extJsRoot + 'build/ext-debug.js'); + } + me.includeScript(me.extensibleRoot + 'lib/extensible-bootstrap.js' + cacheBuster); + } me.includeScript(me.extensibleRoot + 'examples/examples.js?_dc=' + Extensible.version); if (me.language) { diff --git a/src/calendar/CalendarPanel.js b/src/calendar/CalendarPanel.js index 002b6130..71dfbda0 100644 --- a/src/calendar/CalendarPanel.js +++ b/src/calendar/CalendarPanel.js @@ -7,7 +7,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { extend: 'Ext.panel.Panel', alias: 'widget.extensible.calendarpanel', - + requires: [ 'Ext.layout.container.Card', 'Extensible.calendar.view.Day', @@ -16,7 +16,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { 'Extensible.calendar.view.MultiDay', 'Extensible.calendar.view.MultiWeek' ], - + /** * @cfg {Number} activeItem * The 0-based index within the available views to set as the default active view (defaults to undefined). @@ -124,7 +124,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { /** * @cfg {String} multiDayText * **Deprecated.** Please override {@link #getMultiDayText} instead. - * + * * Text to use for the 'X Days' nav bar button (defaults to "{0} Days" where {0} is automatically * replaced by the value of the {@link #multDayViewCfg}'s dayCount value if available, otherwise it * uses the view default of 3). @@ -139,7 +139,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { /** * @cfg {String} multiWeekText * **Deprecated.** Please override {@link #getMultiWeekText} instead. - * + * * Text to use for the 'X Weeks' nav bar button (defaults to "{0} Weeks" where {0} is automatically * replaced by the value of the {@link #multiWeekViewCfg}'s weekCount value if available, otherwise it * uses the view default of 2). @@ -220,34 +220,275 @@ Ext.define('Extensible.calendar.CalendarPanel', { * A config object that will be applied only to the {@link Extensible.calendar.form.EventDetails * EventEditForm} managed by this CalendarPanel. */ - + /** * A reference to the {@link Extensible.calendar.view.AbstractCalendar view} that is currently active. * @type {Extensible.calendar.view.AbstractCalendar} * @property activeView */ - layout: { - type: 'card', - deferredRender: true - }, - + // private + layout: 'card', + // private property startDate: new Date(), + /** + * @event eventadd + * Fires after a new event is added to the underlying store + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The new + * {@link Extensible.calendar.data.EventModel record} that was added + */ + + /** + * @event eventupdate + * Fires after an existing event is updated + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The new + * {@link Extensible.calendar.data.EventModel record} that was updated + */ + + /** + * @event beforeeventdelete + * Fires before an event is deleted by the user. This is a cancelable event, so returning + * false from a handler will cancel the delete operation. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} + * for the event that was deleted + * @param {Ext.Element} el The target element + */ + + /** + * @event eventdelete + * Fires after an event is deleted by the user. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that was deleted + * @param {Ext.Element} el The target element + */ + + /** + * @event eventcancel + * Fires after an event add/edit operation is canceled by the user and no store update took place + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The new + * {@link Extensible.calendar.data.EventModel record} that was canceled + */ + + /** + * @event viewchange + * Fires after a different calendar view is activated (but not when the event edit form is activated) + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.CalendarView} view The view being activated (any valid + * {@link Extensible.calendar.view.AbstractCalendar CalendarView} subclass) + * @param {Object} info Extra information about the newly activated view. This is a plain object + * with following properties: + * + * * **activeDate** + * * The currently selected date + * * **viewStart** + * * The first date in the new view range + * * **viewEnd** + * * The last date in the new view range + */ + + /** + * @event editdetails + * Fires when the user selects the option to edit the selected event in the detailed edit form + * (by default, an instance of {@link Extensible.calendar.form.EventDetails}). Handling code + * should hide the active event editor and transfer the current event record to the appropriate + * instance of the detailed form by showing it and calling + * {@link Extensible.calendar.form.EventDetails#loadRecord loadRecord}. + * @param {Extensible.calendar.CalendarPanel} this The CalendarPanel + * @param {Extensible.calendar.view.AbstractCalendar} view The currently active + * {@link Extensible.calendar.view.AbstractCalendar CalendarView} subclass + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} that is currently being edited + * @param {Ext.Element} el The target element + */ + + // + // NOTE: CalendarPanel also relays the following events from contained views as if + // they originated from this: + // + + /** + * @event eventsrendered + * Fires after events are finished rendering in the view + * @param {Extensible.calendar.CalendarPanel} this + */ + + /** + * @event eventclick + * Fires after the user clicks on an event element. + * + * **NOTE:** This version of eventclick differs from the same + * event fired directly by {@link Extensible.calendar.view.AbstractCalendar CalendarView} + * subclasses in that it provides a default implementation (showing the default edit window) + * and is also cancelable (if a handler returns false the edit window will not be + * shown). This event when fired from a view class is simply a notification that an event was + * clicked and has no default behavior. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that was clicked on + * @param {HTMLNode} el The DOM node that was clicked on + */ + + /** + * @event rangeselect + * Fires after the user drags on the calendar to select a range of dates/times in which to + * create an event + * @param {Extensible.calendar.CalendarPanel} this + * @param {Object} dates An object containing the start (StartDate property) and end (EndDate + * property) dates selected + * @param {Function} callback A callback function that MUST be called after the event handling + * is complete so that the view is properly cleaned up (shim elements are persisted in + * the view while the user is prompted to handle the range selection). The callback is + * already created in the proper scope, so it simply needs to be executed as a standard + * function call (e.g., callback()). + */ + + /** + * @event eventover + * Fires anytime the mouse is over an event element + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that the cursor is over + * @param {HTMLNode} el The DOM node that is being moused over + */ + + /** + * @event eventout + * Fires anytime the mouse exits an event element + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that the cursor exited + * @param {HTMLNode} el The DOM node that was exited + */ + + /** + * @event beforedatechange + * Fires before the start date of the view changes, giving you an opportunity to save state or + * anything else you may need to do prior to the UI view changing. This is a cancelable event, so + * returning false from a handler will cancel both the view change and the setting of the start date. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Date} startDate The current start date of the view (as explained in {@link #getStartDate} + * @param {Date} newStartDate The new start date that will be set when the view changes + * @param {Date} viewStart The first displayed date in the current view + * @param {Date} viewEnd The last displayed date in the current view + */ + + /** + * @event dayclick + * Fires after the user clicks within a day/week view container and not on an event element + * @param {Extensible.calendar.CalendarPanel} this + * @param {Date} dt The date/time that was clicked on + * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. + * @param {Ext.Element} el The Element that was clicked on + */ + + /** + * @event datechange + * Fires after the start date of the view changes + * @param {Extensible.calendar.CalendarPanel} this + * @param {Date} startDate The start date of the view (as explained in {@link #getStartDate} + * @param {Date} viewStart The first displayed date in the view + * @param {Date} viewEnd The last displayed date in the view + */ + + /** + * @event beforeeventmove + * Fires before an event element is dragged by the user and dropped in a new position. This is + * a cancelable event, so returning false from a handler will cancel the move operation. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that will be moved + */ + + /** + * @event eventmove + * Fires after an event element is dragged by the user and dropped in a new position + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that was moved with + * updated start and end dates + */ + + /** + * @event initdrag + * Fires when a drag operation is initiated in the view + * @param {Extensible.calendar.CalendarPanel} this + */ + + /** + * @event dayover + * Fires while the mouse is over a day element + * @param {Extensible.calendar.CalendarPanel} this + * @param {Date} dt The date that is being moused over + * @param {Ext.Element} el The day Element that is being moused over + */ + + /** + * @event dayout + * Fires when the mouse exits a day element + * @param {Extensible.calendar.CalendarPanel} this + * @param {Date} dt The date that is exited + * @param {Ext.Element} el The day Element that is exited + */ + + /** + * @event beforeeventresize + * Fires after the user drags the resize handle of an event to resize it, but before the + * resize operation is carried out. This is a cancelable event, so returning false from a + * handler will cancel the resize operation. **NOTE:** This event is only fired + * from views that support event resizing. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that was resized + * containing the updated start and end dates + */ + + /** + * @event eventresize + * Fires after the user drags the resize handle of an event and the resize operation is + * complete. **NOTE:** This event is only fired from views that support event resizing. + * @param {Extensible.calendar.CalendarPanel} this + * @param {Extensible.calendar.data.EventModel} rec The + * {@link Extensible.calendar.data.EventModel record} for the event that was resized + * containing the updated start and end dates + */ + + /** + * @event eventexception + * Fires after an event has been processed via an Ext proxy and returned with an exception. This + * could be because of a server error, or because the data returned success: false. + * + * The view provides default handling via the overrideable + * {@link Extensible.calendar.view.AbstractCalendar#notifyOnException notifyOnException} method. If + * any function handling this event returns false, the notifyOnException method will not be called. + * + * Note that only Server proxy and subclasses (including Ajax proxy) will raise this event. + * + * @param {Extensible.calendar.CalendarPanel} this + * @param {Object} response The raw response object returned from the server + * @param {Ext.data.Operation} operation The operation that was processed + * @since 1.6.0 + */ + initComponent: function() { this.tbar = { cls: 'ext-cal-toolbar', border: true, items: [] }; - + this.viewCount = 0; - + var text, multiDayViewCount = (this.multiDayViewCfg && this.multiDayViewCfg.dayCount) || 3, multiWeekViewCount = (this.multiWeekViewCfg && this.multiWeekViewCfg.weekCount) || 2; - + // // TODO: Pull the configs for the toolbar/buttons out to the prototype for overrideability // @@ -265,9 +506,9 @@ Ext.define('Extensible.calendar.CalendarPanel', { this.tbar.items.push({id: this.id+'-tb-jump-dt', xtype: 'datefield', width: 120, showToday: false, startDay: this.startDay}); this.tbar.items.push({id: this.id+'-tb-jump', text: this.goText, handler: this.onJumpClick, scope: this}); } - + this.tbar.items.push('->'); - + if(this.showDayView) { this.tbar.items.push({ id: this.id+'-tb-day', text: this.dayText, handler: this.onDayNavClick, scope: this, toggleGroup: this.id+'-tb-views' @@ -301,257 +542,25 @@ Ext.define('Extensible.calendar.CalendarPanel', { this.viewCount++; this.showMonthView = true; } - + var idx = this.viewCount-1; this.activeItem = (this.activeItem === undefined ? idx : (this.activeItem > idx ? idx : this.activeItem)); - + if(this.showNavBar === false) { delete this.tbar; this.addCls('x-calendar-nonav'); } - + this.callParent(arguments); - - this.addEvents({ - /** - * @event eventadd - * Fires after a new event is added to the underlying store - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The new - * {@link Extensible.calendar.data.EventModel record} that was added - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event is updated - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The new - * {@link Extensible.calendar.data.EventModel record} that was updated - */ - eventupdate: true, - /** - * @event beforeeventdelete - * Fires before an event is deleted by the user. This is a cancelable event, so returning - * false from a handler will cancel the delete operation. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} - * for the event that was deleted - * @param {Ext.Element} el The target element - */ - beforeeventdelete: true, - /** - * @event eventdelete - * Fires after an event is deleted by the user. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event 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 {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The new - * {@link Extensible.calendar.data.EventModel record} that was canceled - */ - eventcancel: true, - /** - * @event viewchange - * Fires after a different calendar view is activated (but not when the event edit form is activated) - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.CalendarView} view The view being activated (any valid - * {@link Extensible.calendar.view.AbstractCalendar CalendarView} subclass) - * @param {Object} info Extra information about the newly activated view. This is a plain object - * with following properties: - * - * * **activeDate** - * * The currently selected date - * * **viewStart** - * * The first date in the new view range - * * **viewEnd** - * * The last date in the new view range - */ - viewchange: true, - /** - * @event editdetails - * Fires when the user selects the option to edit the selected event in the detailed edit form - * (by default, an instance of {@link Extensible.calendar.form.EventDetails}). Handling code - * should hide the active event editor and transfer the current event record to the appropriate - * instance of the detailed form by showing it and calling - * {@link Extensible.calendar.form.EventDetails#loadRecord loadRecord}. - * @param {Extensible.calendar.CalendarPanel} this The CalendarPanel - * @param {Extensible.calendar.view.AbstractCalendar} view The currently active - * {@link Extensible.calendar.view.AbstractCalendar CalendarView} subclass - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} that is currently being edited - * @param {Ext.Element} el The target element - */ - editdetails: true - - - // - // NOTE: CalendarPanel also relays the following events from contained views as if - // they originated from this: - // - - /** - * @event eventsrendered - * Fires after events are finished rendering in the view - * @param {Extensible.calendar.CalendarPanel} this - */ - /** - * @event eventclick - * Fires after the user clicks on an event element. - * - * **NOTE:** This version of eventclick differs from the same - * event fired directly by {@link Extensible.calendar.view.AbstractCalendar CalendarView} - * subclasses in that it provides a default implementation (showing the default edit window) - * and is also cancelable (if a handler returns false the edit window will not be - * shown). This event when fired from a view class is simply a notification that an event was - * clicked and has no default behavior. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that was clicked on - * @param {HTMLNode} el The DOM node that was clicked on - */ - /** - * @event rangeselect - * Fires after the user drags on the calendar to select a range of dates/times in which to - * create an event - * @param {Extensible.calendar.CalendarPanel} this - * @param {Object} dates An object containing the start (StartDate property) and end (EndDate - * property) dates selected - * @param {Function} callback A callback function that MUST be called after the event handling - * is complete so that the view is properly cleaned up (shim elements are persisted in - * the view while the user is prompted to handle the range selection). The callback is - * already created in the proper scope, so it simply needs to be executed as a standard - * function call (e.g., callback()). - */ - /** - * @event eventover - * Fires anytime the mouse is over an event element - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that the cursor is over - * @param {HTMLNode} el The DOM node that is being moused over - */ - /** - * @event eventout - * Fires anytime the mouse exits an event element - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that the cursor exited - * @param {HTMLNode} el The DOM node that was exited - */ - /** - * @event beforedatechange - * Fires before the start date of the view changes, giving you an opportunity to save state or - * anything else you may need to do prior to the UI view changing. This is a cancelable event, so - * returning false from a handler will cancel both the view change and the setting of the start date. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Date} startDate The current start date of the view (as explained in {@link #getStartDate} - * @param {Date} newStartDate The new start date that will be set when the view changes - * @param {Date} viewStart The first displayed date in the current view - * @param {Date} viewEnd The last displayed date in the current view - */ - /** - * @event dayclick - * Fires after the user clicks within a day/week view container and not on an event element - * @param {Extensible.calendar.CalendarPanel} this - * @param {Date} dt The date/time that was clicked on - * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. - * @param {Ext.Element} el The Element that was clicked on - */ - /** - * @event datechange - * Fires after the start date of the view changes - * @param {Extensible.calendar.CalendarPanel} this - * @param {Date} startDate The start date of the view (as explained in {@link #getStartDate} - * @param {Date} viewStart The first displayed date in the view - * @param {Date} viewEnd The last displayed date in the view - */ - /** - * @event beforeeventmove - * Fires before an event element is dragged by the user and dropped in a new position. This is - * a cancelable event, so returning false from a handler will cancel the move operation. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that will be moved - */ - /** - * @event eventmove - * Fires after an event element is dragged by the user and dropped in a new position - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that was moved with - * updated start and end dates - */ - /** - * @event initdrag - * Fires when a drag operation is initiated in the view - * @param {Extensible.calendar.CalendarPanel} this - */ - /** - * @event dayover - * Fires while the mouse is over a day element - * @param {Extensible.calendar.CalendarPanel} this - * @param {Date} dt The date that is being moused over - * @param {Ext.Element} el The day Element that is being moused over - */ - /** - * @event dayout - * Fires when the mouse exits a day element - * @param {Extensible.calendar.CalendarPanel} this - * @param {Date} dt The date that is exited - * @param {Ext.Element} el The day Element that is exited - */ - /** - * @event beforeeventresize - * Fires after the user drags the resize handle of an event to resize it, but before the - * resize operation is carried out. This is a cancelable event, so returning false from a - * handler will cancel the resize operation. **NOTE:** This event is only fired - * from views that support event resizing. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that was resized - * containing the updated start and end dates - */ - /** - * @event eventresize - * Fires after the user drags the resize handle of an event and the resize operation is - * complete. **NOTE:** This event is only fired from views that support event resizing. - * @param {Extensible.calendar.CalendarPanel} this - * @param {Extensible.calendar.data.EventModel} rec The - * {@link Extensible.calendar.data.EventModel record} for the event that was resized - * containing the updated start and end dates - */ - /** - * @event eventexception - * Fires after an event has been processed via an Ext proxy and returned with an exception. This - * could be because of a server error, or because the data returned success: false. - * - * The view provides default handling via the overrideable - * {@link Extensible.calendar.view.AbstractCalendar#notifyOnException notifyOnException} method. If - * any function handling this event returns false, the notifyOnException method will not be called. - * - * Note that only Server proxy and subclasses (including Ajax proxy) will raise this event. - * - * @param {Extensible.calendar.CalendarPanel} this - * @param {Object} response The raw response object returned from the server - * @param {Ext.data.Operation} operation The operation that was processed - * @since 1.6.0 - */ - }); - + this.addCls('x-cal-panel'); - + if(this.eventStore) { this.store = this.eventStore; delete this.eventStore; } this.setStore(this.store); - + var sharedViewCfg = { showToday: this.showToday, todayText: this.todayText, @@ -566,13 +575,13 @@ Ext.define('Extensible.calendar.CalendarPanel', { startDay: this.startDay, ownerCalendarPanel: this }; - + if(this.showDayView) { var day = Ext.apply({ xtype: 'extensible.dayview', title: this.dayText }, sharedViewCfg); - + day = Ext.apply(Ext.apply(day, this.viewConfig), this.dayViewCfg); day.id = this.id+'-day'; this.initEventRelay(day); @@ -583,7 +592,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { xtype: 'extensible.multidayview', title: this.getMultiDayText(multiDayViewCount) }, sharedViewCfg); - + mday = Ext.apply(Ext.apply(mday, this.viewConfig), this.multiDayViewCfg); mday.id = this.id+'-multiday'; this.initEventRelay(mday); @@ -594,7 +603,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { xtype: 'extensible.weekview', title: this.weekText }, sharedViewCfg); - + wk = Ext.apply(Ext.apply(wk, this.viewConfig), this.weekViewCfg); wk.id = this.id+'-week'; this.initEventRelay(wk); @@ -605,7 +614,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { xtype: 'extensible.multiweekview', title: this.getMultiWeekText(multiWeekViewCount) }, sharedViewCfg); - + mwk = Ext.apply(Ext.apply(mwk, this.viewConfig), this.multiWeekViewCfg); mwk.id = this.id+'-multiweek'; this.initEventRelay(mwk); @@ -624,7 +633,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { } } }, sharedViewCfg); - + month = Ext.apply(Ext.apply(month, this.viewConfig), this.monthViewCfg); month.id = this.id+'-month'; this.initEventRelay(month); @@ -657,7 +666,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { 'beforeeventmove', 'eventmove', 'initdrag', 'dayover', 'dayout', 'beforeeventresize', 'eventresize', 'eventadd', 'eventupdate', 'beforeeventdelete', 'eventdelete', 'eventcancel', 'eventexception']); - + c.on('editdetails', this.onEditDetails, this); }, scope: this, @@ -667,12 +676,12 @@ Ext.define('Extensible.calendar.CalendarPanel', { afterRender: function() { this.callParent(arguments); - + this.body.addCls('x-cal-body'); this.updateNavState(); this.setActiveView(); }, - + /** * Returns the text to use for the 'X Days' nav bar button (defaults to "{0} Days" where {0} is automatically replaced by the * value of the {@link #multDayViewCfg}'s dayCount value if available, otherwise it uses the view default of 3). @@ -680,7 +689,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { getMultiDayText: function(numDays) { return this.multiDayText; }, - + /** * Returns the text to use for the 'X Weeks' nav bar button (defaults to "{0} Weeks" where {0} is automatically replaced by the * value of the {@link #multiWeekViewCfg}'s weekCount value if available, otherwise it uses the view default of 2). @@ -688,14 +697,14 @@ Ext.define('Extensible.calendar.CalendarPanel', { getMultiWeekText: function(numWeeks) { return this.multiWeekText; }, - + /** * Sets the event store used by the calendar to display {@link Extensible.calendar.data.EventModel events}. * @param {Ext.data.Store} store */ setStore: function(store, initial) { var currStore = this.store; - + if(!initial && currStore) { currStore.un("write", this.onWrite, this); } @@ -721,7 +730,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { onWrite: function(store, operation) { var rec = operation.records[0]; - + switch(operation.action) { case 'create': this.onStoreAdd(store, rec); @@ -774,7 +783,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { this.hideEditForm(); this.fireEvent('eventcancel', this, rec); }, - + /** * Shows the built-in event edit form for the passed in event record. This method automatically * hides the calendar views and navigation toolbar. To return to the calendar, call {@link #hideEditForm}. @@ -787,7 +796,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { this.layout.getActiveItem().loadRecord(rec); return this; }, - + /** * Hides the built-in event edit form and returns to the previous calendar view. If the edit form is * not currently visible this method has no effect. @@ -800,10 +809,10 @@ Ext.define('Extensible.calendar.CalendarPanel', { } return this; }, - + /** * Set the active view, optionally specifying a new start date. - * @param {String/Number} id The id of the view to activate (or the 0-based index of the view within + * @param {String/Number} id The id of the view to activate (or the 0-based index of the view within * the CalendarPanel's internal card layout). * @param {Date} startDate (optional) The new view start date (defaults to the current start date) */ @@ -812,11 +821,11 @@ Ext.define('Extensible.calendar.CalendarPanel', { layout = me.layout, editViewId = me.id + '-edit', toolbar; - + if (startDate) { me.startDate = startDate; } - + // Make sure we're actually changing views if (id !== layout.getActiveItem().id) { // Show/hide the toolbar first so that the layout will calculate the correct item size @@ -824,12 +833,13 @@ Ext.define('Extensible.calendar.CalendarPanel', { if (toolbar) { toolbar[id === editViewId ? 'hide' : 'show'](); } - + + Ext.suspendLayouts(); + // Activate the new view and refresh the layout layout.setActiveItem(id || me.activeItem); - me.doComponentLayout(); me.activeView = layout.getActiveItem(); - + if (id !== editViewId) { if (id && id !== me.preEditView) { // We're changing to a different view, so the view dates are likely different. @@ -842,7 +852,9 @@ Ext.define('Extensible.calendar.CalendarPanel', { // so update the nav bar's selected view button me.updateNavState(); } + // Notify any listeners that the view changed + Ext.resumeLayouts(true); me.fireViewChange(); } }, @@ -851,10 +863,10 @@ Ext.define('Extensible.calendar.CalendarPanel', { if (this.layout && this.layout.getActiveItem) { var view = this.layout.getActiveItem(), cloneDt = Ext.Date.clone; - + if (view) { var info; - + // some views do not have these properties, e.g. the detailed edit form if (view.getViewBounds) { var vb = view.getViewBounds(); @@ -875,11 +887,11 @@ Ext.define('Extensible.calendar.CalendarPanel', { updateNavState: function() { var me = this, activeItem = me.layout.activeItem; - + if (activeItem && me.showNavBar !== false) { var suffix = activeItem.id.split(me.id + '-')[1], btn = Ext.getCmp(me.id + '-tb-' + suffix); - + if (me.showNavToday) { Ext.getCmp(me.id + '-tb-today').setDisabled(activeItem.isToday()); } @@ -952,7 +964,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { onMonthNavClick: function() { this.setActiveView(this.id+'-month'); }, - + /** * Return the calendar view that is currently active, which will be a subclass of * {@link Extensible.calendar.view.AbstractCalendar AbstractCalendar}. @@ -961,4 +973,4 @@ Ext.define('Extensible.calendar.CalendarPanel', { getActiveView: function() { return this.layout.activeItem; } -}); \ No newline at end of file +}); diff --git a/src/calendar/data/EventStore.js b/src/calendar/data/EventStore.js index f05eb9d4..1f35aabd 100644 --- a/src/calendar/data/EventStore.js +++ b/src/calendar/data/EventStore.js @@ -4,10 +4,10 @@ Ext.define('Extensible.calendar.data.EventStore', { extend: 'Ext.data.Store', model: 'Extensible.calendar.data.EventModel', - + constructor: function(config) { config = config || {}; - + // By default autoLoad will cause the store to load itself during the // constructor, before the owning calendar view has a chance to set up // the initial date params to use during loading. We replace autoLoad @@ -15,30 +15,30 @@ Ext.define('Extensible.calendar.data.EventStore', { // up default params as needed, then call the load itself. this.deferLoad = config.autoLoad; config.autoLoad = false; - + //this._dateCache = []; - + this.callParent(arguments); }, - + load: function(o) { Extensible.log('store load'); o = o || {}; - + // if params are passed delete the one-time defaults - if(o.params) { + if (o.params) { delete this.initialParams; } // this.initialParams will only be set if the store is being loaded manually // for the first time (autoLoad = false) so the owning calendar view set // the initial start and end date params to use. Every load after that will // have these params set automatically during normal UI navigation. - if(this.initialParams) { + if (this.initialParams) { o.params = o.params || {}; Ext.apply(o.params, this.initialParams); delete this.initialParams; } - + this.callParent(arguments); } -}); \ No newline at end of file +}); diff --git a/src/calendar/data/MemoryCalendarStore.js b/src/calendar/data/MemoryCalendarStore.js index 90fa5560..12bbe74b 100644 --- a/src/calendar/data/MemoryCalendarStore.js +++ b/src/calendar/data/MemoryCalendarStore.js @@ -5,7 +5,7 @@ Ext.define('Extensible.calendar.data.MemoryCalendarStore', { extend: 'Ext.data.Store', model: 'Extensible.calendar.data.CalendarModel', - + requires: [ 'Ext.data.proxy.Memory', 'Ext.data.reader.Json', @@ -13,12 +13,12 @@ Ext.define('Extensible.calendar.data.MemoryCalendarStore', { 'Extensible.calendar.data.CalendarModel', 'Extensible.calendar.data.CalendarMappings' ], - + proxy: { type: 'memory', reader: { type: 'json', - root: 'calendars' + rootProperty: 'calendars' }, writer: { type: 'json' @@ -26,17 +26,17 @@ Ext.define('Extensible.calendar.data.MemoryCalendarStore', { }, autoLoad: true, - + initComponent: function() { this.sorters = this.sorters || [{ property: Extensible.calendar.data.CalendarMappings.Title.name, direction: 'ASC' }]; - + this.idProperty = this.idProperty || Extensible.calendar.data.CalendarMappings.CalendarId.name || 'id'; - + this.fields = Extensible.calendar.data.CalendarModel.prototype.fields.getRange(); - + this.callParent(arguments); } -}); \ No newline at end of file +}); diff --git a/src/calendar/data/MemoryEventStore.js b/src/calendar/data/MemoryEventStore.js index abf44084..d646d1d7 100644 --- a/src/calendar/data/MemoryEventStore.js +++ b/src/calendar/data/MemoryEventStore.js @@ -28,13 +28,13 @@ Ext.define('Extensible.calendar.data.MemoryEventStore', { type: 'memory', reader: { type: 'json', - root: 'evts' + rootProperty: 'evts' }, writer: { type: 'json' } }, - + // Since we are faking persistence in memory, we also have to fake our primary // keys for things to work consistently. This starting id value will be auto- // incremented as records are created: @@ -53,7 +53,7 @@ Ext.define('Extensible.calendar.data.MemoryEventStore', { this.idProperty = this.idProperty || Extensible.calendar.data.EventMappings.EventId.mapping || 'id'; - this.fields = Extensible.calendar.data.EventModel.prototype.fields.getRange(); + this.fields = Extensible.calendar.data.EventModel.getFields(); // By default this shared example store will monitor its own CRUD events and // automatically show a page-level message for each event. This is simply a shortcut @@ -153,4 +153,4 @@ Ext.define('Extensible.calendar.data.MemoryEventStore', { me.loading = false; me.fireEvent('load', me, records, successful); } -}); \ No newline at end of file +}); diff --git a/src/calendar/dd/DayDragZone.js b/src/calendar/dd/DayDragZone.js index ef2d42ab..fc684987 100644 --- a/src/calendar/dd/DayDragZone.js +++ b/src/calendar/dd/DayDragZone.js @@ -4,19 +4,19 @@ */ Ext.define('Extensible.calendar.dd.DayDragZone', { extend: 'Extensible.calendar.dd.DragZone', - + ddGroup: 'DayViewDD', resizeSelector: '.ext-evt-rsz', - + getDragData: function(e) { var target = e.getTarget(this.resizeSelector, 2, true), rec, parent; - + if (target) { parent = target.parent(this.eventSelector); rec = this.view.getEventRecordFromEl(parent); - + if (!rec) { // if rec is null here it usually means there was a timing issue between drag // start and the browser reporting it properly. Simply ignore and it will @@ -32,12 +32,12 @@ Ext.define('Extensible.calendar.dd.DayDragZone', { proxy: this.proxy }; } - + target = e.getTarget(this.eventSelector, this.eventSelectorDepth); - + if (target) { rec = this.view.getEventRecordFromEl(target); - + if (!rec) { // if rec is null here it usually means there was a timing issue between drag // start and the browser reporting it properly. Simply ignore and it will @@ -53,10 +53,10 @@ Ext.define('Extensible.calendar.dd.DayDragZone', { proxy: this.proxy }; } - + // If not dragging/resizing an event then we are dragging on the calendar to add a new event target = this.view.getDayAt(e.getX(), e.getY()); - + if (target.el) { return { type: 'caldrag', @@ -66,4 +66,4 @@ Ext.define('Extensible.calendar.dd.DayDragZone', { } return null; } -}); \ No newline at end of file +}); diff --git a/src/calendar/dd/DropZone.js b/src/calendar/dd/DropZone.js index 355957cf..e05059dc 100644 --- a/src/calendar/dd/DropZone.js +++ b/src/calendar/dd/DropZone.js @@ -20,8 +20,8 @@ Ext.define('Extensible.calendar.dd.DropZone', { getTargetFromEvent: function(e) { var dragOffset = this.dragOffset || 0, - y = e.getPageY() - dragOffset, - d = this.view.getDayAt(e.getPageX(), y); + y = e.getY() - dragOffset, + d = this.view.getDayAt(e.getX(), y); return d.el ? d: null; }, @@ -128,11 +128,10 @@ Ext.define('Extensible.calendar.dd.DropZone', { el.className = 'ext-dd-shim'; this.shimCt.appendChild(el); - return Ext.create('Ext.Layer', { - shadow: false, - useDisplay: true, - constrain: false - }, el); + el = Ext.get(el); + el.setVisibilityMode(2); + + return el; }, clearShims: function() { diff --git a/src/calendar/dd/StatusProxy.js b/src/calendar/dd/StatusProxy.js index 42b7d204..926d33d6 100644 --- a/src/calendar/dd/StatusProxy.js +++ b/src/calendar/dd/StatusProxy.js @@ -1,12 +1,12 @@ /** - * A specialized drag proxy that supports a drop status icon, {@link Ext.dom.Layer} styles and auto-repair. It also - * contains a calendar-specific drag status message containing details about the dragged event's target drop date range. - * This is the default drag proxy used by all calendar views. + * A specialized drag proxy that supports a drop status icon and auto-repair. It also contains a + * calendar-specific drag status message containing details about the dragged event's target drop + * date range. This is the default drag proxy used by all calendar views. * @private */ Ext.define('Extensible.calendar.dd.StatusProxy', { extend: 'Ext.dd.StatusProxy', - + /** * @cfg {String} moveEventCls * The CSS class to apply to the status element when an event is being dragged (defaults to 'ext-cal-dd-move'). @@ -23,17 +23,17 @@ Ext.define('Extensible.calendar.dd.StatusProxy', { renderTpl: [ '
', '
', - '
', - '
', + '
', + '
', '
' ], - + // applies only to Ext 4.1 and above, see notes in constructor childEls: [ 'ghost', 'message' ], - + constructor: function(config) { // In Ext 4.0.x StatusProxy was a plain class that did not inherit from Component, // and all of its els were rendered inside the constructor. Unfortunately, because @@ -51,13 +51,13 @@ Ext.define('Extensible.calendar.dd.StatusProxy', { this.callParent(arguments); } }, - + // applies only to Ext <4.1, see notes in constructor preComponentConstructor: function(config) { var me = this; - + Ext.apply(me, config); - + me.id = me.id || Ext.id(); me.proxy = Ext.createWidget('component', { floating: true, @@ -67,30 +67,30 @@ Ext.define('Extensible.calendar.dd.StatusProxy', { shadow: !config || config.shadow !== false, renderTo: document.body }); - + me.el = me.proxy.el; me.el.show(); me.el.setVisibilityMode(Ext.Element.VISIBILITY); me.el.hide(); - + me.ghost = Ext.get(me.el.dom.childNodes[1].childNodes[0]); me.message = Ext.get(me.el.dom.childNodes[1].childNodes[1]); me.dropStatus = me.dropNotAllowed; }, - + /** - * @protected + * @protected */ update: function(html) { this.callParent(arguments); - + // If available, set the ghosted event el to autoHeight for visual consistency var el = this.ghost.dom.firstChild; if(el) { Ext.fly(el).setHeight('auto'); } }, - + /* @private * Update the calendar-specific drag status message without altering the ghost element. * @param {String} msg The new status message @@ -98,4 +98,4 @@ Ext.define('Extensible.calendar.dd.StatusProxy', { updateMsg: function(msg) { this.message.update(msg); } -}); \ No newline at end of file +}); diff --git a/src/calendar/form/EventDetails.js b/src/calendar/form/EventDetails.js index baecc4ec..59c78b7d 100644 --- a/src/calendar/form/EventDetails.js +++ b/src/calendar/form/EventDetails.js @@ -45,7 +45,6 @@ Ext.define('Extensible.calendar.form.EventDetails', { 'Extensible.calendar.data.EventMappings', 'Extensible.calendar.form.field.CalendarCombo', 'Extensible.form.recurrence.Fieldset', - 'Ext.layout.container.Column', 'Extensible.form.recurrence.RangeEditWindow' ], @@ -105,45 +104,44 @@ Ext.define('Extensible.calendar.form.EventDetails', { allowDefaultAdd: true, //private properties - layout: 'column', + layout: { + type: 'hbox', + align: 'stretch' + }, - initComponent: function() { + /** + * @event eventadd + * Fires after a new event is added + * @param {Extensible.calendar.form.EventDetails} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was added + */ - this.addEvents({ - /** - * @event eventadd - * Fires after a new event is added - * @param {Extensible.calendar.form.EventDetails} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * record} that was added - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event is updated - * @param {Extensible.calendar.form.EventDetails} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * record} that was updated - */ - eventupdate: true, - /** - * @event eventdelete - * Fires after an event is deleted - * @param {Extensible.calendar.form.EventDetails} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * record} that was deleted - */ - eventdelete: true, - /** - * @event eventcancel - * Fires after an event add/edit operation is canceled by the user and no store update took place - * @param {Extensible.calendar.form.EventDetails} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * record} that was canceled - */ - eventcancel: true - }); + /** + * @event eventupdate + * Fires after an existing event is updated + * @param {Extensible.calendar.form.EventDetails} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was updated + */ + /** + * @event eventdelete + * Fires after an event is deleted + * @param {Extensible.calendar.form.EventDetails} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was deleted + */ + + /** + * @event eventcancel + * Fires after an event add/edit operation is canceled by the user and no store update took place + * @param {Extensible.calendar.form.EventDetails} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was canceled + */ + + initComponent: function() { this.titleField = Ext.create('Ext.form.field.Text', { fieldLabel: this.titleLabelText, name: Extensible.calendar.data.EventMappings.Title.name, @@ -218,7 +216,7 @@ Ext.define('Extensible.calendar.form.EventDetails', { this.items = [{ id: this.id+'-left-col', - columnWidth: this.colWidthLeft, + flex: this.colWidthLeft, layout: 'anchor', fieldDefaults: { labelWidth: labelWidth @@ -227,7 +225,7 @@ Ext.define('Extensible.calendar.form.EventDetails', { items: leftFields },{ id: this.id+'-right-col', - columnWidth: this.colWidthRight, + flex: this.colWidthRight, layout: 'anchor', fieldDefaults: { labelWidth: labelWidth @@ -306,9 +304,9 @@ Ext.define('Extensible.calendar.form.EventDetails', { // Using setValue() results in dirty fields, so we reset the field state // after loading the form so that the current values are the "original" values - me.form.getFields().each(function(item) { - item.resetOriginalValue(); - }); + // Ext.Array.each(me.form.getFields(), function(item) { + // item.resetOriginalValue(); + // }); me.titleField.focus(); }, @@ -320,7 +318,7 @@ Ext.define('Extensible.calendar.form.EventDetails', { name, obj = {}; - fields.each(function(f) { + Ext.Array.each(fields, function(f) { name = f.name; if (name in values) { obj[name] = values[name]; diff --git a/src/calendar/form/EventWindow.js b/src/calendar/form/EventWindow.js index aaa94944..d87c64c9 100644 --- a/src/calendar/form/EventWindow.js +++ b/src/calendar/form/EventWindow.js @@ -94,60 +94,57 @@ Ext.define('Extensible.calendar.form.EventWindow', { */ allowDefaultAdd: true, - initComponent: function() { - this.addEvents({ - /** - * @event eventadd - * Fires after a new event is added - * @param {Extensible.calendar.form.EventWindow} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * record} that was added - * @param {Ext.Element} el The target element - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event is updated - * @param {Extensible.calendar.form.EventWindow} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * record} that was updated - * @param {Ext.Element} el The target element - */ - eventupdate: true, - /** - * @event eventdelete - * Fires after an event is deleted - * @param {Extensible.calendar.form.EventWindow} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * 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 {Extensible.calendar.form.EventWindow} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel - * 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 Extensible.calendar.form.EventDetails}. 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 Extensible.calendar.form.EventDetails#loadRecord loadRecord}. - * @param {Extensible.calendar.form.EventWindow} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} - * that is currently being edited - * @param {Ext.Element} el The target element - */ - editdetails: true - }); + /** + * @event eventadd + * Fires after a new event is added + * @param {Extensible.calendar.form.EventWindow} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was added + * @param {Ext.Element} el The target element + */ - this.fbar = this.getFooterBarConfig(); + /** + * @event eventupdate + * Fires after an existing event is updated + * @param {Extensible.calendar.form.EventWindow} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was updated + * @param {Ext.Element} el The target element + */ + /** + * @event eventdelete + * Fires after an event is deleted + * @param {Extensible.calendar.form.EventWindow} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was deleted + * @param {Ext.Element} el The target element + */ + + /** + * @event eventcancel + * Fires after an event add/edit operation is canceled by the user and no store update took place + * @param {Extensible.calendar.form.EventWindow} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel + * record} that was canceled + * @param {Ext.Element} el The target element + */ + + /** + * @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 Extensible.calendar.form.EventDetails}. 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 Extensible.calendar.form.EventDetails#loadRecord loadRecord}. + * @param {Extensible.calendar.form.EventWindow} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} + * that is currently being edited + * @param {Ext.Element} el The target element + */ + + // private + initComponent: function() { + this.fbar = this.getFooterBarConfig(); this.callParent(arguments); }, @@ -302,27 +299,28 @@ Ext.define('Extensible.calendar.form.EventWindow', { me.setTitle(me.titleTextAdd); var start = o[EventMappings.StartDate.name], - end = o[EventMappings.EndDate.name] || Extensible.Date.add(start, {hours: 1}); - - rec = Ext.create('Extensible.calendar.data.EventModel'); + end = o[EventMappings.EndDate.name] || Extensible.Date.add(start, {hours: 1}), + eventData = {}; - rec.data[EventMappings.Title.name] = o[EventMappings.Title.name]; // in case it's set - rec.data[EventMappings.StartDate.name] = start; - rec.data[EventMappings.EndDate.name] = end; + eventData[EventMappings.Title.name] = o[EventMappings.Title.name]; // in case it's set + eventData[EventMappings.StartDate.name] = start; + eventData[EventMappings.EndDate.name] = end; - rec.data[EventMappings.IsAllDay.name] = !!o[EventMappings.IsAllDay.name] || + eventData[EventMappings.IsAllDay.name] = !!o[EventMappings.IsAllDay.name] || (start.getDate() !== Extensible.Date.add(end, {millis: 1}).getDate()); if (EventMappings.CalendarId) { - rec.data[EventMappings.CalendarId.name] = me.calendarStore ? + eventData[EventMappings.CalendarId.name] = me.calendarStore ? me.calendarStore.getAt(0).data[Extensible.calendar.data.CalendarMappings.CalendarId.name] : ''; } if (EventMappings.Duration) { - rec.data[EventMappings.Duration.name] = Extensible.Date.diff(start, end, + eventData[EventMappings.Duration.name] = Extensible.Date.diff(start, end, Extensible.calendar.data.EventModel.resolution); } + rec = new Extensible.calendar.data.EventModel(eventData); + form.reset(); form.loadRecord(rec); } @@ -336,9 +334,9 @@ Ext.define('Extensible.calendar.form.EventWindow', { // Using setValue() results in dirty fields, so we reset the field state // after loading the form so that the current values are the "original" values - form.getFields().each(function(item) { - item.resetOriginalValue(); - }); + // Ext.Array.each(form.getFields(), function(item) { + // item.resetOriginalValue(); + // }); return me; }, @@ -368,14 +366,14 @@ Ext.define('Extensible.calendar.form.EventWindow', { }, updateRecord: function(record, keepEditing) { - var fields = record.fields, + var fields = record.getFields(), values = this.formPanel.getForm().getValues(), EventMappings = Extensible.calendar.data.EventMappings, name, obj = {}, modified; - fields.each(function(f) { + Ext.Array.each(fields, function(f) { name = f.name; if (name in values) { obj[name] = values[name]; diff --git a/src/calendar/form/field/CalendarCombo.js b/src/calendar/form/field/CalendarCombo.js index 96b2cbdb..5ec27210 100644 --- a/src/calendar/form/field/CalendarCombo.js +++ b/src/calendar/form/field/CalendarCombo.js @@ -1,7 +1,7 @@ /** * A custom combo used for choosing from the list of available calendars to assign an event to. You must * pass a populated calendar store as the store config or the combo will not work. - * + * * This is pretty much a standard combo that is simply pre-configured for the options needed by the * calendar components. The default configs are as follows: * fieldLabel: 'Calendar', @@ -13,47 +13,47 @@ Ext.define('Extensible.calendar.form.field.CalendarCombo', { extend: 'Ext.form.field.ComboBox', alias: 'widget.extensible.calendarcombo', - + requires: ['Extensible.calendar.data.CalendarMappings'], - + fieldLabel: 'Calendar', triggerAction: 'all', queryMode: 'local', forceSelection: true, selectOnFocus: true, - + defaultCls: 'x-cal-default', hiddenCalendarCls: 'ext-cal-hidden', - + initComponent: function() { this.valueField = Extensible.calendar.data.CalendarMappings.CalendarId.name; this.displayField = Extensible.calendar.data.CalendarMappings.Title.name; - + this.listConfig = Ext.apply(this.listConfig || {}, { getInnerTpl: this.getListItemTpl }); - + this.store.on('update', this.refreshColorCls, this); - + this.callParent(arguments); }, - + getListItemTpl: function(displayField) { return '
 
{' + displayField + '}
'; }, - + afterRender: function() { this.callParent(arguments); - - this.wrap = this.el.down('.x-form-item-body'); + + this.wrap = this.el.down('.x-form-text-wrap'); this.wrap.addCls('ext-calendar-picker'); - + this.icon = Ext.core.DomHelper.append(this.wrap, { tag: 'div', cls: 'ext-cal-picker-icon ext-cal-picker-mainicon' }); }, - + /* @private * Refresh the color CSS class based on the current field value */ @@ -62,14 +62,14 @@ Ext.define('Extensible.calendar.form.field.CalendarCombo', { calendarMappings = Extensible.calendar.data.CalendarMappings, colorCls = '', value = me.getValue(); - + if (!me.wrap) { return me; } if (me.currentStyleClss !== undefined) { me.wrap.removeCls(me.currentStyleClss); } - + if (!Ext.isEmpty(value)) { if (Ext.isArray(value)) { value = value[0]; @@ -80,28 +80,28 @@ Ext.define('Extensible.calendar.form.field.CalendarCombo', { } colorCls = 'x-cal-' + (value.data ? value.data[calendarMappings.ColorId.name] : value); } - + me.currentStyleClss = colorCls; - + // if (value && value.data && value.data[calendarMappings.IsHidden.name] === true) { // colorCls += ' ' + me.hiddenCalendarCls; // } me.wrap.addCls(colorCls); - + return me; }, - + /** - * @protected + * @protected */ setValue: function(value) { if (!value && this.store.getCount() > 0) { // ensure that a valid value is always set if possible value = this.store.getAt(0).data[Extensible.calendar.data.CalendarMappings.CalendarId.name]; } - + this.callParent(arguments); - + this.refreshColorCls(); } -}); \ No newline at end of file +}); diff --git a/src/calendar/view/AbstractCalendar.js b/src/calendar/view/AbstractCalendar.js index ac066e18..2d15fc27 100644 --- a/src/calendar/view/AbstractCalendar.js +++ b/src/calendar/view/AbstractCalendar.js @@ -26,6 +26,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * Note that this is an alias to the default {@link #store} config (to differentiate that from the optional {@link #calendarStore} * config), and either can be used interchangeably. */ + /** * @cfg {Ext.data.Store} calendarStore * The {@link Ext.data.Store store} which is bound to this calendar and contains {@link Extensible.calendar.data.CalendarModel CalendarRecords}. @@ -33,6 +34,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * calendar in which to save an event will be shown in the edit forms. If this store is not available then all events will simply use * the default calendar (and color). */ + /* * @cfg {Boolean} recurrence * True to show the recurrence field, false to hide it (default). Note that recurrence requires @@ -57,11 +59,13 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * @cfg {Boolean} readOnly * True to prevent clicks on events or the view from providing CRUD capabilities, false to enable CRUD (the default). */ + /** * @cfg {Number} startDay * The 0-based index for the day on which the calendar week begins (0=Sunday, which is the default) */ startDay: 0, + /** * @cfg {Boolean} spansHavePriority * Allows switching between two different modes of rendering events that span multiple days. When true, @@ -72,12 +76,14 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * first which can result in a less compact, but chronologically consistent layout. */ spansHavePriority: false, + /** * @cfg {Boolean} trackMouseOver * Whether or not the view tracks and responds to the browser mouseover event on contained elements (defaults to * true). If you don't need mouseover event highlighting you can disable this. */ trackMouseOver: true, + /** * @cfg {Boolean} enableFx * Determines whether or not visual effects for CRUD actions are enabled (defaults to true). If this is false @@ -85,6 +91,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * all animations will be disabled. */ enableFx: true, + /** * @cfg {Boolean} enableAddFx * True to enable a visual effect on adding a new event (the default), false to disable it. Note that if @@ -92,6 +99,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * {@link #doAddFx} method. */ enableAddFx: true, + /** * @cfg {Boolean} enableUpdateFx * True to enable a visual effect on updating an event, false to disable it (the default). Note that if @@ -99,6 +107,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * {@link #doUpdateFx} method. */ enableUpdateFx: false, + /** * @cfg {Boolean} enableRemoveFx * True to enable a visual effect on removing an event (the default), false to disable it. Note that if @@ -106,17 +115,20 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * {@link #doRemoveFx} method. */ enableRemoveFx: true, + /** * @cfg {Boolean} enableDD * True to enable drag and drop in the calendar view (the default), false to disable it */ enableDD: true, + /** * @cfg {Boolean} enableContextMenus * True to enable automatic right-click context menu handling in the calendar views (the default), false to disable * them. Different context menus are provided when clicking on events vs. the view background. */ enableContextMenus: true, + /** * @cfg {Boolean} suppressBrowserContextMenu * When {@link #enableContextMenus} is true, the browser context menu will automatically be suppressed whenever a @@ -125,6 +137,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * the browser context menu will still show if the right-clicked element has no custom menu (this is the default). */ suppressBrowserContextMenu: false, + /** * @cfg {Boolean} monitorResize * True to monitor the browser's resize event (the default), false to ignore it. If the calendar view is rendered @@ -133,29 +146,34 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * any resize event propagates properly to all subcomponents and layouts get recalculated properly. */ monitorResize: true, + /** * @cfg {String} todayText * The text to display in the current day's box in the calendar when {@link #showTodayText} is true (defaults to 'Today') */ todayText: 'Today', + /** * @cfg {String} ddCreateEventText * The text to display inside the drag proxy while dragging over the calendar to create a new event (defaults to * 'Create event for {0}' where {0} is a date range supplied by the view) */ ddCreateEventText: 'Create event for {0}', + /** * @cfg {String} ddCopyEventText * The text to display inside the drag proxy while alt-dragging an event to copy it (defaults to * 'Copy event to {0}' where {0} is the updated event start date/time supplied by the view) */ ddCopyEventText: 'Copy event to {0}', + /** * @cfg {String} ddMoveEventText * The text to display inside the drag proxy while dragging an event to reposition it (defaults to * 'Move event to {0}' where {0} is the updated event start date/time supplied by the view) */ ddMoveEventText: 'Move event to {0}', + /** * @cfg {String} ddResizeEventText * The string displayed to the user in the drag proxy while dragging the resize handle of an event (defaults to @@ -164,28 +182,33 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * that allow resizing of events. */ ddResizeEventText: 'Update event to {0}', + /** * @cfg {String} defaultEventTitleText * The default text to display as the title of an event that has a null or empty string title value (defaults to '(No title)') */ defaultEventTitleText: '(No title)', + /** * @cfg {String} dateParamStart * The param name representing the start date of the current view range that's passed in requests to retrieve events * when loading the view (defaults to 'startDate'). */ dateParamStart: 'startDate', + /** * @cfg {String} dateParamEnd * The param name representing the end date of the current view range that's passed in requests to retrieve events * when loading the view (defaults to 'endDate'). */ dateParamEnd: 'endDate', + /** * @cfg {String} dateParamFormat * The format to use for date parameters sent with requests to retrieve events for the calendar (defaults to 'Y-m-d', e.g. '2010-10-31') */ dateParamFormat: 'Y-m-d', + /** * @cfg {Boolean} editModal * True to show the default event editor window modally over the entire page, false to allow user interaction with the page @@ -193,36 +216,42 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * config will no longer apply. */ editModal: false, + /** * @cfg {Boolean} enableEditDetails * True to show a link on the event edit window to allow switching to the detailed edit form (the default), false to remove the * link and disable detailed event editing. */ enableEditDetails: true, + /** * @cfg {String} weekendCls * A CSS class to apply to weekend days in the current view (defaults to 'ext-cal-day-we' which highlights weekend days in light blue). * To disable this styling set the value to null or ''. */ weekendCls: 'ext-cal-day-we', + /** * @cfg {String} prevMonthCls * A CSS class to apply to any days that fall in the month previous to the current view's month (defaults to 'ext-cal-day-prev' which * highlights previous month days in light gray). To disable this styling set the value to null or ''. */ prevMonthCls: 'ext-cal-day-prev', + /** * @cfg {String} nextMonthCls * A CSS class to apply to any days that fall in the month after the current view's month (defaults to 'ext-cal-day-next' which * highlights next month days in light gray). To disable this styling set the value to null or ''. */ nextMonthCls: 'ext-cal-day-next', + /** * @cfg {String} todayCls * A CSS class to apply to the current date when it is visible in the current view (defaults to 'ext-cal-day-today' which * highlights today in yellow). To disable this styling set the value to null or ''. */ todayCls: 'ext-cal-day-today', + /** * @cfg {String} hideMode * How this component should be hidden. Supported values are 'visibility' @@ -233,6 +262,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * 'display' in order to preserve scroll position after hiding/showing a scrollable view like Day or Week. */ hideMode: 'offsets', + /** * @cfg {String} notifyOnExceptionTitle * @since 1.6.0 @@ -240,6 +270,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * (defaults to "Server Error"). */ notifyOnExceptionTitle: 'Server Error', + /** * @cfg {String} notifyOnExceptionText * @since 1.6.0 @@ -247,6 +278,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * (defaults to "The action failed with the following response:"). The text of the error is appended. */ notifyOnExceptionText: 'The action failed with the following response:', + /** * @cfg {String} notifyOnExceptionDefaultMessage * @since 1.6.0 @@ -334,6 +366,207 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { * @method getEventClass * @return {String} A space-delimited CSS class string (or '') */ + getEventClass: Ext.emptyFn, + + /** + * @event eventsrendered + * Fires after events are finished rendering in the view + * @param {Extensible.calendar.view.AbstractCalendar} this + */ + + /** + * @event eventclick + * Fires after the user clicks on an event element. This is a cancelable event, so returning false from a + * handler will cancel the click without displaying the event editor view. This could be useful for + * validating the rules by which events should be editable by the user. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that was clicked on + * @param {HTMLNode} el The DOM node that was clicked on + */ + + /** + * @event eventover + * Fires anytime the mouse is over an event element + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that the cursor is over + * @param {HTMLNode} el The DOM node that is being moused over + */ + + /** + * @event eventout + * Fires anytime the mouse exits an event element + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that the cursor exited + * @param {HTMLNode} el The DOM node that was exited + */ + + /** + * @event beforedatechange + * Fires before the start date of the view changes, giving you an opportunity to save state or anything else you may need + * to do prior to the UI view changing. This is a cancelable event, so returning false from a handler will cancel both the + * view change and the setting of the start date. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Date} startDate The current start date of the view (as explained in {@link #getStartDate} + * @param {Date} newStartDate The new start date that will be set when the view changes + * @param {Date} viewStart The first displayed date in the current view + * @param {Date} viewEnd The last displayed date in the current view + */ + + /** + * @event datechange + * Fires after the start date of the view has changed. If you need to cancel the date change you should handle the + * {@link #beforedatechange} event and return false from your handler function. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Date} startDate The start date of the view (as explained in {@link #getStartDate} + * @param {Date} viewStart The first displayed date in the view + * @param {Date} viewEnd The last displayed date in the view + */ + + /** + * @event rangeselect + * Fires after the user drags on the calendar to select a range of dates/times in which to create an event. This is a + * cancelable event, so returning false from a handler will cancel the drag operation and clean up any drag shim elements + * without displaying the event editor view. This could be useful for validating that a user can only create events within + * a certain range. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Object} dates An object containing the start (StartDate property) and end (EndDate property) dates selected + * @param {Function} callback A callback function that MUST be called after the event handling is complete so that + * the view is properly cleaned up (shim elements are persisted in the view while the user is prompted to handle the + * range selection). The callback is already created in the proper scope, so it simply needs to be executed as a standard + * function call (e.g., callback()). + */ + + /** + * @event beforeeventcopy + * Fires before an existing event is duplicated by the user via the "copy" command. This is a + * cancelable event, so returning false from a handler will cancel the copy operation. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} for the event that will be copied + * @param {Date} dt The new start date to be set in the copy (the end date will be automaticaly + * adjusted to match the original event duration) + */ + + /** + * @event eventcopy + * Fires after an event has been duplicated by the user via the "copy" command. If you need to + * cancel the copy operation you should handle the {@link #beforeeventcopy} event and return + * false from your handler function. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} for the event that was copied (with updated start and end dates) + */ + + /** + * @event beforeeventmove + * Fires after an event element has been dragged by the user and dropped in a new position, but before + * the event record is updated with the new dates, providing a hook for canceling the update. + * To cancel the move, return false from a handling function. This could be useful for validating + * that a user can only move events within a certain date range, for example. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} + * for the event that will be moved. Start and end dates will be the original values before the move started. + * @param {Date} dt The new start date to be set (the end date will be automaticaly calculated to match + * based on the event duration) + */ + + /** + * @event eventmove + * Fires after an event element has been moved to a new position and its data updated. If you need to + * cancel the move operation you should handle the {@link #beforeeventmove} event and return false + * from your handler function. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} + * for the event that was moved with updated start and end dates + */ + + /** + * @event initdrag + * Fires when a drag operation is initiated in the view + * @param {Extensible.calendar.view.AbstractCalendar} this + */ + + /** + * @event dayover + * Fires while the mouse is over a day element + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Date} dt The date that is being moused over + * @param {Ext.Element} el The day Element that is being moused over + */ + + /** + * @event dayout + * Fires when the mouse exits a day element + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Date} dt The date that is exited + * @param {Ext.Element} el The day Element that is exited + */ + + /** + * @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 Extensible.calendar.form.EventDetails}. 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 Extensible.calendar.form.EventDetails#loadRecord loadRecord}. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} that is currently being edited + * @param {Ext.Element} el The target element + */ + + /** + * @event eventadd + * Fires after a new event has been added to the underlying store + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel record} that was added + */ + + /** + * @event eventupdate + * Fires after an existing event has been updated + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel record} that was updated + */ + + /** + * @event eventcancel + * Fires after an event add/edit operation has been canceled by the user and no store update took place + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel record} that was canceled + */ + + /** + * @event beforeeventdelete + * Fires before an event is deleted by the user. This is a cancelable event, so returning false from a handler + * will cancel the delete operation. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that was deleted + * @param {Ext.Element} el The target element + */ + + /** + * @event eventdelete + * Fires after an event has been deleted by the user. If you need to cancel the delete operation you should handle the + * {@link #beforeeventdelete} event and return false from your handler function. + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that was deleted + * @param {Ext.Element} el The target element + */ + + /** + * @event eventexception + * Fires after an event has been processed via an Ext proxy and returned with an exception. This + * could be because of a server error, or because the data returned success: false. + * + * The view provides default handling via the overrideable {@link #notifyOnException} method. If + * any function handling this event returns false, the notifyOnException method will not be called. + * + * Note that only Server proxy and subclasses (including Ajax proxy) will raise this event. + * + * @param {Extensible.calendar.view.AbstractCalendar} this + * @param {Object} response The raw response object returned from the server + * @param {Ext.data.Operation} operation The operation that was processed + * @since 1.6.0 + */ initComponent: function() { this.setStartDate(this.startDate || new Date()); @@ -343,209 +576,6 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { if (this.readOnly === true) { this.addCls('ext-cal-readonly'); } - - this.addEvents({ - /** - * @event eventsrendered - * Fires after events are finished rendering in the view - * @param {Extensible.calendar.view.AbstractCalendar} this - */ - eventsrendered: true, - /** - * @event eventclick - * Fires after the user clicks on an event element. This is a cancelable event, so returning false from a - * handler will cancel the click without displaying the event editor view. This could be useful for - * validating the rules by which events should be editable by the user. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that was clicked on - * @param {HTMLNode} el The DOM node that was clicked on - */ - eventclick: true, - /** - * @event eventover - * Fires anytime the mouse is over an event element - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that the cursor is over - * @param {HTMLNode} el The DOM node that is being moused over - */ - eventover: true, - /** - * @event eventout - * Fires anytime the mouse exits an event element - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that the cursor exited - * @param {HTMLNode} el The DOM node that was exited - */ - eventout: true, - /** - * @event beforedatechange - * Fires before the start date of the view changes, giving you an opportunity to save state or anything else you may need - * to do prior to the UI view changing. This is a cancelable event, so returning false from a handler will cancel both the - * view change and the setting of the start date. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Date} startDate The current start date of the view (as explained in {@link #getStartDate} - * @param {Date} newStartDate The new start date that will be set when the view changes - * @param {Date} viewStart The first displayed date in the current view - * @param {Date} viewEnd The last displayed date in the current view - */ - beforedatechange: true, - /** - * @event datechange - * Fires after the start date of the view has changed. If you need to cancel the date change you should handle the - * {@link #beforedatechange} event and return false from your handler function. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Date} startDate The start date of the view (as explained in {@link #getStartDate} - * @param {Date} viewStart The first displayed date in the view - * @param {Date} viewEnd The last displayed date in the view - */ - datechange: true, - /** - * @event rangeselect - * Fires after the user drags on the calendar to select a range of dates/times in which to create an event. This is a - * cancelable event, so returning false from a handler will cancel the drag operation and clean up any drag shim elements - * without displaying the event editor view. This could be useful for validating that a user can only create events within - * a certain range. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Object} dates An object containing the start (StartDate property) and end (EndDate property) dates selected - * @param {Function} callback A callback function that MUST be called after the event handling is complete so that - * the view is properly cleaned up (shim elements are persisted in the view while the user is prompted to handle the - * range selection). The callback is already created in the proper scope, so it simply needs to be executed as a standard - * function call (e.g., callback()). - */ - rangeselect: true, - /** - * @event beforeeventcopy - * Fires before an existing event is duplicated by the user via the "copy" command. This is a - * cancelable event, so returning false from a handler will cancel the copy operation. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} for the event that will be copied - * @param {Date} dt The new start date to be set in the copy (the end date will be automaticaly - * adjusted to match the original event duration) - */ - beforeeventcopy: true, - /** - * @event eventcopy - * Fires after an event has been duplicated by the user via the "copy" command. If you need to - * cancel the copy operation you should handle the {@link #beforeeventcopy} event and return - * false from your handler function. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} for the event that was copied (with updated start and end dates) - */ - eventcopy: true, - /** - * @event beforeeventmove - * Fires after an event element has been dragged by the user and dropped in a new position, but before - * the event record is updated with the new dates, providing a hook for canceling the update. - * To cancel the move, return false from a handling function. This could be useful for validating - * that a user can only move events within a certain date range, for example. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} - * for the event that will be moved. Start and end dates will be the original values before the move started. - * @param {Date} dt The new start date to be set (the end date will be automaticaly calculated to match - * based on the event duration) - */ - beforeeventmove: true, - /** - * @event eventmove - * Fires after an event element has been moved to a new position and its data updated. If you need to - * cancel the move operation you should handle the {@link #beforeeventmove} event and return false - * from your handler function. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} - * for the event that was moved with updated start and end dates - */ - eventmove: true, - /** - * @event initdrag - * Fires when a drag operation is initiated in the view - * @param {Extensible.calendar.view.AbstractCalendar} this - */ - initdrag: true, - /** - * @event dayover - * Fires while the mouse is over a day element - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Date} dt The date that is being moused over - * @param {Ext.Element} el The day Element that is being moused over - */ - dayover: true, - /** - * @event dayout - * Fires when the mouse exits a day element - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Date} dt The date that is exited - * @param {Ext.Element} el The day Element that is exited - */ - dayout: 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 Extensible.calendar.form.EventDetails}. 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 Extensible.calendar.form.EventDetails#loadRecord loadRecord}. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} that is currently being edited - * @param {Ext.Element} el The target element - */ - editdetails: true, - /** - * @event eventadd - * Fires after a new event has been added to the underlying store - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel record} that was added - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event has been updated - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel record} that was updated - */ - eventupdate: true, - /** - * @event eventcancel - * Fires after an event add/edit operation has been canceled by the user and no store update took place - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The new {@link Extensible.calendar.data.EventModel record} that was canceled - */ - eventcancel: true, - /** - * @event beforeeventdelete - * Fires before an event is deleted by the user. This is a cancelable event, so returning false from a handler - * will cancel the delete operation. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that was deleted - * @param {Ext.Element} el The target element - */ - beforeeventdelete: true, - /** - * @event eventdelete - * Fires after an event has been deleted by the user. If you need to cancel the delete operation you should handle the - * {@link #beforeeventdelete} event and return false from your handler function. - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel record} for the event that was deleted - * @param {Ext.Element} el The target element - */ - eventdelete: true, - /** - * @event eventexception - * Fires after an event has been processed via an Ext proxy and returned with an exception. This - * could be because of a server error, or because the data returned success: false. - * - * The view provides default handling via the overrideable {@link #notifyOnException} method. If - * any function handling this event returns false, the notifyOnException method will not be called. - * - * Note that only Server proxy and subclasses (including Ajax proxy) will raise this event. - * - * @param {Extensible.calendar.view.AbstractCalendar} this - * @param {Object} response The raw response object returned from the server - * @param {Ext.data.Operation} operation The operation that was processed - * @since 1.6.0 - */ - eventexception: true - }); }, afterRender: function() { @@ -865,6 +895,7 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { renderTemplate: function() { if (this.tpl) { + this.el.select('*').destroy(); this.tpl.overwrite(this.el, this.getTemplateParams()); this.lastRenderStart = Ext.Date.clone(this.viewStart); this.lastRenderEnd = Ext.Date.clone(this.viewEnd); diff --git a/src/calendar/view/DayBody.js b/src/calendar/view/DayBody.js index 3279455f..da742430 100644 --- a/src/calendar/view/DayBody.js +++ b/src/calendar/view/DayBody.js @@ -17,9 +17,46 @@ Ext.define('Extensible.calendar.view.DayBody', { 'Extensible.calendar.dd.DayDropZone' ], - dayColumnElIdDelimiter: '-day-col-', hourIncrement: 60, + // private + dayColumnElIdDelimiter: '-day-col-', + + /** + * @event beforeeventresize + * Fires after the user drags the resize handle of an event to resize it, but before the resize + * operation is carried out. This is a cancelable event, so returning false from a handler will + * cancel the resize operation. + * @param {Extensible.calendar.view.DayBody} this + * @param {Extensible.calendar.data.EventModel} rec The original {@link + * Extensible.calendar.data.EventModel record} for the event that was resized + * @param {Object} data An object containing the new start and end dates that will be set into the + * event record if the event is not canceled. Format of the object is: {StartDate: [date], EndDate: [date]} + */ + + /** + * @event eventresize + * Fires after the user has drag-dropped the resize handle of an event and the resize operation is + * complete. If you need to cancel the resize operation you should handle the {@link #beforeeventresize} + * event and return false from your handler function. + * @param {Extensible.calendar.view.DayBody} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} for the event that was resized containing the updated start and end dates + */ + + /** + * @event dayclick + * Fires after the user clicks within the view container and not on an event element. This is a + * cancelable event, so returning false from a handler will cancel the click without displaying the event + * editor view. This could be useful for validating that a user can only create events on certain days. + * @param {Extensible.calendar.view.DayBody} this + * @param {Date} dt The date/time that was clicked on + * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. Clicks + * within the DayBodyView always return false for this param. + * @param {Ext.Element} el The Element that was clicked on + */ + + initComponent: function() { this.callParent(arguments); @@ -28,43 +65,6 @@ Ext.define('Extensible.calendar.view.DayBody', { } this.incrementsPerHour = this.hourIncrement / this.ddIncrement; this.minEventHeight = this.minEventDisplayMinutes / (this.hourIncrement / this.hourHeight); - - this.addEvents({ - /** - * @event beforeeventresize - * Fires after the user drags the resize handle of an event to resize it, but before the resize - * operation is carried out. This is a cancelable event, so returning false from a handler will - * cancel the resize operation. - * @param {Extensible.calendar.view.DayBody} this - * @param {Extensible.calendar.data.EventModel} rec The original {@link - * Extensible.calendar.data.EventModel record} for the event that was resized - * @param {Object} data An object containing the new start and end dates that will be set into the - * event record if the event is not canceled. Format of the object is: {StartDate: [date], EndDate: [date]} - */ - beforeeventresize: true, - /** - * @event eventresize - * Fires after the user has drag-dropped the resize handle of an event and the resize operation is - * complete. If you need to cancel the resize operation you should handle the {@link #beforeeventresize} - * event and return false from your handler function. - * @param {Extensible.calendar.view.DayBody} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} for the event that was resized containing the updated start and end dates - */ - eventresize: true, - /** - * @event dayclick - * Fires after the user clicks within the view container and not on an event element. This is a - * cancelable event, so returning false from a handler will cancel the click without displaying the event - * editor view. This could be useful for validating that a user can only create events on certain days. - * @param {Extensible.calendar.view.DayBody} this - * @param {Date} dt The date/time that was clicked on - * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. Clicks - * within the DayBodyView always return false for this param. - * @param {Ext.Element} el The Element that was clicked on - */ - dayclick: true - }); }, initDD: function() { @@ -489,7 +489,8 @@ Ext.define('Extensible.calendar.view.DayBody', { var markup = this.getEventTemplate().apply(evt), target = this.id + '-day-col-' + Ext.Date.format(evts[i].date, 'Ymd'); - Ext.DomHelper.append(target, markup); + Ext.get(target).select('*').destroy(); + Ext.core.DomHelper.append(target, markup); } this.fireEvent('eventsrendered', this); diff --git a/src/calendar/view/Month.js b/src/calendar/view/Month.js index 8f84389e..51f67d54 100644 --- a/src/calendar/view/Month.js +++ b/src/calendar/view/Month.js @@ -25,29 +25,34 @@ Ext.define('Extensible.calendar.view.Month', { * @deprecated */ moreText: '+{0} more...', + /** * @cfg {String} detailsTitleDateFormat * The date format for the title of the details panel that shows when there are hidden events and the "more" link * is clicked (defaults to 'F j'). */ detailsTitleDateFormat: 'F j', + /** * @cfg {Boolean} showTime * True to display the current time in today's box in the calendar, false to not display it (defaults to true) */ showTime: true, + /** * @cfg {Boolean} showTodayText * True to display the {@link #todayText} string in today's box in the calendar, false to not display it * (defaults to true) */ showTodayText: true, + /** * @cfg {Boolean} showHeader * True to display a header beneath the navigation bar containing the week names above each week's column, false * not to show it and instead display the week names in the first row of days in the calendar (defaults to false). */ showHeader: false, + /** * @cfg {Boolean} showWeekLinks * True to display an extra column before the first day in the calendar that links to the @@ -55,18 +60,21 @@ Ext.define('Extensible.calendar.view.Month', { * If true, the week links can also contain the week number depending on the value of {@link #showWeekNumbers}. */ showWeekLinks: false, + /** * @cfg {Boolean} showWeekNumbers * True to show the week number for each week in the calendar in the week link column, false to show nothing * (defaults to false). Note that if {@link #showWeekLinks} is false this config will have no affect even if true. */ showWeekNumbers: false, + /** * @cfg {String} weekLinkOverClass * The CSS class name applied when the mouse moves over a week link element (only applies when * {@link #showWeekLinks} is true, defaults to 'ext-week-link-over'). */ weekLinkOverClass: 'ext-week-link-over', + /** * @cfg {Number} morePanelMinWidth * When there are more events in a given day than can be displayed in the calendar view, the extra events @@ -86,39 +94,34 @@ Ext.define('Extensible.calendar.view.Month', { moreElIdDelimiter: '-more-', weekLinkIdDelimiter: 'ext-cal-week-', - initComponent: function() { - this.callParent(arguments); + /** + * @event dayclick + * Fires after the user clicks within the view container and not on an event element. This is a + * cancelable event, so returning false from a handler will cancel the click without displaying the event + * editor view. This could be useful for validating that a user can only create events on certain days. + * @param {Extensible.calendar.view.Month} this + * @param {Date} dt The date/time that was clicked on + * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. Clicks + * within the MonthView always return true for this param. + * @param {Ext.Element} el The Element that was clicked on + */ + + /** + * @event weekclick + * Fires after the user clicks within a week link (when {@link #showWeekLinks is true) + * @param {Extensible.calendar.view.Month} this + * @param {Date} dt The start date of the week that was clicked on + */ - this.addEvents({ - /** - * @event dayclick - * Fires after the user clicks within the view container and not on an event element. This is a - * cancelable event, so returning false from a handler will cancel the click without displaying the event - * editor view. This could be useful for validating that a user can only create events on certain days. - * @param {Extensible.calendar.view.Month} this - * @param {Date} dt The date/time that was clicked on - * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. Clicks - * within the MonthView always return true for this param. - * @param {Ext.Element} el The Element that was clicked on - */ - dayclick: true, - /** - * @event weekclick - * Fires after the user clicks within a week link (when {@link #showWeekLinks is true) - * @param {Extensible.calendar.view.Month} this - * @param {Date} dt The start date of the week that was clicked on - */ - weekclick: true, /** * @protected */ - dayover: true, + dayover: true, + /** * @protected */ - dayout: true - }); - }, + dayout: true, initDD: function() { var cfg = { @@ -250,9 +253,12 @@ Ext.define('Extensible.calendar.view.Month', { */ getEventTemplate: function() { if(!this.eventTpl) { - var tpl, body = this.getEventBodyMarkup(); + var tpl, + body = this.getEventBodyMarkup(), + isOldOpera = Ext.isOpera && (parseInt(Ext.operaVersion) < 11); + - tpl = !(Ext.isIE || Ext.isOpera) ? + tpl = !(Ext.isIE7m || isOldOpera) ? Ext.create('Ext.XTemplate', '
', body, @@ -527,7 +533,7 @@ Ext.define('Extensible.calendar.view.Month', { p.setHeight(calculatedHeight); p.show(); - p.getPositionEl().alignTo(dayEl, 't-t?'); + p.getEl().alignTo(dayEl, 't-t?'); }, onHide: function() { diff --git a/src/calendar/view/MonthDayDetail.js b/src/calendar/view/MonthDayDetail.js index 754c6d10..a392ac2c 100644 --- a/src/calendar/view/MonthDayDetail.js +++ b/src/calendar/view/MonthDayDetail.js @@ -7,33 +7,25 @@ Ext.define('Extensible.calendar.view.MonthDayDetail', { extend: 'Ext.Component', alias: 'widget.extensible.monthdaydetailview', - + requires: [ 'Ext.XTemplate', 'Extensible.calendar.view.AbstractCalendar' ], - - initComponent: function() { - this.callParent(arguments); - - this.addEvents({ - eventsrendered: true - }); - }, - + afterRender: function() { this.tpl = this.getTemplate(); - + this.callParent(arguments); - + this.el.on({ - 'click': this.view.onClick, - 'mouseover': this.view.onMouseOver, - 'mouseout': this.view.onMouseOut, + click: this.view.onClick, + mouseover: this.view.onMouseOver, + mouseout: this.view.onMouseOut, scope: this.view }); }, - + getTemplate: function() { if(!this.tpl) { this.tpl = Ext.create('Ext.XTemplate', @@ -51,20 +43,20 @@ Ext.define('Extensible.calendar.view.MonthDayDetail', { this.tpl.compile(); return this.tpl; }, - + update: function(dt) { this.date = dt; this.refresh(); }, - + refresh: function() { if(!this.rendered) { return; } var eventTpl = this.view.getEventTemplate(), - + templateData = []; - + var evts = this.store.queryBy(function(rec) { var thisDt = Ext.Date.clearTime(this.date, true).getTime(), M = Extensible.calendar.data.EventMappings, @@ -73,25 +65,25 @@ Ext.define('Extensible.calendar.view.MonthDayDetail', { spansDate = false, calId = rec.data[M.CalendarId.name], calRec = this.calendarStore ? this.calendarStore.getById(calId) : null; - + if(calRec && calRec.data[Extensible.calendar.data.CalendarMappings.IsHidden.name] === true) { // if the event is on a hidden calendar then no need to test the date boundaries return false; } - + if(!startsOnDate) { var recEnd = Ext.Date.clearTime(rec.data[M.EndDate.name], true).getTime(); spansDate = recStart < thisDt && recEnd >= thisDt; } return startsOnDate || spansDate; }, this); - + Extensible.calendar.view.AbstractCalendar.prototype.sortEventRecordsForDay.call(this, evts); - + evts.each(function(evt) { var item = evt.data, M = Extensible.calendar.data.EventMappings; - + item._renderAsAllDay = item[M.IsAllDay.name] || Extensible.Date.diffDays(item[M.StartDate.name], item[M.EndDate.name]) > 0; item.spanLeft = Extensible.Date.diffDays(item[M.StartDate.name], this.date) > 0; item.spanRight = Extensible.Date.diffDays(this.date, item[M.EndDate.name]) > 0; @@ -100,14 +92,14 @@ Ext.define('Extensible.calendar.view.MonthDayDetail', { templateData.push({markup: eventTpl.apply(this.getTemplateEventData(item, evt))}); }, this); - + this.tpl.overwrite(this.el, templateData); this.fireEvent('eventsrendered', this, this.date, evts.getCount()); }, - + getTemplateEventData: function(evtData, evt) { var data = this.view.getTemplateEventData(evtData, evt); data._elId = 'dtl-'+data._elId; return data; } -}); \ No newline at end of file +}); diff --git a/src/data/Model.js b/src/data/Model.js index da35ae75..e010d45b 100644 --- a/src/data/Model.js +++ b/src/data/Model.js @@ -3,17 +3,15 @@ */ Ext.define('Extensible.data.Model', { extend: 'Ext.data.Model', - - requires: [ - 'Ext.util.MixedCollection' - ], - + + identifier: 'sequential', + // *Must* be defined by subclasses mappingClass: null, - + // Should be defined by subclasses, or will default to the default Model id property mappingIdProperty: null, - + inheritableStatics: { /** * Reconfigures the default model definition based on the current @@ -30,35 +28,22 @@ Ext.define('Extensible.data.Model', { fields = [], i = 0, len = 0; - + if (!mappings) { throw 'The mappingClass for ' + this.$className + ' is undefined or invalid'; } - // TODO: Add this as a compile-time warning: - //if (!idProperty) { - // idProperty should usually be defined at this point, so make sure it's not missing - //} - + // It is critical that the id property mapping is updated in case it changed, since it // is used elsewhere in the data package to match records on CRUD actions: proto.idProperty = idProperty || proto.idProperty || 'id'; - - for (prop in mappings) { - if(mappings.hasOwnProperty(prop)) { - fields.push(mappings[prop]); - } - } - proto.fields.clear(); - len = fields.length; - - for (; i < len; i++) { - proto.fields.add(Ext.create('Ext.data.Field', fields[i])); - } + // Remap the fields + this.replaceFields(Ext.Object.getValues(mappings), true); + return this; } }, - + /** * Returns a new instance of this Model with the `data` property deep-copied from the * original record. By default the {@link #idProperty} value will be deleted to avoid returning @@ -75,12 +60,12 @@ Ext.define('Extensible.data.Model', { clone: function(preserveId) { var copy = Ext.create(this.$className), dataProp = this.persistenceProperty; - + copy[dataProp] = Ext.Object.merge({}, this[dataProp]); - + if (preserveId !== true) { delete copy[dataProp][this.idProperty]; } return copy; } -}); \ No newline at end of file +}); diff --git a/src/form/field/DateRange.js b/src/form/field/DateRange.js index 005eadcf..d75fdd8b 100644 --- a/src/form/field/DateRange.js +++ b/src/form/field/DateRange.js @@ -17,11 +17,13 @@ Ext.define('Extensible.form.field.DateRange', { * The text to display in between the date/time fields (defaults to 'to') */ toText: 'to', + /** * @cfg {String} allDayText * The text to display as the label for the all day checkbox (defaults to 'All day') */ allDayText: 'All day', + /** * @cfg {String/Boolean} singleLine * true to render the fields all on one line, false to break the start @@ -29,6 +31,7 @@ Ext.define('Extensible.form.field.DateRange', { * (defaults to true). */ singleLine: true, + /* * @cfg {Number} singleLineMinWidth -- not currently used * If {@link singleLine} is set to 'auto' it will use this value to determine whether to render the field on one @@ -36,20 +39,23 @@ Ext.define('Extensible.form.field.DateRange', { * the field's container is narrower than this value it will automatically be rendered on two lines. */ //singleLineMinWidth: 490, + /** * @cfg {String} dateFormat * The date display format used by the date fields (defaults to 'n/j/Y') */ dateFormat: 'n/j/Y', + /** * @cfg {Number} startDay * The 0-based index for the day on which the calendar week begins (0=Sunday, which is the default) */ startDay: 0, - fieldLayout: { - type: 'hbox', - defaultMargins: { top: 0, right: 5, bottom: 0, left: 0 } + fieldLayout: 'hbox', + + defaults: { + margin: '0 5 0 0' }, initComponent: function() { @@ -206,7 +212,7 @@ Ext.define('Extensible.form.field.DateRange', { id: this.id + '-allday', hidden: this.showTimes === false || this.showAllDay === false, boxLabel: this.allDayText, - margins: { top: 2, right: 5, bottom: 0, left: 0 }, + margin: '2 5 0 0', handler: this.onAllDayChange, scope: this }; @@ -222,7 +228,7 @@ Ext.define('Extensible.form.field.DateRange', { xtype: 'label', id: this.id + '-to-label', text: this.toText, - margins: { top: 4, right: 5, bottom: 0, left: 0 } + margin: '4 5 0 0', }; }, From 11fb3b0cf0b907334fb2552e52d52033054a4d78 Mon Sep 17 00:00:00 2001 From: Brian Moeskau Date: Sun, 17 Apr 2016 16:38:32 -0500 Subject: [PATCH 2/5] Convert useNull -> allowNull --- examples/calendar/data/Events.js | 2 +- examples/calendar/remote/recurrence.js | 36 +++++++++++++------------- src/calendar/data/EventMappings.js | 36 +++++++++++++------------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/examples/calendar/data/Events.js b/examples/calendar/data/Events.js index a67602eb..3d4cf31e 100644 --- a/examples/calendar/data/Events.js +++ b/examples/calendar/data/Events.js @@ -25,7 +25,7 @@ Ext.define('Extensible.example.calendar.data.Events', { "start" : makeDate(0, 11, 30), "end" : makeDate(0, 13), "loc" : "Chuy's!", - "url" : "http : //chuys.com", + "url" : "http://chuys.com", "notes" : "Order the queso", "rem" : "15" },{ diff --git a/examples/calendar/remote/recurrence.js b/examples/calendar/remote/recurrence.js index 0cca44a7..dffe08d5 100644 --- a/examples/calendar/remote/recurrence.js +++ b/examples/calendar/remote/recurrence.js @@ -25,13 +25,13 @@ Ext.onReady(function() { // Tell PHP to start a debugging session for an IDE to connect to. // This is passed as an additional parameter on each request: //XDEBUG_SESSION_START: 1, - + // Slight hack just so that we can reuse the same demo server code // with persistence across multiple examples so that each example gets // its own unique data set: app_id: 'recurrence' }; - + // Set up mappings to match the DB column names as defined in examples/server/setup.sql Extensible.calendar.data.EventMappings = { EventId: {name: 'EventId', mapping:'id', type:'string'}, @@ -44,25 +44,25 @@ Ext.onReady(function() { Url: {name: 'Url', mapping: 'url'}, IsAllDay: {name: 'IsAllDay', mapping: 'all_day', type: 'boolean'}, Reminder: {name: 'Reminder', mapping: 'reminder'}, - + // NOTE that since we want recurrence support in this demo, we must also include // the recurrence-specific data mappings. Typically RRule and Duration are the only // values that need to be persisted and returned with events, and they are the only ones // mapped to columns in the MySQL database: - RRule: {name: 'RRule', mapping: 'rrule', type: 'string', useNull: true}, - Duration: {name: 'Duration', mapping: 'duration', defaultValue: -1, useNull: true, type: 'int'}, - + RRule: {name: 'RRule', mapping: 'rrule', type: 'string', allowNull: true}, + Duration: {name: 'Duration', mapping: 'duration', defaultValue: -1, allowNull: true, type: 'int'}, + // These additional values are required for processing recurring events properly, // but are either calculated or used only during editing. They still must be mapped // to whatever the server expects, but typically aren't persisted in the DB. For additional // details see the comments in src/calendar/data/EventMappings. - OriginalEventId: {name: 'OriginalEventId', mapping: 'origid', type: 'string', useNull: true}, - RSeriesStartDate: {name: 'RSeriesStartDate', mapping: 'rsstart', type: 'date', dateFormat: 'c', useNull: true}, - RInstanceStartDate: {name: 'RInstanceStartDate', mapping: 'ristart', type: 'date', dateFormat: 'c', useNull: true}, - REditMode: {name: 'REditMode', mapping: 'redit', type: 'string', useNull: true} + OriginalEventId: {name: 'OriginalEventId', mapping: 'origid', type: 'string', allowNull: true}, + RSeriesStartDate: {name: 'RSeriesStartDate', mapping: 'rsstart', type: 'date', dateFormat: 'c', allowNull: true}, + RInstanceStartDate: {name: 'RInstanceStartDate', mapping: 'ristart', type: 'date', dateFormat: 'c', allowNull: true}, + REditMode: {name: 'REditMode', mapping: 'redit', type: 'string', allowNull: true} }; Extensible.calendar.data.EventModel.reconfigure(); - + // Calendars are loaded remotely from a static JSON file var calendarStore = Ext.create('Extensible.calendar.data.MemoryCalendarStore', { autoLoad: true, @@ -70,19 +70,19 @@ Ext.onReady(function() { type: 'ajax', url: '../data/calendars.json', noCache: false, - + reader: { type: 'json', root: 'calendars' } } }); - + // Events are loaded remotely via Ajax. For simplicity in this demo we use simple param-based // actions, although you could easily use REST instead, swapping out the proxy type below. // The event data will still be passed as JSON in the request body. var apiBase = '../../server/php/api/events-recurrence.php?action='; - + var eventStore = Ext.create('Extensible.calendar.data.EventStore', { autoLoad: true, proxy: { @@ -91,7 +91,7 @@ Ext.onReady(function() { pageParam: null, startParam: null, limitParam: null, - + api: { read: apiBase + 'load', create: apiBase + 'add', @@ -130,7 +130,7 @@ Ext.onReady(function() { } } }); - + // This is the code for the entire UI: Ext.create('Ext.container.Viewport', { layout: 'border', @@ -149,7 +149,7 @@ Ext.onReady(function() { eventStore: eventStore, calendarStore: calendarStore, title: 'Recurrence Calendar', - + // This is the magical config that enables the recurrence edit // widget to appear in the event form. Without it, any existing // recurring events sent from the server will still be rendered @@ -159,4 +159,4 @@ Ext.onReady(function() { recurrence: true }] }); -}); \ No newline at end of file +}); diff --git a/src/calendar/data/EventMappings.js b/src/calendar/data/EventMappings.js index e3493f39..961ed933 100644 --- a/src/calendar/data/EventMappings.js +++ b/src/calendar/data/EventMappings.js @@ -8,7 +8,7 @@ * Ext records are mapped to your back-end data model. If you only need to change a handful * of field properties you can directly modify the EventMappings object as needed and then * reconfigure it. The simplest approach is to only override specific field attributes: - * + * * var M = Extensible.calendar.data.EventMappings; * M.Title.mapping = 'evt_title'; * M.Title.name = 'EventTitle'; @@ -18,7 +18,7 @@ * provide your own custom field definitions (as in the following example). Note that if you do * this, you **MUST** include a complete field definition, including the type attribute * if the field is not the default type of string. - * + * * // Add a new field that does not exist in the default EventMappings: * Extensible.calendar.data.EventMappings.Timestamp = { * name: 'Timestamp', @@ -33,7 +33,7 @@ * mappings have all been customized. Note that the name of each field definition object * (e.g., 'EventId') should **NOT** be changed for the default EventMappings fields as it * is the key used to access the field data programmatically. - * + * * Extensible.calendar.data.EventMappings = { * EventId: {name: 'ID', mapping:'evt_id', type:'int'}, * CalendarId: {name: 'CalID', mapping: 'cal_id', type: 'int'}, @@ -60,7 +60,7 @@ * that mapping as the idProperty of your data reader, otherwise it won't recognize how to * access the data correctly and will treat existing records as phantoms. Here's an easy way to make sure * your mapping is always valid: - * + * * var reader = new Ext.data.reader.Json({ * totalProperty: 'total', * successProperty: 'success', @@ -128,14 +128,14 @@ Extensible.calendar.data.EventMappings = { mapping: 'rem', type: 'string' }, - + // ----- Recurrence properties ----- // NOTE: Only RRule and Duration need to be persisted. The other properties // do need to be mapped as they are used on the back end, but typically they // are transient properties only used during processing of requests and do // not need to be stored in a DB. - + // The iCal-formatted RRULE (recurrence rule) pattern. // (See: http://www.kanzaki.com/docs/ical/rrule.html) // While technically recurrence could be implemented in other custom @@ -148,9 +148,9 @@ Extensible.calendar.data.EventMappings = { name: 'RRule', mapping: 'rrule', type: 'string', - useNull: true + allowNull: true }, - + // When using recurrence, the standard EndDate value will be the end date // of the _recurrence series_, not the end date of the "event". In fact, // with recurrence there is no single "event", only a pattern that generates @@ -162,10 +162,10 @@ Extensible.calendar.data.EventMappings = { name: 'Duration', mapping: 'duration', defaultValue: -1, // the standard int default of 0 is actually a valid duration - useNull: true, // Without this, the null returned from the server is coerced to 0 + allowNull: true, // Without this, the null returned from the server is coerced to 0 type: 'int' }, - + // This is used to associate recurring event instances back to their // original master events when sending edit requests to the server. This // is required since each individual event instance will have a unique id @@ -176,18 +176,18 @@ Extensible.calendar.data.EventMappings = { name: 'OriginalEventId', mapping: 'origid', type: 'string', - useNull: true + allowNull: true }, - + // The start date for the recurring series. RSeriesStartDate: { name: 'RSeriesStartDate', mapping: 'rsstart', type: 'date', dateFormat: 'c', - useNull: true + allowNull: true }, - + // If the start date of a recurring event instance is changed and then saved // using the "single" instance case (or if you drag an event instance and drop // it on a different date) the server has to create an exception for that instance @@ -199,9 +199,9 @@ Extensible.calendar.data.EventMappings = { mapping: 'ristart', type: 'date', dateFormat: 'c', - useNull: true + allowNull: true }, - + // Recurrence edit mode ('single', 'future' or 'all'). This is transient data // and would typically not be persisted (it's ignored by the calendar for // display purposes), but it's kept on the record for ease of transmission to @@ -210,6 +210,6 @@ Extensible.calendar.data.EventMappings = { name: 'REditMode', mapping: 'redit', type: 'string', - useNull: true + allowNull: true } -}; \ No newline at end of file +}; From fcf8a9cc32a6c58f7eb8fd8fed085bb3af68703b Mon Sep 17 00:00:00 2001 From: Brian Moeskau Date: Sun, 17 Apr 2016 22:43:12 -0500 Subject: [PATCH 3/5] Bunch of minor compatibility fixes --- examples/calendar/TestApp/App.js | 4 +- examples/calendar/remote/recurrence.js | 4 +- examples/calendar/remote/remote.js | 32 ++-- examples/calendar/window.js | 2 +- examples/examples.js | 15 +- examples/server/php/api/events-common.php | 24 +-- examples/server/php/api/events-recurrence.php | 8 +- resources/css/calendar.css | 45 ++---- src/calendar/CalendarPanel.js | 7 +- src/calendar/data/MemoryEventStore.js | 20 ++- src/calendar/gadget/CalendarListMenu.js | 72 +++++---- src/calendar/menu/Event.js | 127 ++++++++-------- src/form/recurrence/AbstractOption.js | 80 +++++----- src/form/recurrence/Fieldset.js | 143 +++++++++--------- src/form/recurrence/FrequencyCombo.js | 40 +++-- src/form/recurrence/option/Interval.js | 70 ++++----- 16 files changed, 349 insertions(+), 344 deletions(-) diff --git a/examples/calendar/TestApp/App.js b/examples/calendar/TestApp/App.js index 2b655eee..8ff4e4c3 100644 --- a/examples/calendar/TestApp/App.js +++ b/examples/calendar/TestApp/App.js @@ -67,7 +67,7 @@ Ext.define('Extensible.example.calendar.TestApp.App', { items: [{ id:'app-west', region: 'west', - width: 179, + width: 215, border: false, items: [{ xtype: 'datepicker', @@ -86,7 +86,7 @@ Ext.define('Extensible.example.calendar.TestApp.App', { xtype: 'extensible.calendarlist', store: this.calendarStore, border: false, - width: 178 + width: '100%' }] },{ xtype: 'extensible.calendarpanel', diff --git a/examples/calendar/remote/recurrence.js b/examples/calendar/remote/recurrence.js index dffe08d5..657ea26e 100644 --- a/examples/calendar/remote/recurrence.js +++ b/examples/calendar/remote/recurrence.js @@ -73,7 +73,7 @@ Ext.onReady(function() { reader: { type: 'json', - root: 'calendars' + rootProperty: 'calendars' } } }); @@ -100,7 +100,7 @@ Ext.onReady(function() { }, reader: { type: 'json', - root: 'data' + rootProperty: 'data' }, writer: { type: 'json', diff --git a/examples/calendar/remote/remote.js b/examples/calendar/remote/remote.js index df53ccad..a0c6df25 100644 --- a/examples/calendar/remote/remote.js +++ b/examples/calendar/remote/remote.js @@ -25,13 +25,13 @@ Ext.onReady(function() { // Tell PHP to start a debugging session for an IDE to connect to. // This is passed as an additional parameter on each request: // XDEBUG_SESSION_START: 1, - + // Slight hack just so that we can reuse the same demo server code // with persistence across multiple examples so that each example gets // its own unique data set: app_id: 'remote' }; - + // Set up mappings to match the DB column names as defined in examples/server/setup.sql Extensible.calendar.data.EventMappings = { EventId: {name: 'EventId', mapping:'id', type:'string'}, @@ -46,7 +46,7 @@ Ext.onReady(function() { Reminder: {name: 'Reminder', mapping: 'reminder'} }; Extensible.calendar.data.EventModel.reconfigure(); - + // Calendars are loaded remotely from a static JSON file var calendarStore = Ext.create('Extensible.calendar.data.MemoryCalendarStore', { autoLoad: true, @@ -54,19 +54,19 @@ Ext.onReady(function() { type: 'ajax', url: '../data/calendars.json', noCache: false, - + reader: { type: 'json', - root: 'calendars' + rootProperty: 'calendars' } } }); - + // Events are loaded remotely via Ajax. For simplicity in this demo we use simple param-based // actions, although you could easily use REST instead, swapping out the proxy type below. // The event data will still be passed as JSON in the request body. var apiBase = '../../server/php/api/events-basic.php?action='; - + var eventStore = Ext.create('Extensible.calendar.data.EventStore', { autoLoad: true, proxy: { @@ -75,7 +75,7 @@ Ext.onReady(function() { pageParam: null, startParam: null, limitParam: null, - + api: { read: apiBase + 'load', create: apiBase + 'add', @@ -84,7 +84,7 @@ Ext.onReady(function() { }, reader: { type: 'json', - root: 'data' + rootProperty: 'data' }, writer: { type: 'json', @@ -114,7 +114,7 @@ Ext.onReady(function() { } } }); - + // This is the actual calendar setup code -- pretty simple! var calendarPanel = Ext.create('Extensible.calendar.CalendarPanel', { id: 'calendar-remote', @@ -123,7 +123,7 @@ Ext.onReady(function() { calendarStore: calendarStore, title: 'Remote Calendar' }); - + Ext.create('Ext.container.Viewport', { layout: 'border', items: [{ @@ -138,7 +138,7 @@ Ext.onReady(function() { calendarPanel ] }); - + // You can optionally call load() here if you prefer instead of using the // autoLoad config. Note that as long as you call load AFTER the store // has been passed into the CalendarPanel the default start and end date parameters @@ -147,9 +147,9 @@ Ext.onReady(function() { // it will call the remote read method without any date parameters, which is most // likely not what you'll want. // store.load({ ... }); - + var errorCheckbox = Ext.get('forceError'); - + var setRemoteErrorMode = function() { if (errorCheckbox.dom.checked) { // force an error response to test handling of CUD (not R) actions. this param is @@ -162,7 +162,7 @@ Ext.onReady(function() { calendarPanel.setTitle('Remote Calendar'); } }; - + setRemoteErrorMode(); errorCheckbox.on('click', setRemoteErrorMode); -}); \ No newline at end of file +}); diff --git a/examples/calendar/window.js b/examples/calendar/window.js index 6cc0e4be..d9470f6b 100644 --- a/examples/calendar/window.js +++ b/examples/calendar/window.js @@ -36,7 +36,7 @@ Ext.onReady(function(){ this.calendarWin.show(); }; - Ext.fly('cal-win').on('click', showWindow, this); + Ext.get('cal-win').on('click', showWindow, this); showWindow(); }); diff --git a/examples/examples.js b/examples/examples.js index 310ecd16..85e4a8a8 100644 --- a/examples/examples.js +++ b/examples/examples.js @@ -7,10 +7,13 @@ Ext.define('Extensible.example', { this.msgCt.alignTo(document, 't-t'); var s = Ext.String.format.apply(String, Array.prototype.slice.call(arguments, 1)); var m = Ext.core.DomHelper.append(this.msgCt, {html:'

' + title + '

' + s + '

'}, true); - - m.slideIn('t').pause(3000).ghost('t', {remove:true}); + + m.slideIn('t').ghost('t', { + remove:true, + duration: 3000 + }); }, - + insertExamplesMenuLink: function() { var sampleCt = Ext.get('sample-overview'); if (sampleCt) { @@ -21,7 +24,7 @@ Ext.define('Extensible.example', { }); } }, - + insertViewSourceLink: function() { var sampleCt = Ext.get('sample-overview'); if (sampleCt) { @@ -47,7 +50,7 @@ Ext.onReady(function() { 'either need to build the project first (see the included README ' + 'file) or you should download the pre-built files from the Extensible website.'; - + Ext.Msg.show({ title: 'Extensible Not Ready', msg: msg, @@ -56,4 +59,4 @@ Ext.onReady(function() { maxWidth: 400 }); } -}); \ No newline at end of file +}); diff --git a/examples/server/php/api/events-common.php b/examples/server/php/api/events-common.php index 9a76a2ca..bc7df940 100644 --- a/examples/server/php/api/events-common.php +++ b/examples/server/php/api/events-common.php @@ -1,40 +1,40 @@ modify('+1 day'); $end_dt = $endDate->format('Y-m-d'); } - + // Set the app_id to allow each example to reuse this API with its own data. // In a real application this would not be needed. - $app_id = $event['app_id'] = isset($_REQUEST['app_id']) ? strtolower($_REQUEST['app_id']) : null; - + $app_id = $event['app_id'] = isset($_REQUEST['app_id']) ? strtolower($_REQUEST['app_id']) : 'remote'; + // The demos support simulating server failure for testing purposes $fail = isset($_REQUEST['fail']) ? TRUE : FALSE; // Helper function for outputting event resposnes consistently function out($result, $msg = null) { global $table; - + if (isset($result) && $result !== 0) { echo json_encode(array( 'success' => true, @@ -49,7 +49,7 @@ function out($result, $msg = null) { )); } }; - + if ($fail) { // The client requested a hard-coded failure, useful for testing echo json_encode(array( @@ -58,10 +58,10 @@ function out($result, $msg = null) { )); die(); } - + function handleException($e) { $msg = $e->getMessage(); - + if (preg_match('/table(.+)not found/i', $msg)) { out(0, 'Your database does not appear to be properly configured. '. 'Please see Extensible > examples > server > README.md. Details: '.$msg); diff --git a/examples/server/php/api/events-recurrence.php b/examples/server/php/api/events-recurrence.php index 81d184f9..a6c6faf6 100644 --- a/examples/server/php/api/events-recurrence.php +++ b/examples/server/php/api/events-recurrence.php @@ -260,12 +260,13 @@ function calculateEndDate($event) { if (isset($recurrence->end_date) && $recurrence->end_date < $max_date) { // The RRULE includes an explicit end date, so use that - $end = $recurrence->end_date->format($date_format).'Z'; + $recurrence->end_date->setTimezone(new DateTimeZone('UTC')); + $end = $recurrence->end_date->format($date_format); } else if (isset($recurrence->count) && $recurrence->count > 0) { // The RRULE has a limit, so calculate the end date based on the instance count $count = 0; - $newEnd; + $newEnd = null; $rdates = $recurrence->recur($event[$mappings['start_date']])->rrule($rrule); while ($rdate = $rdates->next()) { @@ -276,7 +277,8 @@ function calculateEndDate($event) { } // The 'minutes' portion should match Extensible.calendar.data.EventModel.resolution: $newEnd->modify('+'.$event[$mappings['duration']].' minutes'); - $end = $newEnd->format($date_format).'Z'; + $newEnd->setTimezone(new DateTimeZone('UTC')); + $end = $newEnd->format($date_format); } else { // The RRULE does not specify an end date or count, so default to max date diff --git a/resources/css/calendar.css b/resources/css/calendar.css index d003db7d..89777814 100644 --- a/resources/css/calendar.css +++ b/resources/css/calendar.css @@ -1,19 +1,19 @@ /******************************************* - * + * * Ext Calendar styles * ******************************************/ /* ----------------------------------------- - * Ext overrides + * Ext overrides */ .x-strict .x-webkit .x-small-editor .x-form-field-wrap .x-form-trigger { height: 21px; } /* ----------------------------------------- - * Shared calendar view containers + * Shared calendar view containers */ .x-panel-tbar .ext-cal-toolbar { padding: 3px; @@ -168,7 +168,7 @@ } .ext-cal-dayview .ext-cal-dtitle { padding: 8px 1px 2px; -} +} .ext-cal-hd-ad-bg-tbl { position: absolute; left: 0; @@ -354,7 +354,7 @@ .ext-cal-readonly .ext-cal-day, .ext-cal-readonly .ext-cal-dtitle { cursor: default; -} +} .ext-day-over { background: #D1EAEF !important; } @@ -756,22 +756,14 @@ td.ext-cal-dtitle-today div { } /******************************************* - * + * * Calendar navigation picker styles - * + * ******************************************/ .ext-cal-nav-picker { border-style: none none solid; border-color: #99BBE8; } -.ext-cal-nav-picker .x-datepicker-header { - background: #D3E1F1 url(../images/default/ext/toolbar-bg.gif) repeat-x; -} -.ext-cal-nav-picker .x-datepicker-month, -.ext-cal-nav-picker .x-datepicker-prev, -.ext-cal-nav-picker .x-datepicker-next { - background: transparent; -} .ext-cal-nav-picker .x-datepicker-prev a { background-image: url(../images/default/ext/page-prev.gif); } @@ -786,10 +778,6 @@ td.ext-cal-dtitle-today div { font-weight: bold; font-family: arial,tahoma,verdana,helvetica; } -.ext-cal-nav-picker .x-datepicker-month .x-btn-split-right { - background-image: url(../images/default/ext/button-arrow.gif) !important; - background-position: right 4px; -} .ext-cal-nav-picker .x-datepicker-inner { border-top: 1px solid #BBCCFF; } @@ -812,7 +800,7 @@ td.ext-cal-dtitle-today div { } /******************************************* - * + * * Calendar editor window styles * ******************************************/ @@ -831,7 +819,7 @@ td.ext-cal-dtitle-today div { } /******************************************* - * + * * Calendar form styles * ******************************************/ @@ -864,7 +852,7 @@ td.ext-cal-dtitle-today div { } /******************************************* - * + * * DateRangeField styles * ******************************************/ @@ -878,7 +866,7 @@ td.ext-cal-dtitle-today div { } /******************************************* - * + * * ContextMenu styles * ******************************************/ @@ -896,7 +884,7 @@ td.ext-cal-dtitle-today div { } /******************************************* - * + * * CalendarList styles * ******************************************/ @@ -969,12 +957,9 @@ td.ext-cal-dtitle-today div { .extensible-cal-icon-cal-show { background-image:url(../images/default/silk/calendar_view_month.png) !important; } -.extensible-cal-icon-cal-colors { - background-image:url(../images/default/silk/color_wheel.png) !important; -} /******************************************* - * + * * CalendarList menu styles * ******************************************/ @@ -993,7 +978,7 @@ td.ext-cal-dtitle-today div { outline: 0 none; cursor: pointer; } -.x-calendar-list-menu .x-color-picker a:hover, +.x-calendar-list-menu .x-color-picker a:hover, .x-calendar-list-menu .x-color-picker a.x-color-picker-selected { border-color: #8BB8F3; } @@ -1007,4 +992,4 @@ td.ext-cal-dtitle-today div { height: 14px; width: 14px; line-height: 10px; -} \ No newline at end of file +} diff --git a/src/calendar/CalendarPanel.js b/src/calendar/CalendarPanel.js index 71dfbda0..d5b91434 100644 --- a/src/calendar/CalendarPanel.js +++ b/src/calendar/CalendarPanel.js @@ -729,7 +729,8 @@ Ext.define('Extensible.calendar.CalendarPanel', { }, onWrite: function(store, operation) { - var rec = operation.records[0]; + var records = operation.getRecords(), + rec = records[0]; switch(operation.action) { case 'create': @@ -913,6 +914,10 @@ Ext.define('Extensible.calendar.CalendarPanel', { return this; }, + showDay: function(dt) { + this.setActiveView(this.id+'-day', dt); + }, + showWeek: function(dt) { this.setActiveView(this.id+'-week', dt); }, diff --git a/src/calendar/data/MemoryEventStore.js b/src/calendar/data/MemoryEventStore.js index d646d1d7..a5b0b789 100644 --- a/src/calendar/data/MemoryEventStore.js +++ b/src/calendar/data/MemoryEventStore.js @@ -76,13 +76,13 @@ Ext.define('Extensible.calendar.data.MemoryEventStore', { } this.autoMsg = config.autoMsg; - this.onCreateRecords = Ext.Function.createInterceptor(this.onCreateRecords, this.interceptCreateRecords); + // this.onCreateRecords = Ext.Function.createInterceptor(this.onCreateRecords, this.interceptCreateRecords); this.initRecs(); }, // private - override to make sure that any records added in-memory // still get a unique PK assigned at the data level - interceptCreateRecords: function(records, operation, success) { + /*interceptCreateRecords: function(records, operation, success) { if (success) { var i = 0, rec, @@ -92,7 +92,7 @@ Ext.define('Extensible.calendar.data.MemoryEventStore', { records[i].data[Extensible.calendar.data.EventMappings.EventId.name] = this.idSeed++; } } - }, + },*/ // If the store started with preloaded inline data, we have to make sure the records are set up // properly as valid "saved" records otherwise they may get "added" on initial edit. @@ -109,18 +109,22 @@ Ext.define('Extensible.calendar.data.MemoryEventStore', { if (Extensible.example && Extensible.example.msg) { var success = operation.wasSuccessful(), - rec = operation.records[0], - title = rec.data[Extensible.calendar.data.EventMappings.Title.name]; + rec = operation.getRecords[0], + //var records = 'Ext.data.operation.Destroy' == Ext.getClass(operation).getName()? operation.getResultSet().getRecords() : operation.getRecords(), + title = rec.get(Extensible.calendar.data.EventMappings.Title.name) || '(No title)'; + + + title = record.get(Extensible.calendar.data.EventMappings.Title.mapping) || '(No title)'; switch (operation.action) { case 'create': - Extensible.example.msg('Add', 'Added "' + Ext.value(title, '(No title)') + '"'); + Extensible.example.msg('Add', 'Added "' + title + '"'); break; case 'update': - Extensible.example.msg('Update', 'Updated "' + Ext.value(title, '(No title)') + '"'); + Extensible.example.msg('Update', 'Updated "' + title + '"'); break; case 'destroy': - Extensible.example.msg('Delete', 'Deleted "' + Ext.value(title, '(No title)') + '"'); + Extensible.example.msg('Delete', 'Deleted "' + title + '"'); break; } } diff --git a/src/calendar/gadget/CalendarListMenu.js b/src/calendar/gadget/CalendarListMenu.js index 9f30114c..8b4fa6dc 100644 --- a/src/calendar/gadget/CalendarListMenu.js +++ b/src/calendar/gadget/CalendarListMenu.js @@ -1,74 +1,90 @@ /** * A menu containing a {@link Extensible.calendar.util.ColorPicker color picker} for choosing * calendar colors, as well as other calendar-specific options. - * + * * @private */ Ext.define('Extensible.calendar.gadget.CalendarListMenu', { extend: 'Ext.menu.Menu', alias: 'widget.extensible.calendarlistmenu', - + requires: ['Extensible.calendar.util.ColorPicker'], - + /** * @cfg {Boolean} hideOnClick * False to continue showing the menu after a color is selected, defaults to true. */ hideOnClick: true, + /** * @cfg {Boolean} ignoreParentClicks * True to ignore clicks on any item in this menu that is a parent item (displays a submenu) * so that the submenu is not dismissed when clicking the parent item (defaults to true). */ ignoreParentClicks: true, + /** * @cfg {String} displayOnlyThisCalendarText * The text to display for the 'Display only this calendar' option in the menu. */ displayOnlyThisCalendarText: 'Display only this calendar', + /** * @cfg {Number} calendarId * The id of the calendar to be associated with this menu. This calendarId will be passed * back with any events from this menu to identify the calendar to be acted upon. The calendar * id can also be changed at any time after creation by calling {@link setCalendar}. */ - + /** * @cfg {Boolean} enableScrolling * @hide */ enableScrolling: false, + /** * @cfg {Number} maxHeight * @hide */ + /** * @cfg {Number} scrollIncrement * @hide */ + + /** + * @property palette + * @type ColorPicker + * The {@link Extensible.calendar.util.ColorPicker ColorPicker} instance for this CalendarListMenu + */ + + /** + * @event showcalendar + */ + + /** + * @event hidecalendar + */ + + /** + * @event radiocalendar + */ + + /** + * @event colorchange + */ + /** * @event click * @hide */ + /** * @event itemclick * @hide */ - - /** - * @property palette - * @type ColorPicker - * The {@link Extensible.calendar.util.ColorPicker ColorPicker} instance for this CalendarListMenu - */ - + initComponent: function() { - this.addEvents( - 'showcalendar', - 'hidecalendar', - 'radiocalendar', - 'colorchange' - ); - Ext.apply(this, { plain: true, items: [{ @@ -81,31 +97,31 @@ Ext.define('Extensible.calendar.gadget.CalendarListMenu', { handler: Ext.bind(this.handleColorSelect, this) }] }); - - this.addClass('x-calendar-list-menu'); + + this.addCls('x-calendar-list-menu'); this.callParent(arguments); }, - + afterRender: function() { this.callParent(arguments); - + this.palette = this.down('#' + this.id + '-calendar-color-picker'); - + if(this.colorId) { this.palette.select(this.colorId, true); } }, - + handleRadioCalendarClick: function(e, t) { this.fireEvent('radiocalendar', this, this.calendarId); }, - + handleColorSelect: function(cp, selColorId) { this.fireEvent('colorchange', this, this.calendarId, selColorId, this.colorId); this.colorId = selColorId; this.menuHide(); }, - + /** * Sets the calendar id and color id to be associated with this menu. This should be called each time the * menu is shown relative to a new calendar. @@ -116,7 +132,7 @@ Ext.define('Extensible.calendar.gadget.CalendarListMenu', { setCalendar: function(id, cid) { this.calendarId = id; this.colorId = cid; - + if(this.rendered) { this.palette.select(cid, true); } @@ -128,4 +144,4 @@ Ext.define('Extensible.calendar.gadget.CalendarListMenu', { this.hide(); } } -}); \ No newline at end of file +}); diff --git a/src/calendar/menu/Event.js b/src/calendar/menu/Event.js index 15de3b7c..9f5e8873 100644 --- a/src/calendar/menu/Event.js +++ b/src/calendar/menu/Event.js @@ -4,9 +4,9 @@ Ext.define('Extensible.calendar.menu.Event', { extend: 'Ext.menu.Menu', alias: 'widget.extensible.eventcontextmenu', - + requires: ['Ext.menu.DatePicker'], - + /** * @cfg {Boolean} hideOnClick * False to continue showing the menu after a color is selected, defaults to true. @@ -48,6 +48,57 @@ Ext.define('Extensible.calendar.menu.Event', { * @hide */ enableScrolling: false, + + /** + * @event editdetails + * Fires when the user selects the option to edit the event details + * (by default, in an instance of {@link Extensible.calendar.form.EventDetails}. Handling code should + * transfer the current event record to the appropriate instance of the detailed form by showing + * the form and calling {@link Extensible.calendar.form.EventDetails#loadRecord loadRecord}. + * @param {Extensible.calendar.menu.Event} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} that is currently being edited + * @param {Ext.Element} el The element associated with this context menu + */ + + /** + * @event eventdelete + * Fires after the user selectes the option to delete an event. Note that this menu does not actually + * delete the event from the data store. This is simply a notification that the menu option was + * selected -- it is the responsibility of handling code to perform the deletion and any clean + * up required. + * @param {Extensible.calendar.menu.Event} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} for the event to be deleted + * @param {Ext.Element} el The element associated with this context menu + */ + + /** + * @event eventmove + * Fires after the user selects a date in the calendar picker under the "move event" menu option. + * Note that this menu does not actually update the event in the data store. This is simply a + * notification that the menu option was selected -- it is the responsibility of handling code + * to perform the move action and any clean up required. + * @param {Extensible.calendar.menu.Event} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} for the event to be moved + * @param {Date} dt The new start date for the event (the existing event start time will be preserved) + */ + + /** + * @event eventcopy + * Fires after the user selects a date in the calendar picker under the "copy event" menu option. + * Note that this menu does not actually update the event in the data store. This is simply a + * notification that the menu option was selected -- it is the responsibility of handling code + * to perform the copy action. + * @param {Extensible.calendar.menu.Event} this + * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel + * record} for the event to be copied + * @param {Date} dt The start date for the event copy (the existing event start time will + * be preserved) + */ + + /** * @cfg {Number} maxHeight * @hide @@ -73,69 +124,17 @@ Ext.define('Extensible.calendar.menu.Event', { ownerCalendarPanel: {}, initComponent: function() { - this.addEvents( - /** - * @event editdetails - * Fires when the user selects the option to edit the event details - * (by default, in an instance of {@link Extensible.calendar.form.EventDetails}. Handling code should - * transfer the current event record to the appropriate instance of the detailed form by showing - * the form and calling {@link Extensible.calendar.form.EventDetails#loadRecord loadRecord}. - * @param {Extensible.calendar.menu.Event} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} that is currently being edited - * @param {Ext.Element} el The element associated with this context menu - */ - 'editdetails', - /** - * @event eventdelete - * Fires after the user selectes the option to delete an event. Note that this menu does not actually - * delete the event from the data store. This is simply a notification that the menu option was - * selected -- it is the responsibility of handling code to perform the deletion and any clean - * up required. - * @param {Extensible.calendar.menu.Event} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} for the event to be deleted - * @param {Ext.Element} el The element associated with this context menu - */ - 'eventdelete', - /** - * @event eventmove - * Fires after the user selects a date in the calendar picker under the "move event" menu option. - * Note that this menu does not actually update the event in the data store. This is simply a - * notification that the menu option was selected -- it is the responsibility of handling code - * to perform the move action and any clean up required. - * @param {Extensible.calendar.menu.Event} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} for the event to be moved - * @param {Date} dt The new start date for the event (the existing event start time will be preserved) - */ - 'eventmove', - /** - * @event eventcopy - * Fires after the user selects a date in the calendar picker under the "copy event" menu option. - * Note that this menu does not actually update the event in the data store. This is simply a - * notification that the menu option was selected -- it is the responsibility of handling code - * to perform the copy action. - * @param {Extensible.calendar.menu.Event} this - * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel - * record} for the event to be copied - * @param {Date} dt The start date for the event copy (the existing event start time will - * be preserved) - */ - 'eventcopy' - ); - this.buildMenu(); this.callParent(arguments); }, - + /** * Overrideable method intended for customizing the menu items. This should only to be used for overriding * or called from a subclass and should not be called directly from application code. */ buildMenu: function() { var me = this; - + if(me.rendered) { return; } @@ -149,7 +148,7 @@ Ext.define('Extensible.calendar.menu.Event', { startDay: me.startDay, handler: me.onEventCopySelected }); - + Ext.apply(me, { items: [{ text: me.editDetailsText, @@ -176,22 +175,22 @@ Ext.define('Extensible.calendar.menu.Event', { }] }); }, - + onEventMoveSelected: function(datePicker, selectedDate) { this.doCopyOrMove(selectedDate, 'move'); }, - + onEventCopySelected: function(datePicker, selectedDate) { this.doCopyOrMove(selectedDate, 'copy'); }, - + doCopyOrMove: function(selectedDate, mode) { selectedDate = Extensible.Date.copyTime( this.rec.data[Extensible.calendar.data.EventMappings.StartDate.name], selectedDate); - + this.fireEvent('event' + mode, this, this.rec, selectedDate); }, - + /** * Shows the specified event at the given XY position. * @param {Extensible.calendar.data.EventModel} rec The {@link Extensible.calendar.data.EventModel @@ -203,7 +202,7 @@ Ext.define('Extensible.calendar.menu.Event', { showForEvent: function(rec, el, xy) { var me = this, startDate = rec.data[Extensible.calendar.data.EventMappings.StartDate.name]; - + me.rec = rec; me.ctxEl = el; me.dateMenu.picker.setValue(startDate); @@ -219,4 +218,4 @@ Ext.define('Extensible.calendar.menu.Event', { delete this.ctxEl; this.callParent(arguments); } -}); \ No newline at end of file +}); diff --git a/src/form/recurrence/AbstractOption.js b/src/form/recurrence/AbstractOption.js index 7bcdaf2a..71ef7c31 100644 --- a/src/form/recurrence/AbstractOption.js +++ b/src/form/recurrence/AbstractOption.js @@ -1,30 +1,30 @@ /** * The abstract base class for all of the recurrence option widgets. Intended to be subclassed. - * + * * @private */ Ext.define('Extensible.form.recurrence.AbstractOption', { - + // TODO: Create Extensible.form.recurrence.Parser and factor all // rrule value getting/setting out of these option classes // and into the parser. - + extend: 'Ext.form.FieldContainer', - + requires: [ 'Extensible.form.recurrence.Rule' ], - + mixins: { field: 'Ext.form.field.Field' }, - + layout: 'hbox', - + defaults: { margins: '0 5 0 0' }, - + /** * @cfg {Extensible.form.recurrence.Rule} rrule * The {@link Extensible.form.recurrence.Rule recurrence Rule} instance underlying this recurrence @@ -32,6 +32,7 @@ Ext.define('Extensible.form.recurrence.AbstractOption', { * so that the same instance is shared across option widgets. */ rrule: undefined, + /** * @cfg {Date} startDate * The start date of the underlying recurrence series. This is not always required, depending on the specific @@ -39,82 +40,83 @@ Ext.define('Extensible.form.recurrence.AbstractOption', { * {@link #rrule} config, this is typically set by the parent {@link Extensible.form.recurrence.Fieldset fieldset}. */ startDate: undefined, + /** * @cfg {Number} startDay * The 0-based index for the day on which the calendar week begins (0=Sunday, which is the default). * Used anytime a calendar or date picker is displayed within the recurrence options. */ startDay: 0, + /** * Maximum end date allowed when choosing dates from date fields (defaults to 12/31/9999). */ maxEndDate: new Date('12/31/9999'), - + + /** + * @event change + * Fires when a user-initiated change is detected in the value of the field. + * @param {Extensible.form.recurrence.AbstractOption} this + * @param {Mixed} newValue The new value + * @param {Mixed} oldValue The old value + */ + + // private key: undefined, - + + // private optionDelimiter: ';', //TODO: remove - + initComponent: function() { var me = this; - - me.addEvents( - /** - * @event change - * Fires when a user-initiated change is detected in the value of the field. - * @param {Extensible.form.recurrence.AbstractOption} this - * @param {Mixed} newValue The new value - * @param {Mixed} oldValue The old value - */ - 'change' - ); - + me.initRRule(); me.items = me.getItemConfigs(); - + me.callParent(arguments); - + me.initRefs(); me.initField(); }, - + initRRule: function() { var me = this; - + me.rrule = me.rrule || Ext.create('Extensible.form.recurrence.Rule'); me.startDate = me.startDate || me.rrule.startDate || Extensible.Date.today(); - + if (!me.rrule.startDate) { me.rrule.setStartDate(me.startDate); } }, - + afterRender: function() { this.callParent(arguments); this.updateLabel(); }, - + initRefs: Ext.emptyFn, - + setFrequency: function(freq) { this.frequency = freq; }, - + setStartDate: function(dt) { this.startDate = dt; return this; }, - + getStartDate: function() { return this.startDate || Extensible.Date.today(); }, - + getDefaultValue: function() { return ''; }, - + preSetValue: function(v, readyField) { var me = this; - + if (!v) { v = me.getDefaultValue(); } @@ -124,9 +126,9 @@ Ext.define('Extensible.form.recurrence.AbstractOption', { }, me, {single: true}); return false; } - + me.value = v; - + return true; } -}); \ No newline at end of file +}); diff --git a/src/form/recurrence/Fieldset.js b/src/form/recurrence/Fieldset.js index 03e80c42..21f513a1 100644 --- a/src/form/recurrence/Fieldset.js +++ b/src/form/recurrence/Fieldset.js @@ -6,11 +6,11 @@ Ext.define('Extensible.form.recurrence.Fieldset', { extend: 'Ext.form.FieldContainer', alias: 'widget.extensible.recurrencefield', - + mixins: { field: 'Ext.form.field.Field' }, - + requires: [ 'Ext.form.Label', 'Extensible.form.recurrence.Rule', @@ -42,57 +42,54 @@ Ext.define('Extensible.form.recurrence.Fieldset', { */ startDay: 0, + /** + * @event startchange + * Fires when the start date of the recurrence series is changed + * @param {Extensible.form.recurrence.option.Interval} this + * @param {Date} newDate The new start date + * @param {Date} oldDate The previous start date + */ + //TODO: implement code to use this config. // Maybe use xtypes instead for dynamic loading of custom options? // Include secondly/minutely/hourly, plugins for M-W-F, T-Th, weekends options: [ 'daily', 'weekly', 'weekdays', 'monthly', 'yearly' ], - + //TODO: implement displayStyle: 'field', // or 'dialog' - + fieldLabel: 'Repeats', fieldContainerWidth: 400, - + //enableFx: true, monitorChanges: true, cls: 'extensible-recur-field', - + frequencyWidth: null, // defaults to the anchor value - + layout: 'anchor', defaults: { anchor: '100%' }, - + initComponent: function() { var me = this; - + if (!me.height || me.displayStyle === 'field') { delete me.height; me.autoHeight = true; } - - this.addEvents( - /** - * @event startchange - * Fires when the start date of the recurrence series is changed - * @param {Extensible.form.recurrence.option.Interval} this - * @param {Date} newDate The new start date - * @param {Date} oldDate The previous start date - */ - 'startchange' - ); - + me.initRRule(); - + me.items = [{ xtype: 'extensible.recurrence-frequency', hideLabel: true, width: this.frequencyWidth, itemId: this.id + '-frequency', - + listeners: { 'frequencychange': { fn: this.onFrequencyChange, @@ -108,7 +105,7 @@ Ext.define('Extensible.form.recurrence.Fieldset', { hideMode: 'offsets', hidden: true, width: this.fieldContainerWidth, - + defaults: { hidden: true, rrule: me.rrule @@ -132,32 +129,32 @@ Ext.define('Extensible.form.recurrence.Fieldset', { startDay: this.startDay }] }]; - + me.callParent(arguments); - + me.initField(); }, - + initRRule: function() { var me = this; - + me.rrule = me.rrule || Ext.create('Extensible.form.recurrence.Rule'); me.startDate = me.startDate || me.rrule.startDate || Extensible.Date.today(); - + if (!me.rrule.startDate) { me.rrule.setStartDate(me.startDate); } }, - + afterRender: function() { this.callParent(arguments); this.initRefs(); }, - + initRefs: function() { var me = this, id = me.id; - + me.innerContainer = me.down('#' + id + '-inner-ct'); me.frequencyCombo = me.down('#' + id + '-frequency'); me.intervalField = me.down('#' + id + '-interval'); @@ -165,30 +162,30 @@ Ext.define('Extensible.form.recurrence.Fieldset', { me.monthlyField = me.down('#' + id + '-monthly'); me.yearlyField = me.down('#' + id + '-yearly'); me.durationField = me.down('#' + id + '-duration'); - + me.initChangeEvents(); }, - + initChangeEvents: function() { var me = this; - + me.intervalField.on('startchange', me.onStartDateChange, me); - + me.intervalField.on('change', me.onChange, me); me.weeklyField.on('change', me.onChange, me); me.monthlyField.on('change', me.onChange, me); me.yearlyField.on('change', me.onChange, me); me.durationField.on('change', me.onChange, me); }, - + onStartDateChange: function(interval, newDate, oldDate) { this.fireEvent('startchange', this, newDate, oldDate); }, - + onChange: function() { this.fireEvent('change', this, this.getValue()); }, - + onFrequencyChange: function(freq) { this.setFrequency(freq); this.onChange(); @@ -201,9 +198,9 @@ Ext.define('Extensible.form.recurrence.Fieldset', { // Set the initial value - prevent validation on initial set me.suspendCheckChange++; - + me.setStartDate(me.startDate); - + if (me.value !== undefined) { me.setValue(me.value); } @@ -214,11 +211,11 @@ Ext.define('Extensible.form.recurrence.Fieldset', { me.setValue(''); } me.suspendCheckChange--; - + Ext.defer(me.doLayout, 1, me); me.onChange(); }, - + /** * Sets the start date of the recurrence pattern * @param {Date} The new start date @@ -226,9 +223,9 @@ Ext.define('Extensible.form.recurrence.Fieldset', { */ setStartDate: function(dt) { var me = this; - + me.startDate = dt; - + if (me.innerContainer) { me.innerContainer.items.each(function(item) { if (item.setStartDate) { @@ -243,7 +240,7 @@ Ext.define('Extensible.form.recurrence.Fieldset', { } return me; }, - + /** * Returns the start date of the recurrence pattern (defaults to the current date * if not explicitly set via {@link #setStartDate} or the constructor). @@ -252,14 +249,14 @@ Ext.define('Extensible.form.recurrence.Fieldset', { getStartDate: function() { return this.startDate; }, - + /** * Return true if the fieldset currently has a recurrence value set, otherwise returns false. */ isRecurring: function() { return this.getValue() !== ''; }, - + getValue: function() { if (!this.innerContainer) { return this.value; @@ -267,17 +264,17 @@ Ext.define('Extensible.form.recurrence.Fieldset', { if (this.frequency === 'NONE') { return ''; } - + var values, itemValue; - + if (this.frequency === 'WEEKDAYS') { values = ['FREQ=WEEKLY','BYDAY=MO,TU,WE,TH,FR']; } else { values = ['FREQ=' + this.frequency]; } - + this.innerContainer.items.each(function(item) { if(item.isVisible() && item.getValue) { itemValue = item.getValue(); @@ -286,10 +283,10 @@ Ext.define('Extensible.form.recurrence.Fieldset', { } } }, this); - + return values.length > 1 ? values.join(';') : values[0]; }, - + includeItemValue: function(value) { if (value) { if (value === 'INTERVAL=1') { @@ -305,17 +302,17 @@ Ext.define('Extensible.form.recurrence.Fieldset', { } return false; }, - + getDescription: function() { // TODO: Should not have to set value here return this.rrule.setRule(this.getValue()).getDescription(); }, - + setValue: function(value) { var me = this; - + me.value = (!value || value === 'NONE' ? '' : value); - + if (!me.frequencyCombo || !me.innerContainer) { me.on('afterrender', function() { me.setValue(value); @@ -326,7 +323,7 @@ Ext.define('Extensible.form.recurrence.Fieldset', { } var parts = me.value.split(';'); - + if (me.value === '') { me.setFrequency('NONE'); } @@ -340,27 +337,27 @@ Ext.define('Extensible.form.recurrence.Fieldset', { } }, me); } - + me.innerContainer.items.each(function(item) { if (item.setValue) { item.setValue(me.value); } }); - + me.checkChange(); - + return me; }, - + setFrequency: function(freq) { var me = this; - + me.frequency = freq; - + if (me.frequencyCombo) { me.frequencyCombo.setValue(freq); me.showOptions(freq); - + this.innerContainer.items.each(function(item) { item.setFrequency(freq); }); @@ -373,11 +370,11 @@ Ext.define('Extensible.form.recurrence.Fieldset', { } return me; }, - + showOptions: function(freq) { var me = this, unit = 'day'; - + if (freq === 'NONE') { // me.innerContainer.items.each(function(item) { // item.hide(); @@ -389,33 +386,33 @@ Ext.define('Extensible.form.recurrence.Fieldset', { me.durationField.show(); me.innerContainer.show(); } - + switch(freq) { case 'DAILY': case 'WEEKDAYS': me.weeklyField.hide(); me.monthlyField.hide(); me.yearlyField.hide(); - + if (freq === 'WEEKDAYS') { unit = 'week'; } break; - + case 'WEEKLY': me.weeklyField.show(); me.monthlyField.hide(); me.yearlyField.hide(); unit = 'week'; break; - + case 'MONTHLY': me.monthlyField.show(); me.weeklyField.hide(); me.yearlyField.hide(); unit = 'month'; break; - + case 'YEARLY': me.yearlyField.show(); me.weeklyField.hide(); @@ -426,4 +423,4 @@ Ext.define('Extensible.form.recurrence.Fieldset', { me.intervalField.updateLabel(unit); } -}); \ No newline at end of file +}); diff --git a/src/form/recurrence/FrequencyCombo.js b/src/form/recurrence/FrequencyCombo.js index b8ee7b01..c668a468 100644 --- a/src/form/recurrence/FrequencyCombo.js +++ b/src/form/recurrence/FrequencyCombo.js @@ -6,12 +6,12 @@ Ext.define('Extensible.form.recurrence.FrequencyCombo', { extend: 'Ext.form.field.ComboBox', alias: 'widget.extensible.recurrence-frequency', - + requires: [ 'Ext.data.ArrayStore', 'Extensible.form.recurrence.Parser' ], - + fieldLabel: 'Repeats', queryMode: 'local', triggerAction: 'all', @@ -19,21 +19,19 @@ Ext.define('Extensible.form.recurrence.FrequencyCombo', { displayField: 'pattern', valueField: 'id', cls: 'extensible-recur-frequency', - + + /** + * @event frequencychange + * Fires when a frequency list item is selected. + * @param {Extensible.form.recurrence.Combo} combo This combo box + * @param {String} value The selected frequency value (one of the names + * from {@link #frequencyOptions}, e.g. 'DAILY') + */ + initComponent: function() { - var me = this; - - /** - * @event frequencychange - * Fires when a frequency list item is selected. - * @param {Extensible.form.recurrence.Combo} combo This combo box - * @param {String} value The selected frequency value (one of the names - * from {@link #frequencyOptions}, e.g. 'DAILY') - */ - me.addEvents('frequencychange'); - - var freq = Extensible.form.recurrence.Parser.strings.frequency; - + var me = this, + freq = Extensible.form.recurrence.Parser.strings.frequency; + /** * @cfg {Array} frequencyOptions * An array of arrays, each containing the name/value pair that defines a recurring @@ -59,19 +57,19 @@ Ext.define('Extensible.form.recurrence.FrequencyCombo', { ['MONTHLY', freq.monthly], ['YEARLY', freq.yearly] ]; - + me.store = me.store || Ext.create('Ext.data.ArrayStore', { fields: ['id', 'pattern'], idIndex: 0, data: me.frequencyOptions }); - + me.on('select', me.onSelect, me); - + me.callParent(arguments); }, - + onSelect: function(combo, records) { this.fireEvent('frequencychange', records[0].data.id); } -}); \ No newline at end of file +}); diff --git a/src/form/recurrence/option/Interval.js b/src/form/recurrence/option/Interval.js index 4c364637..6f28feec 100644 --- a/src/form/recurrence/option/Interval.js +++ b/src/form/recurrence/option/Interval.js @@ -4,13 +4,13 @@ Ext.define('Extensible.form.recurrence.option.Interval', { extend: 'Extensible.form.recurrence.AbstractOption', alias: 'widget.extensible.recurrence-interval', - + dateLabelFormat: 'l, F j', unit: 'day', minValue: 1, maxValue: 999, startDateWidth: 120, - + strings: { repeatEvery: 'Repeat every', beginning: 'beginning', @@ -23,23 +23,17 @@ Ext.define('Extensible.form.recurrence.option.Interval', { year: 'year', years: 'years' }, - + cls: 'extensible-recur-interval', - - initComponent: function() { - this.addEvents( - /** - * @event startchange - * Fires when the start date of the recurrence series is changed - * @param {Extensible.form.recurrence.option.Interval} this - * @param {Date} newDate The new start date - * @param {Date} oldDate The previous start date - */ - 'startchange' - ); - this.callParent(arguments); - }, - + + /** + * @event startchange + * Fires when the start date of the recurrence series is changed + * @param {Extensible.form.recurrence.option.Interval} this + * @param {Date} newDate The new start date + * @param {Date} oldDate The previous start date + */ + getItemConfigs: function() { return [ this.getRepeatEveryLabelConfig(), @@ -48,17 +42,17 @@ Ext.define('Extensible.form.recurrence.option.Interval', { this.getBeginDateFieldConfig() ]; }, - + getRepeatEveryLabelConfig: function() { return { xtype: 'label', text: this.strings.repeatEvery }; }, - + getIntervalComboConfig: function() { var me = this; - + return { xtype: 'numberfield', itemId: me.id + '-interval', @@ -73,18 +67,18 @@ Ext.define('Extensible.form.recurrence.option.Interval', { } }; }, - + getBeginDateLabelConfig: function() { return { xtype: 'label', itemId: this.id + '-date-label' }; }, - + getBeginDateFieldConfig: function() { var me = this, startDate = me.getStartDate(); - + return { xtype: 'datefield', itemId: me.id + '-start-date', @@ -94,40 +88,40 @@ Ext.define('Extensible.form.recurrence.option.Interval', { maxValue: me.maxEndDate, allowBlank: false, value: startDate, - + listeners: { 'change': Ext.bind(me.onStartDateChange, me) } }; }, - + initRefs: function() { var me = this; me.intervalField = me.down('#' + me.id + '-interval'); me.dateLabel = me.down('#' + me.id + '-date-label'); me.startDateField = me.down('#' + me.id + '-start-date'); }, - + onIntervalChange: function(field, value, oldValue) { this.checkChange(); this.updateLabel(); }, - + onStartDateChange: function(field, value, oldValue) { this.checkChange(); this.fireEvent('startchange', this, value, oldValue); }, - + getValue: function() { if (this.intervalField) { return 'INTERVAL=' + this.intervalField.getValue(); } return ''; }, - + setValue: function(v) { var me = this; - + if (!me.preSetValue(v, me.intervalField)) { return me; } @@ -140,37 +134,37 @@ Ext.define('Extensible.form.recurrence.option.Interval', { Ext.each(options, function(option) { parts = option.split('='); - + if (parts[0] === 'INTERVAL') { me.intervalField.setValue(parts[1]); me.updateLabel(); return; } }, me); - + return me; }, - + setStartDate: function(dt) { this.startDate = dt; this.startDateField.setValue(dt); return this; }, - + setUnit: function(unit) { this.unit = unit; this.updateLabel(); return this; }, - + updateLabel: function(unit) { var me = this; - + if (me.intervalField) { // TODO: Change this to support locale text var s = me.intervalField.getValue() === 1 ? '' : 's'; me.unit = unit ? unit.toLowerCase() : me.unit || 'day'; - + if (me.dateLabel) { me.dateLabel.update(me.strings[me.unit + s] + ' ' + me.strings.beginning); } From df677703b6e615cc54d404f8edd1e3e3bf4d0f09 Mon Sep 17 00:00:00 2001 From: Brian Moeskau Date: Mon, 18 Apr 2016 00:41:06 -0500 Subject: [PATCH 4/5] More fixes --- src/calendar/CalendarPanel.js | 6 +-- src/calendar/view/AbstractCalendar.js | 61 +++++++++++++++++---------- src/calendar/view/DayBody.js | 4 +- src/calendar/view/MonthDayDetail.js | 4 ++ src/data/Model.js | 2 +- src/form/recurrence/FrequencyCombo.js | 6 +-- src/form/recurrence/option/Weekly.js | 40 +++++++++--------- 7 files changed, 71 insertions(+), 52 deletions(-) diff --git a/src/calendar/CalendarPanel.js b/src/calendar/CalendarPanel.js index d5b91434..f1c38944 100644 --- a/src/calendar/CalendarPanel.js +++ b/src/calendar/CalendarPanel.js @@ -835,7 +835,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { toolbar[id === editViewId ? 'hide' : 'show'](); } - Ext.suspendLayouts(); + // Ext.suspendLayouts(); // Activate the new view and refresh the layout layout.setActiveItem(id || me.activeItem); @@ -844,7 +844,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { if (id !== editViewId) { if (id && id !== me.preEditView) { // We're changing to a different view, so the view dates are likely different. - // Re-set the start date so that the view range will be updated if needed. + // Reset the start date so that the view range will be updated if needed. // If id is undefined, it means this is the initial pass after render so we can // skip this (as we don't want to cause a duplicate forced reload). layout.activeItem.setStartDate(me.startDate, true); @@ -855,7 +855,7 @@ Ext.define('Extensible.calendar.CalendarPanel', { } // Notify any listeners that the view changed - Ext.resumeLayouts(true); + // Ext.resumeLayouts(true); me.fireViewChange(); } }, diff --git a/src/calendar/view/AbstractCalendar.js b/src/calendar/view/AbstractCalendar.js index eca010eb..665adb42 100644 --- a/src/calendar/view/AbstractCalendar.js +++ b/src/calendar/view/AbstractCalendar.js @@ -993,9 +993,17 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { // edited or was recurring before being edited AND an event store reload has not been triggered already for // this operation. If an event is not currently recurring (isRecurring = false) but still has an instance // start date set, then it must have been recurring and edited to no longer recur. - var RInstanceStartDate = Extensible.calendar.data.EventMappings.RInstanceStartDate, - isInstance = RInstanceStartDate && !!operation.records[0].get(RInstanceStartDate.name), - reload = (operation.records[0].isRecurring() || isInstance) && !operation.wasStoreReloadTriggered; + + // var RInstanceStartDate = Extensible.calendar.data.EventMappings.RInstanceStartDate, + // isInstance = RInstanceStartDate && !!operation.records[0].get(RInstanceStartDate.name), + // reload = (operation.records[0].isRecurring() || isInstance) && !operation.wasStoreReloadTriggered; + + var records = 'Ext.data.operation.Destroy' == Ext.getClass(operation).getName() ? + operation.getResultSet().getRecords() : operation.getRecords(), + record = records[0], + RInstanceStartDate = Extensible.calendar.data.EventMappings.RInstanceStartDate, + isInstance = RInstanceStartDate && !!record.get(RInstanceStartDate.name), + reload = isInstance && !operation.wasStoreReloadTriggered; if (reload) { // For calendar views with a body and a header component (e.g. weekly view, day view), this function is @@ -1018,7 +1026,8 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { this.refreshAfterEventChange('update', operation); - var rec = operation.records[0]; + var records = operation.getRecords(), + rec = records[0]; if (this.enableFx && this.enableUpdateFx) { this.doUpdateFx(this.getEventEls(rec.data[Extensible.calendar.data.EventMappings.EventId.name]), { @@ -1043,7 +1052,8 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { }, onAdd: function(store, operation) { - var rec = operation.records[0]; + var records = operation.getRecords(), + rec = records[0]; if (this.hidden === true || this.ownerCt.hidden === true || this.monitorStoreEvents === false) { // Hidden calendar view don't need to be refreshed. For views composed of header and body (for example @@ -1095,18 +1105,21 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { Extensible.log('onRemove'); this.dismissEventEditor(); - var rec = operation.records[0]; + if (operation.getResultSet()) { + var records = operation.getResultSet().getRecords(), + rec = records[0]; - if (this.enableFx && this.enableRemoveFx) { - this.doRemoveFx(this.getEventEls(rec.data[Extensible.calendar.data.EventMappings.EventId.name]), { - remove: true, - scope: this, - callback: Ext.bind(this.refreshAfterEventChange, this, ['delete', operation]) - }); - } - else { - this.getEventEls(rec.data[Extensible.calendar.data.EventMappings.EventId.name]).remove(); - this.refreshAfterEventChange('delete', operation); + if (this.enableFx && this.enableRemoveFx) { + this.doRemoveFx(this.getEventEls(rec.data[Extensible.calendar.data.EventMappings.EventId.name]), { + remove: true, + scope: this, + callback: Ext.bind(this.refreshAfterEventChange, this, ['delete', operation]) + }); + } + else { + this.getEventEls(rec.data[Extensible.calendar.data.EventMappings.EventId.name]).remove(); + this.refreshAfterEventChange('delete', operation); + } } }, @@ -1674,13 +1687,15 @@ Ext.define('Extensible.calendar.view.AbstractCalendar', { }, getEventRecord: function(id) { - var idx = this.store.find(Extensible.calendar.data.EventMappings.EventId.name, id, - 0, // start index - false, // match any part of string - true, // case sensitive - true // force exact match - ); - return this.store.getAt(idx); + // var idx = this.store.find(Extensible.calendar.data.EventMappings.EventId.name, id, + // 0, // start index + // false, // match any part of string + // true, // case sensitive + // true // force exact match + // ); + // return this.store.getAt(idx); + + return this.store.getById(id); }, getEventRecordFromEl: function(el) { diff --git a/src/calendar/view/DayBody.js b/src/calendar/view/DayBody.js index da742430..ae67aef1 100644 --- a/src/calendar/view/DayBody.js +++ b/src/calendar/view/DayBody.js @@ -407,7 +407,8 @@ Ext.define('Extensible.calendar.view.DayBody', { renderItems: function() { var day = 0, evt, - evts = []; + evts = [], + M = Extensible.calendar.data.EventMappings; for (; day < this.dayCount; day++) { var ev = 0, @@ -422,7 +423,6 @@ Ext.define('Extensible.calendar.view.DayBody', { continue; } var item = evt.data || evt.event.data, - M = Extensible.calendar.data.EventMappings, ad = item[M.IsAllDay.name] === true, span = this.isEventSpanning(evt.event || evt), renderAsAllDay = ad || span; diff --git a/src/calendar/view/MonthDayDetail.js b/src/calendar/view/MonthDayDetail.js index a392ac2c..cb04ad24 100644 --- a/src/calendar/view/MonthDayDetail.js +++ b/src/calendar/view/MonthDayDetail.js @@ -13,6 +13,10 @@ Ext.define('Extensible.calendar.view.MonthDayDetail', { 'Extensible.calendar.view.AbstractCalendar' ], + /** + * @event eventsrendered + */ + afterRender: function() { this.tpl = this.getTemplate(); diff --git a/src/data/Model.js b/src/data/Model.js index e010d45b..2ff75d4d 100644 --- a/src/data/Model.js +++ b/src/data/Model.js @@ -59,7 +59,7 @@ Ext.define('Extensible.data.Model', { */ clone: function(preserveId) { var copy = Ext.create(this.$className), - dataProp = this.persistenceProperty; + dataProp = this.persistenceProperty || 'data'; copy[dataProp] = Ext.Object.merge({}, this[dataProp]); diff --git a/src/form/recurrence/FrequencyCombo.js b/src/form/recurrence/FrequencyCombo.js index c668a468..c7b4c8e9 100644 --- a/src/form/recurrence/FrequencyCombo.js +++ b/src/form/recurrence/FrequencyCombo.js @@ -30,7 +30,7 @@ Ext.define('Extensible.form.recurrence.FrequencyCombo', { initComponent: function() { var me = this, - freq = Extensible.form.recurrence.Parser.strings.frequency; + freq = Extensible.form.recurrence.Parser.config.strings.frequency; /** * @cfg {Array} frequencyOptions @@ -69,7 +69,7 @@ Ext.define('Extensible.form.recurrence.FrequencyCombo', { me.callParent(arguments); }, - onSelect: function(combo, records) { - this.fireEvent('frequencychange', records[0].data.id); + onSelect: function(combo, record) { + this.fireEvent('frequencychange', record.data.id); } }); diff --git a/src/form/recurrence/option/Weekly.js b/src/form/recurrence/option/Weekly.js index 73ab7587..daf715fa 100644 --- a/src/form/recurrence/option/Weekly.js +++ b/src/form/recurrence/option/Weekly.js @@ -4,7 +4,7 @@ Ext.define('Extensible.form.recurrence.option.Weekly', { extend: 'Extensible.form.recurrence.AbstractOption', alias: 'widget.extensible.recurrence-weekly', - + requires: [ 'Ext.form.field.Checkbox', // should be required by CheckboxGroup but isn't 'Ext.form.CheckboxGroup', @@ -18,7 +18,7 @@ Ext.define('Extensible.form.recurrence.option.Weekly', { startDay: 0, dayValueDelimiter: ',', - + cls: 'extensible-recur-weekly', strings: { @@ -41,7 +41,7 @@ Ext.define('Extensible.form.recurrence.option.Weekly', { */ getCheckboxGroupItems: function() { var weekdaysId = Extensible.form.recurrence.Parser.byDayNames, - weekdaysText = Extensible.form.recurrence.Parser.strings.dayNamesShortByIndex, + weekdaysText = Extensible.form.recurrence.Parser.config.strings.dayNamesShortByIndex, checkboxArray = [], i = this.startDay; @@ -69,48 +69,48 @@ Ext.define('Extensible.form.recurrence.option.Weekly', { } }]; }, - + initValue: function() { this.callParent(arguments); - + if (!this.value) { this.selectByDate(); } }, - + initRefs: function() { this.daysCheckboxGroup = this.down('#' + this.id + '-days'); }, - + onSelectionChange: function(field, value, oldValue) { this.checkChange(); this.updateLabel(); }, - + selectByDate: function(dt) { var day = Ext.Date.format(dt || this.getStartDate(), 'D').substring(0,2).toUpperCase(); this.setValue('BYDAY=' + day); }, - + clearValue: function() { this.value = undefined; - + if (this.daysCheckboxGroup) { this.daysCheckboxGroup.setValue({ SU:0, MO:0, TU:0, WE:0, TH:0, FR:0, SA:0 }); } }, - + getValue: function() { var me = this; - + if (me.daysCheckboxGroup) { // Checkbox group value will look like {MON:"on", TUE:"on", FRI:"on"} var fieldValue = me.daysCheckboxGroup.getValue(), days = [], property; - + for (property in fieldValue) { if (fieldValue.hasOwnProperty(property)) { // Push the name ('MON') not the value ('on') @@ -121,10 +121,10 @@ Ext.define('Extensible.form.recurrence.option.Weekly', { } return ''; }, - + setValue: function(v) { var me = this; - + if (!me.preSetValue(v, me.daysCheckboxGroup)) { return me; } @@ -139,19 +139,19 @@ Ext.define('Extensible.form.recurrence.option.Weekly', { Ext.each(options, function(option) { parts = option.split('='); - + if (parts[0] === 'BYDAY') { days = parts[1].split(me.dayValueDelimiter); - + Ext.each(days, function(day) { compositeValue[day] = true; }, me); - + me.daysCheckboxGroup.setValue(compositeValue); return; } }, me); - + return me; } -}); \ No newline at end of file +}); From 5833e98165ad7feb676ab5bcc6a216604311cd94 Mon Sep 17 00:00:00 2001 From: Brian Moeskau Date: Mon, 18 Apr 2016 00:50:07 -0500 Subject: [PATCH 5/5] Fix config.strings refs --- src/form/recurrence/Rule.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/form/recurrence/Rule.js b/src/form/recurrence/Rule.js index f6d2b89d..d2e196aa 100644 --- a/src/form/recurrence/Rule.js +++ b/src/form/recurrence/Rule.js @@ -519,7 +519,7 @@ Ext.define('Extensible.form.recurrence.Rule', { */ getDescriptionDaily: function(desc, startDate) { var me = this, - strings = me.strings; + strings = me.config.strings; if (me.interval === 1) { // E.g. Daily @@ -542,7 +542,7 @@ Ext.define('Extensible.form.recurrence.Rule', { */ getDescriptionWeekly: function(desc, startDate) { var me = this, - strings = me.strings; + strings = me.config.strings; if (me.interval === 1) { // E.g. Weekly @@ -594,11 +594,11 @@ Ext.define('Extensible.form.recurrence.Rule', { */ getDescriptionWeekdays: function(desc, startDate) { if (this.interval === 1) { - desc.push(this.strings.frequency.weekdays); + desc.push(this.config.strings.frequency.weekdays); } else { // E.g. Every two weekdays - desc.push(this.strings.every, ' ', this.interval, ' ', this.strings.weekdays); + desc.push(this.config.strings.every, ' ', this.interval, ' ', this.config.strings.weekdays); } }, @@ -613,7 +613,7 @@ Ext.define('Extensible.form.recurrence.Rule', { */ getDescriptionMonthly: function(desc, startDate) { var me = this, - strings = me.strings; + strings = me.config.strings; if (me.interval === 1) { // E.g. Monthly @@ -656,7 +656,7 @@ Ext.define('Extensible.form.recurrence.Rule', { */ getDescriptionYearly: function(desc, startDate) { var me = this, - strings = me.strings; + strings = me.config.strings; if (me.interval === 1) { // E.g. Yearly @@ -708,7 +708,7 @@ Ext.define('Extensible.form.recurrence.Rule', { getDescriptionCount: function(desc, startDate) { if (this.count) { // E.g. Daily, 5 times - desc.push(', ', this.count, ' ', (this.count === 1 ? this.strings.time : this.strings.times)); + desc.push(', ', this.count, ' ', (this.count === 1 ? this.config.strings.time : this.config.strings.times)); } }, @@ -724,7 +724,7 @@ Ext.define('Extensible.form.recurrence.Rule', { getDescriptionUntil: function(desc, startDate) { if (this.until) { // E.g. Daily, until December 31, 2012 - desc.push(', ', this.strings.until, ' ', Ext.Date.format(this.until, this.strings.untilFormat)); + desc.push(', ', this.config.strings.until, ' ', Ext.Date.format(this.until, this.config.strings.untilFormat)); } } });