/** * The default implementation for am event model. All fields are accessed via the * getter/setter API to allow for custom model implementations. * * ## Fields ## * * The following fields are provided: * * - id : {Number} - The unique id for the calendar event record * - title : {String} - The title to display for the event. Maps to * {@link #method-getTitle} and {@link #method-setTitle}. * - calendarId : {Object} - The id of the parent source calendar. Maps to * {@link #method-getCalendarId} and {@link #method-setCalendarId}. * - description : {String} - The description to display for the event. Maps to * {@link #method-getDescription} and {@link #method-setDescription}. * - startDate : {Date} - The event's start date and time (in UTC format). Maps to * {@link #method-getStartDate} and {@link #method-setStartDate}. * - endDate : {Date} - The event's end date and time (in UTC format). Maps to * {@link #method-getEndDate} and {@link #method-setEndDate}. * - allDay : {Boolean} - A flag indicating that the event is all day. Maps to * {@link #method-getAllDay} and {@link #method-setAllDay}. * - duration : {Number} - The duration of the event. Maps to * {@link #method-getDuration} and {@link #method-setDuration}. * * Events read / write the time stamp in UTC format. The time zone should be GMT. The * timezone offset for the local computer is used when rendering the event on the * calendar view. A different timezone offset can be specified using the view's * {@link Ext.calendar.view.Base#cfg-timezoneOffset timezoneOffset} config option. * * ### Sample Response * * Below is a sample response from a remote source providing a single event for a source * calendar with an id of 1: * * [{ * "id": 1001, * "calendarId": 1, * "startDate": "2016-09-30T21:30:00.000Z", * "endDate": "2016-09-30T22:30:00.000Z", * "title": "Watch cartoons", * "description": "Catch up with adventurers Finn and Jake" * }] * * Sample response for the same source calendar with an all day event on Sept. 30th 2016 * * [{ * "id": 1001, * "calendarId": 1, * "startDate": "2016-09-30T00:00:00.000Z", * "endDate": "2016-10-01T00:00:00.000Z", * "allDay": true, * "title": "Netflix Binge", * "description": "Watch Luke Cage. Maybe twice." * }] * * **Note:** The "id"s for all events must be unique within a calendar store across all * event stores. Duplicate "id"s even across event stores may result in unintended * consequences. * * ### Custom Data * * While the Event model fields may not be set on a user-defined model, custom data can * easily be accommodated by extending the Event model and modifying the associated * getter / setter methods. * * For example, let's assume your events server provides the `description` as "desc". * The response from the server would look like: * * [{ * "id": 1001, * "calendarId": 1, * "startDate": "2016-09-30T21:30:00.000Z", * "endDate": "2016-09-30T22:30:00.000Z", * "title": "Demo starter app", * "desc": "Demonstrate the starter app to project management" * }] * * Internally what is used to read and write the description is `getDescription` and * `setDescription`. By default those will be looking for the description string to be * on the `description` field. To have our model work with the `desc` data instead the * derived model would look like: * * Ext.define('MyApp.model.Event', { * extend: 'Ext.calendar.model.Event', * * getDescription: function () { * return this.data.desc; * }, * setDescription: function (description) { * this.set('desc', description); * } * }); * * The model can then be specified on the Events store config: * * Ext.create({ * xtype: 'calendar', * renderTo: Ext.getBody(), * height: 400, * width: 600, * store: { * autoLoad: true, * proxy: { * type: 'ajax', * url: 'calendars.php' * }, * eventStoreDefaults: { * model: 'MyApp.model.Event', * proxy: { * type: 'ajax', * url: 'events.php' * } * } * } * }); * * The calendar makes no assumptions about the structure of the data provided, only that * it exists. This abstraction of data access ensures flexibility for a wide range of * data structures to be used. * * As an example of this concept, the default Event model has a `startDate` and `endDate` * field. The {@link #method-getDuration} method is calculated based on these values. * Another possible implementation could be to have a `startDate` and `duration` field on * the model and have the `getEndDate` be a calculated quantity. The API makes no * distinction here, as long as the EventBase interface is fulfilled. */Ext.define('Ext.calendar.model.Event', { extend: 'Ext.data.Model', mixins: ['Ext.calendar.model.EventBase'], requires: [ 'Ext.data.field.String', 'Ext.data.field.Integer', 'Ext.data.field.Date', 'Ext.data.field.Boolean' ], fields: [{ name: 'title', type: 'string' }, { name: 'calendarId' }, { name: 'color', type: 'string' }, { name: 'description', type: 'string' }, { name: 'startDate', type: 'date', dateFormat: 'c' }, { name: 'endDate', type: 'date', dateFormat: 'c' }, { name: 'allDay', type: 'boolean' }, { name: 'duration', type: 'int', depends: ['startDate', 'endDate'], calculate: function(data) { var start = data.startDate, end = data.endDate, ms = 0; if (end && start) { ms = end.getTime() - start.getTime(); } return ms / 60000; } }], getAllDay: function() { return this.data.allDay; }, getCalendarId: function() { return this.data.calendarId; }, getColor: function() { return this.data.color; }, getDescription: function() { return this.data.description; }, getDuration: function() { return this.data.duration; }, getEndDate: function() { return this.data.endDate; }, getRange: function() { var me = this, range = me.range; if (!range) { me.range = range = new Ext.calendar.date.Range(me.getStartDate(), me.getEndDate()); } return range; }, getStartDate: function() { return this.data.startDate; }, getTitle: function() { return this.data.title; }, isEditable: function() { var calendar = this.getCalendar(); return calendar ? calendar.isEditable() : true; }, setAllDay: function(allDay) { this.set('allDay', allDay); }, setCalendarId: function(calendarId, dirty) { dirty = dirty !== false; this.set('calendarId', calendarId, { dirty: dirty }); }, setColor: function(color) { this.set('color', color); }, setData: function(data) { var duration = data.duration; if (duration) { data = Ext.apply({}, data); delete data.duration; this.setDuration(duration) } else if (data.startDate && data.endDate) { this.range = null; } this.set(data); }, setDescription: function(description) { this.set('description', description); }, setDuration: function(duration) { var D = Ext.Date; this.range = null; this.set('endDate', D.add(this.data.startDate, D.MINUTE, duration)); }, setRange: function(start, end) { var D = Ext.Date; if (start.isRange) { end = start.end; start = start.start; } this.range = null; this.set({ startDate: D.clone(start), endDate: D.clone(end) }); }, setTitle: function(title) { this.set('title', title); }});