X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/0494b8d9b9bb03ab6c22b34dae81261e3cd7e3e6..7a654f8d43fdb43d78b63d90528bed6e86b608cc:/examples/calendar/calendar-all-debug.js diff --git a/examples/calendar/calendar-all-debug.js b/examples/calendar/calendar-all-debug.js deleted file mode 100644 index e1e7cb80..00000000 --- a/examples/calendar/calendar-all-debug.js +++ /dev/null @@ -1,5246 +0,0 @@ -/*! - * Ext JS Library 3.3.1 - * Copyright(c) 2006-2010 Sencha Inc. - * licensing@sencha.com - * http://www.sencha.com/license - */ -Ext.ns('Ext.calendar'); - - (function() { - Ext.apply(Ext.calendar, { - Date: { - diffDays: function(start, end) { - day = 1000 * 60 * 60 * 24; - diff = end.clearTime(true).getTime() - start.clearTime(true).getTime(); - return Math.ceil(diff / day); - }, - - copyTime: function(fromDt, toDt) { - var dt = toDt.clone(); - dt.setHours( - fromDt.getHours(), - fromDt.getMinutes(), - fromDt.getSeconds(), - fromDt.getMilliseconds()); - - return dt; - }, - - compare: function(dt1, dt2, precise) { - if (precise !== true) { - dt1 = dt1.clone(); - dt1.setMilliseconds(0); - dt2 = dt2.clone(); - dt2.setMilliseconds(0); - } - return dt2.getTime() - dt1.getTime(); - }, - - // private helper fn - maxOrMin: function(max) { - var dt = (max ? 0: Number.MAX_VALUE), - i = 0, - args = arguments[1], - ln = args.length; - for (; i < ln; i++) { - dt = Math[max ? 'max': 'min'](dt, args[i].getTime()); - } - return new Date(dt); - }, - - max: function() { - return this.maxOrMin.apply(this, [true, arguments]); - }, - - min: function() { - return this.maxOrMin.apply(this, [false, arguments]); - } - } - }); -})();/** - * @class Ext.calendar.DayHeaderTemplate - * @extends Ext.XTemplate - *

This is the template used to render the all-day event container used in {@link Ext.calendar.DayView DayView} and - * {@link Ext.calendar.WeekView WeekView}. Internally the majority of the layout logic is deferred to an instance of - * {@link Ext.calendar.BoxLayoutTemplate}.

- *

This template is automatically bound to the underlying event store by the - * calendar components and expects records of type {@link Ext.calendar.EventRecord}.

- *

Note that this template would not normally be used directly. Instead you would use the {@link Ext.calendar.DayViewTemplate} - * that internally creates an instance of this template along with a {@link Ext.calendar.DayBodyTemplate}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DayHeaderTemplate = function(config){ - - Ext.apply(this, config); - - this.allDayTpl = new Ext.calendar.BoxLayoutTemplate(config); - this.allDayTpl.compile(); - - Ext.calendar.DayHeaderTemplate.superclass.constructor.call(this, - '
', - '', - '', - '', - '', - '', - '', - '', - '', - '
{allDayTpl}
', - '
' - ); -}; - -Ext.extend(Ext.calendar.DayHeaderTemplate, Ext.XTemplate, { - applyTemplate : function(o){ - return Ext.calendar.DayHeaderTemplate.superclass.applyTemplate.call(this, { - allDayTpl: this.allDayTpl.apply(o) - }); - } -}); - -Ext.calendar.DayHeaderTemplate.prototype.apply = Ext.calendar.DayHeaderTemplate.prototype.applyTemplate; -/** - * @class Ext.calendar.DayBodyTemplate - * @extends Ext.XTemplate - *

This is the template used to render the scrolling body container used in {@link Ext.calendar.DayView DayView} and - * {@link Ext.calendar.WeekView WeekView}. This template is automatically bound to the underlying event store by the - * calendar components and expects records of type {@link Ext.calendar.EventRecord}.

- *

Note that this template would not normally be used directly. Instead you would use the {@link Ext.calendar.DayViewTemplate} - * that internally creates an instance of this template along with a {@link Ext.calendar.DayHeaderTemplate}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DayBodyTemplate = function(config){ - - Ext.apply(this, config); - - Ext.calendar.DayBodyTemplate.superclass.constructor.call(this, - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '
', - '
', - '
', - '', - '
', - '
', - '
', - '
', - '
', - '
', - '
', - '', - '
', - '
{.}
', - '
', - '
', - '
', - '
', - '
', - '
', - '
' - ); -}; - -Ext.extend(Ext.calendar.DayBodyTemplate, Ext.XTemplate, { - // private - applyTemplate : function(o){ - this.today = new Date().clearTime(); - this.dayCount = this.dayCount || 1; - - var i = 0, days = [], - dt = o.viewStart.clone(), - times; - - for(; iThis is the template used to render the all-day event container used in {@link Ext.calendar.DayView DayView} and - * {@link Ext.calendar.WeekView WeekView}. Internally this class simply defers to instances of {@link Ext.calerndar.DayHeaderTemplate} - * and {@link Ext.calerndar.DayBodyTemplate} to perform the actual rendering logic, but it also provides the overall calendar view - * container that contains them both. As such this is the template that should be used when rendering day or week views.

- *

This template is automatically bound to the underlying event store by the - * calendar components and expects records of type {@link Ext.calendar.EventRecord}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DayViewTemplate = function(config){ - - Ext.apply(this, config); - - this.headerTpl = new Ext.calendar.DayHeaderTemplate(config); - this.headerTpl.compile(); - - this.bodyTpl = new Ext.calendar.DayBodyTemplate(config); - this.bodyTpl.compile(); - - Ext.calendar.DayViewTemplate.superclass.constructor.call(this, - '
', - '{headerTpl}', - '{bodyTpl}', - '
' - ); -}; - -Ext.extend(Ext.calendar.DayViewTemplate, Ext.XTemplate, { - // private - applyTemplate : function(o){ - return Ext.calendar.DayViewTemplate.superclass.applyTemplate.call(this, { - headerTpl: this.headerTpl.apply(o), - bodyTpl: this.bodyTpl.apply(o) - }); - } -}); - -Ext.calendar.DayViewTemplate.prototype.apply = Ext.calendar.DayViewTemplate.prototype.applyTemplate; -/** - * @class Ext.calendar.BoxLayoutTemplate - * @extends Ext.XTemplate - *

This is the template used to render calendar views based on small day boxes within a non-scrolling container (currently - * the {@link Ext.calendar.MonthView MonthView} and the all-day headers for {@link Ext.calendar.DayView DayView} and - * {@link Ext.calendar.WeekView WeekView}. This template is automatically bound to the underlying event store by the - * calendar components and expects records of type {@link Ext.calendar.EventRecord}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.BoxLayoutTemplate = function(config){ - - Ext.apply(this, config); - - var weekLinkTpl = this.showWeekLinks ? '' : ''; - - Ext.calendar.BoxLayoutTemplate.superclass.constructor.call(this, - '', - '
', - weekLinkTpl, - '', - '', - '', - '', - '', - '', - '', - '', - '
 
', - '', - '', - '', - '', - '', - '', - '', - '', - '
{title}
', - '
', - '
', { - getRowTop: function(i, ln){ - return ((i-1)*(100/ln)); - }, - getRowHeight: function(ln){ - return 100/ln; - } - } - ); -}; - -Ext.extend(Ext.calendar.BoxLayoutTemplate, Ext.XTemplate, { - // private - applyTemplate : function(o){ - - Ext.apply(this, o); - - var w = 0, title = '', first = true, isToday = false, showMonth = false, prevMonth = false, nextMonth = false, - weeks = [[]], - today = new Date().clearTime(), - dt = this.viewStart.clone(), - thisMonth = this.startDate.getMonth(); - - for(; w < this.weekCount || this.weekCount == -1; w++){ - if(dt > this.viewEnd){ - break; - } - weeks[w] = []; - - for(var d = 0; d < this.dayCount; d++){ - isToday = dt.getTime() === today.getTime(); - showMonth = first || (dt.getDate() == 1); - prevMonth = (dt.getMonth() < thisMonth) && this.weekCount == -1; - nextMonth = (dt.getMonth() > thisMonth) && this.weekCount == -1; - - if(dt.getDay() == 1){ - // The ISO week format 'W' is relative to a Monday week start. If we - // make this check on Sunday the week number will be off. - weeks[w].weekNum = this.showWeekNumbers ? dt.format('W') : ' '; - weeks[w].weekLinkId = 'ext-cal-week-'+dt.format('Ymd'); - } - - if(showMonth){ - if(isToday){ - title = this.getTodayText(); - } - else{ - title = dt.format(this.dayCount == 1 ? 'l, F j, Y' : (first ? 'M j, Y' : 'M j')); - } - } - else{ - var dayFmt = (w == 0 && this.showHeader !== true) ? 'D j' : 'j'; - title = isToday ? this.getTodayText() : dt.format(dayFmt); - } - - weeks[w].push({ - title: title, - date: dt.clone(), - titleCls: 'ext-cal-dtitle ' + (isToday ? ' ext-cal-dtitle-today' : '') + - (w==0 ? ' ext-cal-dtitle-first' : '') + - (prevMonth ? ' ext-cal-dtitle-prev' : '') + - (nextMonth ? ' ext-cal-dtitle-next' : ''), - cellCls: 'ext-cal-day ' + (isToday ? ' ext-cal-day-today' : '') + - (d==0 ? ' ext-cal-day-first' : '') + - (prevMonth ? ' ext-cal-day-prev' : '') + - (nextMonth ? ' ext-cal-day-next' : '') - }); - dt = dt.add(Date.DAY, 1); - first = false; - } - } - - return Ext.calendar.BoxLayoutTemplate.superclass.applyTemplate.call(this, { - weeks: weeks - }); - }, - - // private - getTodayText : function(){ - var dt = new Date().format('l, F j, Y'), - todayText = this.showTodayText !== false ? this.todayText : '', - timeText = this.showTime !== false ? ' ' + - new Date().format('g:i a') + '' : '', - separator = todayText.length > 0 || timeText.length > 0 ? ' — ' : ''; - - if(this.dayCount == 1){ - return dt + separator + todayText + timeText; - } - fmt = this.weekCount == 1 ? 'D j' : 'j'; - return todayText.length > 0 ? todayText + timeText : new Date().format(fmt) + timeText; - } -}); - -Ext.calendar.BoxLayoutTemplate.prototype.apply = Ext.calendar.BoxLayoutTemplate.prototype.applyTemplate; -/** - * @class Ext.calendar.MonthViewTemplate - * @extends Ext.XTemplate - *

This is the template used to render the {@link Ext.calendar.MonthView MonthView}. Internally this class defers to an - * instance of {@link Ext.calerndar.BoxLayoutTemplate} to handle the inner layout rendering and adds containing elements around - * that to form the month view.

- *

This template is automatically bound to the underlying event store by the - * calendar components and expects records of type {@link Ext.calendar.EventRecord}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.MonthViewTemplate = function(config){ - - Ext.apply(this, config); - - this.weekTpl = new Ext.calendar.BoxLayoutTemplate(config); - this.weekTpl.compile(); - - var weekLinkTpl = this.showWeekLinks ? '' : ''; - - Ext.calendar.MonthViewTemplate.superclass.constructor.call(this, - '
', - '
', - weekLinkTpl, - '', - '', - '', - '', - '', - '', - '', - '', - '
{.:date("D")}
', - '
', - '
{weeks}
', - '
' - ); -}; - -Ext.extend(Ext.calendar.MonthViewTemplate, Ext.XTemplate, { - // private - applyTemplate : function(o){ - var days = [], - weeks = this.weekTpl.apply(o), - dt = o.viewStart; - - for(var i = 0; i < 7; i++){ - days.push(dt.add(Date.DAY, i)); - } - - var extraClasses = this.showHeader === true ? '' : 'ext-cal-noheader'; - if(this.showWeekLinks){ - extraClasses += ' ext-cal-week-links'; - } - - return Ext.calendar.MonthViewTemplate.superclass.applyTemplate.call(this, { - days: days, - weeks: weeks, - extraClasses: extraClasses - }); - } -}); - -Ext.calendar.MonthViewTemplate.prototype.apply = Ext.calendar.MonthViewTemplate.prototype.applyTemplate; -/** - * @class Ext.dd.ScrollManager - *

Provides automatic scrolling of overflow regions in the page during drag operations.

- *

The ScrollManager configs will be used as the defaults for any scroll container registered with it, - * but you can also override most of the configs per scroll container by adding a - * ddScrollConfig object to the target element that contains these properties: {@link #hthresh}, - * {@link #vthresh}, {@link #increment} and {@link #frequency}. Example usage: - *


-var el = Ext.get('scroll-ct');
-el.ddScrollConfig = {
-    vthresh: 50,
-    hthresh: -1,
-    frequency: 100,
-    increment: 200
-};
-Ext.dd.ScrollManager.register(el);
-
- * Note: This class uses "Point Mode" and is untested in "Intersect Mode". - * @singleton - */ -Ext.dd.ScrollManager = function() { - var ddm = Ext.dd.DragDropMgr, - els = {}, - dragEl = null, - proc = {}, - onStop = function(e) { - dragEl = null; - clearProc(); - }, - triggerRefresh = function() { - if (ddm.dragCurrent) { - ddm.refreshCache(ddm.dragCurrent.groups); - } - }, - doScroll = function() { - if (ddm.dragCurrent) { - var dds = Ext.dd.ScrollManager, - inc = proc.el.ddScrollConfig ? proc.el.ddScrollConfig.increment: dds.increment; - if (!dds.animate) { - if (proc.el.scroll(proc.dir, inc)) { - triggerRefresh(); - } - } else { - proc.el.scroll(proc.dir, inc, true, dds.animDuration, triggerRefresh); - } - } - }, - clearProc = function() { - if (proc.id) { - clearInterval(proc.id); - } - proc.id = 0; - proc.el = null; - proc.dir = ""; - }, - startProc = function(el, dir) { - clearProc(); - proc.el = el; - proc.dir = dir; - var freq = (el.ddScrollConfig && el.ddScrollConfig.frequency) ? - el.ddScrollConfig.frequency: Ext.dd.ScrollManager.frequency, - group = el.ddScrollConfig ? el.ddScrollConfig.ddGroup: undefined; - - if (group === undefined || ddm.dragCurrent.ddGroup == group) { - proc.id = setInterval(doScroll, freq); - } - }, - onFire = function(e, isDrop) { - if (isDrop || !ddm.dragCurrent) { - return; - } - var dds = Ext.dd.ScrollManager; - if (!dragEl || dragEl != ddm.dragCurrent) { - dragEl = ddm.dragCurrent; - // refresh regions on drag start - dds.refreshCache(); - } - - var xy = Ext.lib.Event.getXY(e), - pt = new Ext.lib.Point(xy[0], xy[1]), - id, - el, - r, - c; - for (id in els) { - if (els.hasOwnProperty(id)) { - el = els[id]; - r = el._region; - c = el.ddScrollConfig ? el.ddScrollConfig: dds; - if (r && r.contains(pt) && el.isScrollable()) { - if (r.bottom - pt.y <= c.vthresh) { - if (proc.el != el) { - startProc(el, "down"); - } - return; - } else if (r.right - pt.x <= c.hthresh) { - if (proc.el != el) { - startProc(el, "left"); - } - return; - } else if (pt.y - r.top <= c.vthresh) { - if (proc.el != el) { - startProc(el, "up"); - } - return; - } else if (pt.x - r.left <= c.hthresh) { - if (proc.el != el) { - startProc(el, "right"); - } - return; - } - } - } - } - clearProc(); - }; - - ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm); - ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm); - - return { - /** - * Registers new overflow element(s) to auto scroll - * @param {Mixed/Array} el The id of or the element to be scrolled or an array of either - */ - register: function(el) { - if (Ext.isArray(el)) { - var i = 0, - len = el.length; - for (; i < len; i++) { - this.register(el[i]); - } - } else { - el = Ext.get(el); - els[el.id] = el; - } - }, - - /** - * Unregisters overflow element(s) so they are no longer scrolled - * @param {Mixed/Array} el The id of or the element to be removed or an array of either - */ - unregister: function(el) { - if (Ext.isArray(el)) { - var i = 0, - len = el.length; - for (; i < len; i++) { - this.unregister(el[i]); - } - } else { - el = Ext.get(el); - delete els[el.id]; - } - }, - - /** - * The number of pixels from the top or bottom edge of a container the pointer needs to be to - * trigger scrolling (defaults to 25) - * @type Number - */ - vthresh: 25, - /** - * The number of pixels from the right or left edge of a container the pointer needs to be to - * trigger scrolling (defaults to 25) - * @type Number - */ - hthresh: 25, - - /** - * The number of pixels to scroll in each scroll increment (defaults to 50) - * @type Number - */ - increment: 100, - - /** - * The frequency of scrolls in milliseconds (defaults to 500) - * @type Number - */ - frequency: 500, - - /** - * True to animate the scroll (defaults to true) - * @type Boolean - */ - animate: true, - - /** - * The animation duration in seconds - - * MUST BE less than Ext.dd.ScrollManager.frequency! (defaults to .4) - * @type Number - */ - animDuration: 0.4, - - /** - * Manually trigger a cache refresh. - */ - refreshCache: function() { - var id; - for (id in els) { - if (els.hasOwnProperty(id)) { - if (typeof els[id] == 'object') { - // for people extending the object prototype - els[id]._region = els[id].getRegion(); - } - } - } - } - }; -}();/* - * @class Ext.calendar.StatusProxy - * A specialized drag proxy that supports a drop status icon, {@link Ext.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. - * @constructor - * @param {Object} config - */ -Ext.calendar.StatusProxy = function(config) { - Ext.apply(this, config); - this.id = this.id || Ext.id(); - this.el = new Ext.Layer({ - dh: { - id: this.id, - cls: 'ext-dd-drag-proxy x-dd-drag-proxy ' + this.dropNotAllowed, - cn: [ - { - cls: 'x-dd-drop-icon' - }, - { - cls: 'ext-dd-ghost-ct', - cn: [ - { - cls: 'x-dd-drag-ghost' - }, - { - cls: 'ext-dd-msg' - } - ] - } - ] - }, - shadow: !config || config.shadow !== false - }); - this.ghost = Ext.get(this.el.dom.childNodes[1].childNodes[0]); - this.message = Ext.get(this.el.dom.childNodes[1].childNodes[1]); - this.dropStatus = this.dropNotAllowed; -}; - -Ext.extend(Ext.calendar.StatusProxy, 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'). - */ - moveEventCls: 'ext-cal-dd-move', - /** - * @cfg {String} addEventCls - * The CSS class to apply to the status element when drop is not allowed (defaults to 'ext-cal-dd-add'). - */ - addEventCls: 'ext-cal-dd-add', - - // inherit docs - update: function(html) { - if (typeof html == 'string') { - this.ghost.update(html); - } else { - this.ghost.update(''); - html.style.margin = '0'; - this.ghost.dom.appendChild(html); - } - var el = this.ghost.dom.firstChild; - if (el) { - Ext.fly(el).setStyle('float', 'none').setHeight('auto'); - Ext.getDom(el).id += '-ddproxy'; - } - }, - - /** - * Update the calendar-specific drag status message without altering the ghost element. - * @param {String} msg The new status message - */ - updateMsg: function(msg) { - this.message.update(msg); - } -});/* - * Internal drag zone implementation for the calendar components. This provides base functionality - * and is primarily for the month view -- DayViewDD adds day/week view-specific functionality. - */ -Ext.calendar.DragZone = Ext.extend(Ext.dd.DragZone, { - ddGroup: 'CalendarDD', - eventSelector: '.ext-cal-evt', - - constructor: function(el, config) { - if (!Ext.calendar._statusProxyInstance) { - Ext.calendar._statusProxyInstance = new Ext.calendar.StatusProxy(); - } - this.proxy = Ext.calendar._statusProxyInstance; - Ext.calendar.DragZone.superclass.constructor.call(this, el, config); - }, - - getDragData: function(e) { - // Check whether we are dragging on an event first - var t = e.getTarget(this.eventSelector, 3); - if (t) { - var rec = this.view.getEventRecordFromEl(t); - return { - type: 'eventdrag', - ddel: t, - eventStart: rec.data[Ext.calendar.EventMappings.StartDate.name], - eventEnd: rec.data[Ext.calendar.EventMappings.EndDate.name], - proxy: this.proxy - }; - } - - // If not dragging an event then we are dragging on - // the calendar to add a new event - t = this.view.getDayAt(e.getPageX(), e.getPageY()); - if (t.el) { - return { - type: 'caldrag', - start: t.date, - proxy: this.proxy - }; - } - return null; - }, - - onInitDrag: function(x, y) { - if (this.dragData.ddel) { - var ghost = this.dragData.ddel.cloneNode(true), - child = Ext.fly(ghost).child('dl'); - - Ext.fly(ghost).setWidth('auto'); - - if (child) { - // for IE/Opera - child.setHeight('auto'); - } - this.proxy.update(ghost); - this.onStartDrag(x, y); - } - else if (this.dragData.start) { - this.onStartDrag(x, y); - } - this.view.onInitDrag(); - return true; - }, - - afterRepair: function() { - if (Ext.enableFx && this.dragData.ddel) { - Ext.Element.fly(this.dragData.ddel).highlight(this.hlColor || 'c3daf9'); - } - this.dragging = false; - }, - - getRepairXY: function(e) { - if (this.dragData.ddel) { - return Ext.Element.fly(this.dragData.ddel).getXY(); - } - }, - - afterInvalidDrop: function(e, id) { - Ext.select('.ext-dd-shim').hide(); - } -}); - -/* - * Internal drop zone implementation for the calendar components. This provides base functionality - * and is primarily for the month view -- DayViewDD adds day/week view-specific functionality. - */ -Ext.calendar.DropZone = Ext.extend(Ext.dd.DropZone, { - ddGroup: 'CalendarDD', - eventSelector: '.ext-cal-evt', - - // private - shims: [], - - getTargetFromEvent: function(e) { - var dragOffset = this.dragOffset || 0, - y = e.getPageY() - dragOffset, - d = this.view.getDayAt(e.getPageX(), y); - - return d.el ? d: null; - }, - - onNodeOver: function(n, dd, e, data) { - var D = Ext.calendar.Date, - start = data.type == 'eventdrag' ? n.date: D.min(data.start, n.date), - end = data.type == 'eventdrag' ? n.date.add(Date.DAY, D.diffDays(data.eventStart, data.eventEnd)) : - D.max(data.start, n.date); - - if (!this.dragStartDate || !this.dragEndDate || (D.diffDays(start, this.dragStartDate) != 0) || (D.diffDays(end, this.dragEndDate) != 0)) { - this.dragStartDate = start; - this.dragEndDate = end.clearTime().add(Date.DAY, 1).add(Date.MILLI, -1); - this.shim(start, end); - - var range = start.format('n/j'); - if (D.diffDays(start, end) > 0) { - range += '-' + end.format('n/j'); - } - var msg = String.format(data.type == 'eventdrag' ? this.moveText: this.createText, range); - data.proxy.updateMsg(msg); - } - return this.dropAllowed; - }, - - shim: function(start, end) { - this.currWeek = -1; - var dt = start.clone(), - i = 0, - shim, - box, - cnt = Ext.calendar.Date.diffDays(dt, end) + 1; - - Ext.each(this.shims, - function(shim) { - if (shim) { - shim.isActive = false; - } - } - ); - - while (i++This is the {@link Ext.data.Record Record} specification for calendar event data used by the - * {@link Ext.calendar.CalendarPanel CalendarPanel}'s underlying store. It can be overridden as - * necessary to customize the fields supported by events, although the existing column names should - * not be altered. If your model fields are named differently you should update the mapping - * configs accordingly.

- *

The only required fields when creating a new event record instance are StartDate and - * EndDate. All other fields are either optional are will be defaulted if blank.

- *

Here is a basic example for how to create a new record of this type:


-rec = new Ext.calendar.EventRecord({
-    StartDate: '2101-01-12 12:00:00',
-    EndDate: '2101-01-12 13:30:00',
-    Title: 'My cool event',
-    Notes: 'Some notes'
-});
-
- * If you have overridden any of the record's data mappings via the Ext.calendar.EventMappings object - * you may need to set the values using this alternate syntax to ensure that the fields match up correctly:

-var M = Ext.calendar.EventMappings;
-
-rec = new Ext.calendar.EventRecord();
-rec.data[M.StartDate.name] = '2101-01-12 12:00:00';
-rec.data[M.EndDate.name] = '2101-01-12 13:30:00';
-rec.data[M.Title.name] = 'My cool event';
-rec.data[M.Notes.name] = 'Some notes';
-
- * @constructor - * @param {Object} data (Optional) An object, the properties of which provide values for the new Record's - * fields. If not specified the {@link Ext.data.Field#defaultValue defaultValue} - * for each field will be assigned. - * @param {Object} id (Optional) The id of the Record. The id is used by the - * {@link Ext.data.Store} object which owns the Record to index its collection - * of Records (therefore this id should be unique within each store). If an - * id is not specified a {@link #phantom} - * Record will be created with an {@link #Record.id automatically generated id}. - */ - (function() { - var M = Ext.calendar.EventMappings; - - Ext.calendar.EventRecord = Ext.data.Record.create([ - M.EventId, - M.CalendarId, - M.Title, - M.StartDate, - M.EndDate, - M.Location, - M.Notes, - M.Url, - M.IsAllDay, - M.Reminder, - M.IsNew - ]); - - /** - * Reconfigures the default record definition based on the current Ext.calendar.EventMappings object - */ - Ext.calendar.EventRecord.reconfigure = function() { - Ext.calendar.EventRecord = Ext.data.Record.create([ - M.EventId, - M.CalendarId, - M.Title, - M.StartDate, - M.EndDate, - M.Location, - M.Notes, - M.Url, - M.IsAllDay, - M.Reminder, - M.IsNew - ]); - }; -})(); -/* - * This is the view used internally by the panel that displays overflow events in the - * month view. Anytime a day cell cannot display all of its events, it automatically displays - * a link at the bottom to view all events for that day. When clicked, a panel pops up that - * uses this view to display the events for that day. - */ -Ext.calendar.MonthDayDetailView = Ext.extend(Ext.BoxComponent, { - initComponent: function() { - Ext.calendar.CalendarView.superclass.initComponent.call(this); - - this.addEvents({ - eventsrendered: true - }); - - if (!this.el) { - this.el = document.createElement('div'); - } - }, - - afterRender: function() { - this.tpl = this.getTemplate(); - - Ext.calendar.MonthDayDetailView.superclass.afterRender.call(this); - - this.el.on({ - 'click': this.view.onClick, - 'mouseover': this.view.onMouseOver, - 'mouseout': this.view.onMouseOut, - scope: this.view - }); - }, - - getTemplate: function() { - if (!this.tpl) { - this.tpl = new Ext.XTemplate( - '
', - '', - '', - '', - '', - '', - '', - '
{markup}
', - '
' - ); - } - 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 = []; - - evts = this.store.queryBy(function(rec) { - var thisDt = this.date.clearTime(true).getTime(), - recStart = rec.data[Ext.calendar.EventMappings.StartDate.name].clearTime(true).getTime(), - startsOnDate = (thisDt == recStart), - spansDate = false; - - if (!startsOnDate) { - var recEnd = rec.data[Ext.calendar.EventMappings.EndDate.name].clearTime(true).getTime(); - spansDate = recStart < thisDt && recEnd >= thisDt; - } - return startsOnDate || spansDate; - }, - this); - - evts.each(function(evt) { - var item = evt.data, - M = Ext.calendar.EventMappings; - - item._renderAsAllDay = item[M.IsAllDay.name] || Ext.calendar.Date.diffDays(item[M.StartDate.name], item[M.EndDate.name]) > 0; - item.spanLeft = Ext.calendar.Date.diffDays(item[M.StartDate.name], this.date) > 0; - item.spanRight = Ext.calendar.Date.diffDays(this.date, item[M.EndDate.name]) > 0; - item.spanCls = (item.spanLeft ? (item.spanRight ? 'ext-cal-ev-spanboth': - 'ext-cal-ev-spanleft') : (item.spanRight ? 'ext-cal-ev-spanright': '')); - - templateData.push({ - markup: eventTpl.apply(this.getTemplateEventData(item)) - }); - }, - this); - - this.tpl.overwrite(this.el, templateData); - this.fireEvent('eventsrendered', this, this.date, evts.getCount()); - }, - - getTemplateEventData: function(evt) { - var data = this.view.getTemplateEventData(evt); - data._elId = 'dtl-' + data._elId; - return data; - } -}); - -Ext.reg('monthdaydetailview', Ext.calendar.MonthDayDetailView); -/** - * @class Ext.calendar.CalendarPicker - * @extends Ext.form.ComboBox - *

A custom combo used for choosing from the list of available calendars to assign an event to.

- *

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',
-    valueField: 'CalendarId',
-    displayField: 'Title',
-    triggerAction: 'all',
-    mode: 'local',
-    forceSelection: true,
-    width: 200
-
- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.CalendarPicker = Ext.extend(Ext.form.ComboBox, { - fieldLabel: 'Calendar', - valueField: 'CalendarId', - displayField: 'Title', - triggerAction: 'all', - mode: 'local', - forceSelection: true, - width: 200, - - // private - initComponent: function() { - Ext.calendar.CalendarPicker.superclass.initComponent.call(this); - this.tpl = this.tpl || - '
 
{' + this.displayField + '}
'; - }, - - // private - afterRender: function() { - Ext.calendar.CalendarPicker.superclass.afterRender.call(this); - - this.wrap = this.el.up('.x-form-field-wrap'); - this.wrap.addClass('ext-calendar-picker'); - - this.icon = Ext.DomHelper.append(this.wrap, { - tag: 'div', - cls: 'ext-cal-picker-icon ext-cal-picker-mainicon' - }); - }, - - // inherited docs - setValue: function(value) { - this.wrap.removeClass('ext-color-' + this.getValue()); - if (!value && this.store !== undefined) { - // always default to a valid calendar - value = this.store.getAt(0).data.CalendarId; - } - Ext.calendar.CalendarPicker.superclass.setValue.call(this, value); - this.wrap.addClass('ext-color-' + value); - } -}); - -Ext.reg('calendarpicker', Ext.calendar.CalendarPicker); -/* - * This is an internal helper class for the calendar views and should not be overridden. - * It is responsible for the base event rendering logic underlying all of the calendar views. - */ -Ext.calendar.WeekEventRenderer = function() { - - var getEventRow = function(id, week, index) { - var indexOffset = 1, - //skip row with date #'s - evtRow, - wkRow = Ext.get(id + '-wk-' + week); - if (wkRow) { - var table = wkRow.child('.ext-cal-evt-tbl', true); - evtRow = table.tBodies[0].childNodes[index + indexOffset]; - if (!evtRow) { - evtRow = Ext.DomHelper.append(table.tBodies[0], ''); - } - } - return Ext.get(evtRow); - }; - - return { - render: function(o) { - var w = 0, - grid = o.eventGrid, - dt = o.viewStart.clone(), - eventTpl = o.tpl, - max = o.maxEventsPerDay != undefined ? o.maxEventsPerDay: 999, - weekCount = o.weekCount < 1 ? 6: o.weekCount, - dayCount = o.weekCount == 1 ? o.dayCount: 7, - cellCfg; - - for (; w < weekCount; w++) { - if (!grid[w] || grid[w].length == 0) { - // no events or span cells for the entire week - if (weekCount == 1) { - row = getEventRow(o.id, w, 0); - cellCfg = { - tag: 'td', - cls: 'ext-cal-ev', - id: o.id + '-empty-0-day-' + dt.format('Ymd'), - html: ' ' - }; - if (dayCount > 1) { - cellCfg.colspan = dayCount; - } - Ext.DomHelper.append(row, cellCfg); - } - dt = dt.add(Date.DAY, 7); - } else { - var row, - d = 0, - wk = grid[w], - startOfWeek = dt.clone(), - endOfWeek = startOfWeek.add(Date.DAY, dayCount).add(Date.MILLI, -1); - - for (; d < dayCount; d++) { - if (wk[d]) { - var ev = emptyCells = skipped = 0, - day = wk[d], - ct = day.length, - evt; - - for (; ev < ct; ev++) { - if (!day[ev]) { - emptyCells++; - continue; - } - if (emptyCells > 0 && ev - emptyCells < max) { - row = getEventRow(o.id, w, ev - emptyCells); - cellCfg = { - tag: 'td', - cls: 'ext-cal-ev', - id: o.id + '-empty-' + ct + '-day-' + dt.format('Ymd') - }; - if (emptyCells > 1 && max - ev > emptyCells) { - cellCfg.rowspan = Math.min(emptyCells, max - ev); - } - Ext.DomHelper.append(row, cellCfg); - emptyCells = 0; - } - - if (ev >= max) { - skipped++; - continue; - } - evt = day[ev]; - - if (!evt.isSpan || evt.isSpanStart) { - //skip non-starting span cells - var item = evt.data || evt.event.data; - item._weekIndex = w; - item._renderAsAllDay = item[Ext.calendar.EventMappings.IsAllDay.name] || evt.isSpanStart; - item.spanLeft = item[Ext.calendar.EventMappings.StartDate.name].getTime() < startOfWeek.getTime(); - item.spanRight = item[Ext.calendar.EventMappings.EndDate.name].getTime() > endOfWeek.getTime(); - item.spanCls = (item.spanLeft ? (item.spanRight ? 'ext-cal-ev-spanboth': - 'ext-cal-ev-spanleft') : (item.spanRight ? 'ext-cal-ev-spanright': '')); - - row = getEventRow(o.id, w, ev); - cellCfg = { - tag: 'td', - cls: 'ext-cal-ev', - cn: eventTpl.apply(o.templateDataFn(item)) - }; - var diff = Ext.calendar.Date.diffDays(dt, item[Ext.calendar.EventMappings.EndDate.name]) + 1, - cspan = Math.min(diff, dayCount - d); - - if (cspan > 1) { - cellCfg.colspan = cspan; - } - Ext.DomHelper.append(row, cellCfg); - } - } - if (ev > max) { - row = getEventRow(o.id, w, max); - Ext.DomHelper.append(row, { - tag: 'td', - cls: 'ext-cal-ev-more', - id: 'ext-cal-ev-more-' + dt.format('Ymd'), - cn: { - tag: 'a', - html: '+' + skipped + ' more...' - } - }); - } - if (ct < o.evtMaxCount[w]) { - row = getEventRow(o.id, w, ct); - if (row) { - cellCfg = { - tag: 'td', - cls: 'ext-cal-ev', - id: o.id + '-empty-' + (ct + 1) + '-day-' + dt.format('Ymd') - }; - var rowspan = o.evtMaxCount[w] - ct; - if (rowspan > 1) { - cellCfg.rowspan = rowspan; - } - Ext.DomHelper.append(row, cellCfg); - } - } - } else { - row = getEventRow(o.id, w, 0); - if (row) { - cellCfg = { - tag: 'td', - cls: 'ext-cal-ev', - id: o.id + '-empty-day-' + dt.format('Ymd') - }; - if (o.evtMaxCount[w] > 1) { - cellCfg.rowSpan = o.evtMaxCount[w]; - } - Ext.DomHelper.append(row, cellCfg); - } - } - dt = dt.add(Date.DAY, 1); - } - } - } - } - }; -}(); -/** - * @class Ext.calendar.CalendarView - * @extends Ext.BoxComponent - *

This is an abstract class that serves as the base for other calendar views. This class is not - * intended to be directly instantiated.

- *

When extending this class to create a custom calendar view, you must provide an implementation - * for the renderItems method, as there is no default implementation for rendering events - * The rendering logic is totally dependent on how the UI structures its data, which - * is determined by the underlying UI template (this base class does not have a template).

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.CalendarView = Ext.extend(Ext.BoxComponent, { - /** - * @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, - * span events are always sorted first, possibly at the expense of start dates being out of order (e.g., - * a span event that starts at 11am one day and spans into the next day would display before a non-spanning - * event that starts at 10am, even though they would not be in date order). This can lead to more compact - * layouts when there are many overlapping events. If false (the default), events will always sort by start date - * 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 - * it will override any values for {@link #enableAddFx}, {@link #enableUpdateFx} or {@link enableRemoveFx} and - * 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 - * {@link #enableFx} is false it will override this value. The specific effect that runs is defined in the - * {@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 - * {@link #enableFx} is false it will override this value. The specific effect that runs is defined in the - * {@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 - * {@link #enableFx} is false it will override this value. The specific effect that runs is defined in the - * {@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} monitorResize - * True to monitor the browser's resize event (the default), false to ignore it. If the calendar view is rendered - * into a fixed-size container this can be set to false. However, if the view can change dimensions (e.g., it's in - * fit layout in a viewport or some other resizable container) it is very important that this config is true so that - * any resize event propagates properly to all subcomponents and layouts get recalculated properly. - */ - monitorResize: true, - /** - * @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} 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 - * 'Update event to {0}' where {0} is the updated event start-end range supplied by the view). Note that - * this text is only used in views - * that allow resizing of events. - */ - ddResizeEventText: 'Update event to {0}', - - //private properties -- do not override: - weekCount: 1, - dayCount: 1, - eventSelector: '.ext-cal-evt', - eventOverClass: 'ext-evt-over', - eventElIdDelimiter: '-evt-', - dayElIdDelimiter: '-day-', - - /** - * Returns a string of HTML template markup to be used as the body portion of the event template created - * by {@link #getEventTemplate}. This provdes the flexibility to customize what's in the body without - * having to override the entire XTemplate. This string can include any valid {@link Ext.Template} code, and - * any data tokens accessible to the containing event template can be referenced in this string. - * @return {String} The body template string - */ - getEventBodyMarkup: Ext.emptyFn, - // must be implemented by a subclass - /** - *

Returns the XTemplate that is bound to the calendar's event store (it expects records of type - * {@link Ext.calendar.EventRecord}) to populate the calendar views with events. Internally this method - * by default generates different markup for browsers that support CSS border radius and those that don't. - * This method can be overridden as needed to customize the markup generated.

- *

Note that this method calls {@link #getEventBodyMarkup} to retrieve the body markup for events separately - * from the surrounding container markup. This provdes the flexibility to customize what's in the body without - * having to override the entire XTemplate. If you do override this method, you should make sure that your - * overridden version also does the same.

- * @return {Ext.XTemplate} The event XTemplate - */ - getEventTemplate: Ext.emptyFn, - // must be implemented by a subclass - // private - initComponent: function() { - this.setStartDate(this.startDate || new Date()); - - Ext.calendar.CalendarView.superclass.initComponent.call(this); - - this.addEvents({ - /** - * @event eventsrendered - * Fires after events are finished rendering in the view - * @param {Ext.calendar.CalendarView} this - */ - eventsrendered: true, - /** - * @event eventclick - * Fires after the user clicks on an event element - * @param {Ext.calendar.CalendarView} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarView} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarView} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} for the event that the cursor exited - * @param {HTMLNode} el The DOM node that was exited - */ - eventout: true, - /** - * @event datechange - * Fires after the start date of the view changes - * @param {Ext.calendar.CalendarView} 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 - * @param {Ext.calendar.CalendarView} 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 eventmove - * Fires after an event element is dragged by the user and dropped in a new position - * @param {Ext.calendar.CalendarView} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarView} this - */ - initdrag: true, - /** - * @event dayover - * Fires while the mouse is over a day element - * @param {Ext.calendar.CalendarView} 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 {Ext.calendar.CalendarView} this - * @param {Date} dt The date that is exited - * @param {Ext.Element} el The day Element that is exited - */ - dayout: true - /* - * @event eventdelete - * Fires after an event element is deleted by the user. Not currently implemented directly at the view level -- currently - * deletes only happen from one of the forms. - * @param {Ext.calendar.CalendarView} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} for the event that was deleted - */ - //eventdelete: true - }); - }, - - // private - afterRender: function() { - Ext.calendar.CalendarView.superclass.afterRender.call(this); - - this.renderTemplate(); - - if (this.store) { - this.setStore(this.store, true); - } - - this.el.on({ - 'mouseover': this.onMouseOver, - 'mouseout': this.onMouseOut, - 'click': this.onClick, - 'resize': this.onResize, - scope: this - }); - - this.el.unselectable(); - - if (this.enableDD && this.initDD) { - this.initDD(); - } - - this.on('eventsrendered', this.forceSize); - this.forceSize.defer(100, this); - - }, - - // private - forceSize: function() { - if (this.el && this.el.child) { - var hd = this.el.child('.ext-cal-hd-ct'), - bd = this.el.child('.ext-cal-body-ct'); - - if (bd == null || hd == null) return; - - var headerHeight = hd.getHeight(), - sz = this.el.parent().getSize(); - - bd.setHeight(sz.height - headerHeight); - } - }, - - refresh: function() { - this.prepareData(); - this.renderTemplate(); - this.renderItems(); - }, - - getWeekCount: function() { - var days = Ext.calendar.Date.diffDays(this.viewStart, this.viewEnd); - return Math.ceil(days / this.dayCount); - }, - - // private - prepareData: function() { - var lastInMonth = this.startDate.getLastDateOfMonth(), - w = 0, - row = 0, - dt = this.viewStart.clone(), - weeks = this.weekCount < 1 ? 6: this.weekCount; - - this.eventGrid = [[]]; - this.allDayGrid = [[]]; - this.evtMaxCount = []; - - var evtsInView = this.store.queryBy(function(rec) { - return this.isEventVisible(rec.data); - }, - this); - - for (; w < weeks; w++) { - this.evtMaxCount[w] = 0; - if (this.weekCount == -1 && dt > lastInMonth) { - //current week is fully in next month so skip - break; - } - this.eventGrid[w] = this.eventGrid[w] || []; - this.allDayGrid[w] = this.allDayGrid[w] || []; - - for (d = 0; d < this.dayCount; d++) { - if (evtsInView.getCount() > 0) { - var evts = evtsInView.filterBy(function(rec) { - var startsOnDate = (dt.getTime() == rec.data[Ext.calendar.EventMappings.StartDate.name].clearTime(true).getTime()); - var spansFromPrevView = (w == 0 && d == 0 && (dt > rec.data[Ext.calendar.EventMappings.StartDate.name])); - return startsOnDate || spansFromPrevView; - }, - this); - - this.sortEventRecordsForDay(evts); - this.prepareEventGrid(evts, w, d); - } - dt = dt.add(Date.DAY, 1); - } - } - this.currentWeekCount = w; - }, - - // private - prepareEventGrid: function(evts, w, d) { - var row = 0, - dt = this.viewStart.clone(), - max = this.maxEventsPerDay ? this.maxEventsPerDay: 999; - - evts.each(function(evt) { - var M = Ext.calendar.EventMappings, - days = Ext.calendar.Date.diffDays( - Ext.calendar.Date.max(this.viewStart, evt.data[M.StartDate.name]), - Ext.calendar.Date.min(this.viewEnd, evt.data[M.EndDate.name])) + 1; - - if (days > 1 || Ext.calendar.Date.diffDays(evt.data[M.StartDate.name], evt.data[M.EndDate.name]) > 1) { - this.prepareEventGridSpans(evt, this.eventGrid, w, d, days); - this.prepareEventGridSpans(evt, this.allDayGrid, w, d, days, true); - } else { - row = this.findEmptyRowIndex(w, d); - this.eventGrid[w][d] = this.eventGrid[w][d] || []; - this.eventGrid[w][d][row] = evt; - - if (evt.data[M.IsAllDay.name]) { - row = this.findEmptyRowIndex(w, d, true); - this.allDayGrid[w][d] = this.allDayGrid[w][d] || []; - this.allDayGrid[w][d][row] = evt; - } - } - - if (this.evtMaxCount[w] < this.eventGrid[w][d].length) { - this.evtMaxCount[w] = Math.min(max + 1, this.eventGrid[w][d].length); - } - return true; - }, - this); - }, - - // private - prepareEventGridSpans: function(evt, grid, w, d, days, allday) { - // this event spans multiple days/weeks, so we have to preprocess - // the events and store special span events as placeholders so that - // the render routine can build the necessary TD spans correctly. - var w1 = w, - d1 = d, - row = this.findEmptyRowIndex(w, d, allday), - dt = this.viewStart.clone(); - - var start = { - event: evt, - isSpan: true, - isSpanStart: true, - spanLeft: false, - spanRight: (d == 6) - }; - grid[w][d] = grid[w][d] || []; - grid[w][d][row] = start; - - while (--days) { - dt = dt.add(Date.DAY, 1); - if (dt > this.viewEnd) { - break; - } - if (++d1 > 6) { - // reset counters to the next week - d1 = 0; - w1++; - row = this.findEmptyRowIndex(w1, 0); - } - grid[w1] = grid[w1] || []; - grid[w1][d1] = grid[w1][d1] || []; - - grid[w1][d1][row] = { - event: evt, - isSpan: true, - isSpanStart: (d1 == 0), - spanLeft: (w1 > w) && (d1 % 7 == 0), - spanRight: (d1 == 6) && (days > 1) - }; - } - }, - - // private - findEmptyRowIndex: function(w, d, allday) { - var grid = allday ? this.allDayGrid: this.eventGrid, - day = grid[w] ? grid[w][d] || [] : [], - i = 0, - ln = day.length; - - for (; i < ln; i++) { - if (day[i] == null) { - return i; - } - } - return ln; - }, - - // private - renderTemplate: function() { - if (this.tpl) { - this.tpl.overwrite(this.el, this.getParams()); - this.lastRenderStart = this.viewStart.clone(); - this.lastRenderEnd = this.viewEnd.clone(); - } - }, - - disableStoreEvents: function() { - this.monitorStoreEvents = false; - }, - - enableStoreEvents: function(refresh) { - this.monitorStoreEvents = true; - if (refresh === true) { - this.refresh(); - } - }, - - // private - onResize: function() { - this.refresh(); - }, - - // private - onInitDrag: function() { - this.fireEvent('initdrag', this); - }, - - // private - onEventDrop: function(rec, dt) { - if (Ext.calendar.Date.compare(rec.data[Ext.calendar.EventMappings.StartDate.name], dt) === 0) { - // no changes - return; - } - var diff = dt.getTime() - rec.data[Ext.calendar.EventMappings.StartDate.name].getTime(); - rec.set(Ext.calendar.EventMappings.StartDate.name, dt); - rec.set(Ext.calendar.EventMappings.EndDate.name, rec.data[Ext.calendar.EventMappings.EndDate.name].add(Date.MILLI, diff)); - - this.fireEvent('eventmove', this, rec); - }, - - // private - onCalendarEndDrag: function(start, end, onComplete) { - // set this flag for other event handlers that might conflict while we're waiting - this.dragPending = true; - - // have to wait for the user to save or cancel before finalizing the dd interation - var o = {}; - o[Ext.calendar.EventMappings.StartDate.name] = start; - o[Ext.calendar.EventMappings.EndDate.name] = end; - - this.fireEvent('rangeselect', this, o, this.onCalendarEndDragComplete.createDelegate(this, [onComplete])); - }, - - // private - onCalendarEndDragComplete: function(onComplete) { - // callback for the drop zone to clean up - onComplete(); - // clear flag for other events to resume normally - this.dragPending = false; - }, - - // private - onUpdate: function(ds, rec, operation) { - if (this.monitorStoreEvents === false) { - return; - } - if (operation == Ext.data.Record.COMMIT) { - this.refresh(); - if (this.enableFx && this.enableUpdateFx) { - this.doUpdateFx(this.getEventEls(rec.data[Ext.calendar.EventMappings.EventId.name]), { - scope: this - }); - } - } - }, - - - doUpdateFx: function(els, o) { - this.highlightEvent(els, null, o); - }, - - // private - onAdd: function(ds, records, index) { - if (this.monitorStoreEvents === false) { - return; - } - var rec = records[0]; - this.tempEventId = rec.id; - this.refresh(); - - if (this.enableFx && this.enableAddFx) { - this.doAddFx(this.getEventEls(rec.data[Ext.calendar.EventMappings.EventId.name]), { - scope: this - }); - }; - }, - - doAddFx: function(els, o) { - els.fadeIn(Ext.apply(o, { - duration: 2 - })); - }, - - // private - onRemove: function(ds, rec) { - if (this.monitorStoreEvents === false) { - return; - } - if (this.enableFx && this.enableRemoveFx) { - this.doRemoveFx(this.getEventEls(rec.data[Ext.calendar.EventMappings.EventId.name]), { - remove: true, - scope: this, - callback: this.refresh - }); - } - else { - this.getEventEls(rec.data[Ext.calendar.EventMappings.EventId.name]).remove(); - this.refresh(); - } - }, - - doRemoveFx: function(els, o) { - els.fadeOut(o); - }, - - /** - * Visually highlights an event using {@link Ext.Fx#highlight} config options. - * If {@link #highlightEventActions} is false this method will have no effect. - * @param {Ext.CompositeElement} els The element(s) to highlight - * @param {Object} color (optional) The highlight color. Should be a 6 char hex - * color without the leading # (defaults to yellow: 'ffff9c') - * @param {Object} o (optional) Object literal with any of the {@link Ext.Fx} config - * options. See {@link Ext.Fx#highlight} for usage examples. - */ - highlightEvent: function(els, color, o) { - if (this.enableFx) { - var c; - ! (Ext.isIE || Ext.isOpera) ? - els.highlight(color, o) : - // Fun IE/Opera handling: - els.each(function(el) { - el.highlight(color, Ext.applyIf({ - attr: 'color' - }, - o)); - c = el.child('.ext-cal-evm'); - if (c) { - c.highlight(color, o); - } - }, - this); - } - }, - - /** - * Retrieve an Event object's id from its corresponding node in the DOM. - * @param {String/Element/HTMLElement} el An {@link Ext.Element}, DOM node or id - */ - getEventIdFromEl: function(el) { - el = Ext.get(el); - var id = el.id.split(this.eventElIdDelimiter)[1]; - if (id.indexOf('-') > -1) { - //This id has the index of the week it is rendered in as the suffix. - //This allows events that span across weeks to still have reproducibly-unique DOM ids. - id = id.split('-')[0]; - } - return id; - }, - - // private - getEventId: function(eventId) { - if (eventId === undefined && this.tempEventId) { - eventId = this.tempEventId; - } - return eventId; - }, - - /** - * - * @param {String} eventId - * @param {Boolean} forSelect - * @return {String} The selector class - */ - getEventSelectorCls: function(eventId, forSelect) { - var prefix = forSelect ? '.': ''; - return prefix + this.id + this.eventElIdDelimiter + this.getEventId(eventId); - }, - - /** - * - * @param {String} eventId - * @return {Ext.CompositeElement} The matching CompositeElement of nodes - * that comprise the rendered event. Any event that spans across a view - * boundary will contain more than one internal Element. - */ - getEventEls: function(eventId) { - var els = Ext.select(this.getEventSelectorCls(this.getEventId(eventId), true), false, this.el.id); - return new Ext.CompositeElement(els); - }, - - /** - * Returns true if the view is currently displaying today's date, else false. - * @return {Boolean} True or false - */ - isToday: function() { - var today = new Date().clearTime().getTime(); - return this.viewStart.getTime() <= today && this.viewEnd.getTime() >= today; - }, - - // private - onDataChanged: function(store) { - this.refresh(); - }, - - // private - isEventVisible: function(evt) { - var start = this.viewStart.getTime(), - end = this.viewEnd.getTime(), - M = Ext.calendar.EventMappings, - evStart = (evt.data ? evt.data[M.StartDate.name] : evt[M.StartDate.name]).getTime(), - evEnd = (evt.data ? evt.data[M.EndDate.name] : evt[M.EndDate.name]).add(Date.SECOND, -1).getTime(), - - startsInRange = (evStart >= start && evStart <= end), - endsInRange = (evEnd >= start && evEnd <= end), - spansRange = (evStart < start && evEnd > end); - - return (startsInRange || endsInRange || spansRange); - }, - - // private - isOverlapping: function(evt1, evt2) { - var ev1 = evt1.data ? evt1.data: evt1, - ev2 = evt2.data ? evt2.data: evt2, - M = Ext.calendar.EventMappings, - start1 = ev1[M.StartDate.name].getTime(), - end1 = ev1[M.EndDate.name].add(Date.SECOND, -1).getTime(), - start2 = ev2[M.StartDate.name].getTime(), - end2 = ev2[M.EndDate.name].add(Date.SECOND, -1).getTime(); - - if (end1 < start1) { - end1 = start1; - } - if (end2 < start2) { - end2 = start2; - } - - var ev1startsInEv2 = (start1 >= start2 && start1 <= end2), - ev1EndsInEv2 = (end1 >= start2 && end1 <= end2), - ev1SpansEv2 = (start1 < start2 && end1 > end2); - - return (ev1startsInEv2 || ev1EndsInEv2 || ev1SpansEv2); - }, - - getDayEl: function(dt) { - return Ext.get(this.getDayId(dt)); - }, - - getDayId: function(dt) { - if (Ext.isDate(dt)) { - dt = dt.format('Ymd'); - } - return this.id + this.dayElIdDelimiter + dt; - }, - - /** - * Returns the start date of the view, as set by {@link #setStartDate}. Note that this may not - * be the first date displayed in the rendered calendar -- to get the start and end dates displayed - * to the user use {@link #getViewBounds}. - * @return {Date} The start date - */ - getStartDate: function() { - return this.startDate; - }, - - /** - * Sets the start date used to calculate the view boundaries to display. The displayed view will be the - * earliest and latest dates that match the view requirements and contain the date passed to this function. - * @param {Date} dt The date used to calculate the new view boundaries - */ - setStartDate: function(start, refresh) { - this.startDate = start.clearTime(); - this.setViewBounds(start); - this.store.load({ - params: { - start: this.viewStart.format('m-d-Y'), - end: this.viewEnd.format('m-d-Y') - } - }); - if (refresh === true) { - this.refresh(); - } - this.fireEvent('datechange', this, this.startDate, this.viewStart, this.viewEnd); - }, - - // private - setViewBounds: function(startDate) { - var start = startDate || this.startDate, - offset = start.getDay() - this.startDay; - - switch (this.weekCount) { - case 0: - case 1: - this.viewStart = this.dayCount < 7 ? start: start.add(Date.DAY, -offset).clearTime(true); - this.viewEnd = this.viewStart.add(Date.DAY, this.dayCount || 7).add(Date.SECOND, -1); - return; - - case - 1: - // auto by month - start = start.getFirstDateOfMonth(); - offset = start.getDay() - this.startDay; - if (offset < 0) { - offset += 7; - } - this.viewStart = start.add(Date.DAY, -offset).clearTime(true); - - // start from current month start, not view start: - var end = start.add(Date.MONTH, 1).add(Date.SECOND, -1); - // fill out to the end of the week: - this.viewEnd = end.add(Date.DAY, 6 - end.getDay()); - return; - - default: - this.viewStart = start.add(Date.DAY, -offset).clearTime(true); - this.viewEnd = this.viewStart.add(Date.DAY, this.weekCount * 7).add(Date.SECOND, -1); - } - }, - - // private - getViewBounds: function() { - return { - start: this.viewStart, - end: this.viewEnd - }; - }, - - /* private - * Sort events for a single day for display in the calendar. This sorts allday - * events first, then non-allday events are sorted either based on event start - * priority or span priority based on the value of {@link #spansHavePriority} - * (defaults to event start priority). - * @param {MixedCollection} evts A {@link Ext.util.MixedCollection MixedCollection} - * of {@link #Ext.calendar.EventRecord EventRecord} objects - */ - sortEventRecordsForDay: function(evts) { - if (evts.length < 2) { - return; - } - evts.sort('ASC', - function(evtA, evtB) { - var a = evtA.data, - b = evtB.data, - M = Ext.calendar.EventMappings; - - // Always sort all day events before anything else - if (a[M.IsAllDay.name]) { - return - 1; - } - else if (b[M.IsAllDay.name]) { - return 1; - } - if (this.spansHavePriority) { - // This logic always weights span events higher than non-span events - // (at the possible expense of start time order). This seems to - // be the approach used by Google calendar and can lead to a more - // visually appealing layout in complex cases, but event order is - // not guaranteed to be consistent. - var diff = Ext.calendar.Date.diffDays; - if (diff(a[M.StartDate.name], a[M.EndDate.name]) > 0) { - if (diff(b[M.StartDate.name], b[M.EndDate.name]) > 0) { - // Both events are multi-day - if (a[M.StartDate.name].getTime() == b[M.StartDate.name].getTime()) { - // If both events start at the same time, sort the one - // that ends later (potentially longer span bar) first - return b[M.EndDate.name].getTime() - a[M.EndDate.name].getTime(); - } - return a[M.StartDate.name].getTime() - b[M.StartDate.name].getTime(); - } - return - 1; - } - else if (diff(b[M.StartDate.name], b[M.EndDate.name]) > 0) { - return 1; - } - return a[M.StartDate.name].getTime() - b[M.StartDate.name].getTime(); - } - else { - // Doing this allows span and non-span events to intermingle but - // remain sorted sequentially by start time. This seems more proper - // but can make for a less visually-compact layout when there are - // many such events mixed together closely on the calendar. - return a[M.StartDate.name].getTime() - b[M.StartDate.name].getTime(); - } - }.createDelegate(this)); - }, - - /** - * Updates the view to contain the passed date - * @param {Date} dt The date to display - */ - moveTo: function(dt, noRefresh) { - if (Ext.isDate(dt)) { - this.setStartDate(dt); - if (noRefresh !== false) { - this.refresh(); - } - return this.startDate; - } - return dt; - }, - - /** - * Updates the view to the next consecutive date(s) - */ - moveNext: function(noRefresh) { - return this.moveTo(this.viewEnd.add(Date.DAY, 1)); - }, - - /** - * Updates the view to the previous consecutive date(s) - */ - movePrev: function(noRefresh) { - var days = Ext.calendar.Date.diffDays(this.viewStart, this.viewEnd) + 1; - return this.moveDays( - days, noRefresh); - }, - - /** - * Shifts the view by the passed number of months relative to the currently set date - * @param {Number} value The number of months (positive or negative) by which to shift the view - */ - moveMonths: function(value, noRefresh) { - return this.moveTo(this.startDate.add(Date.MONTH, value), noRefresh); - }, - - /** - * Shifts the view by the passed number of weeks relative to the currently set date - * @param {Number} value The number of weeks (positive or negative) by which to shift the view - */ - moveWeeks: function(value, noRefresh) { - return this.moveTo(this.startDate.add(Date.DAY, value * 7), noRefresh); - }, - - /** - * Shifts the view by the passed number of days relative to the currently set date - * @param {Number} value The number of days (positive or negative) by which to shift the view - */ - moveDays: function(value, noRefresh) { - return this.moveTo(this.startDate.add(Date.DAY, value), noRefresh); - }, - - /** - * Updates the view to show today - */ - moveToday: function(noRefresh) { - return this.moveTo(new Date(), noRefresh); - }, - - /** - * Sets the event store used by the calendar to display {@link Ext.calendar.EventRecord events}. - * @param {Ext.data.Store} store - */ - setStore: function(store, initial) { - if (!initial && this.store) { - this.store.un("datachanged", this.onDataChanged, this); - this.store.un("add", this.onAdd, this); - this.store.un("remove", this.onRemove, this); - this.store.un("update", this.onUpdate, this); - this.store.un("clear", this.refresh, this); - } - if (store) { - store.on("datachanged", this.onDataChanged, this); - store.on("add", this.onAdd, this); - store.on("remove", this.onRemove, this); - store.on("update", this.onUpdate, this); - store.on("clear", this.refresh, this); - } - this.store = store; - if (store && store.getCount() > 0) { - this.refresh(); - } - }, - - getEventRecord: function(id) { - var idx = this.store.find(Ext.calendar.EventMappings.EventId.name, id); - return this.store.getAt(idx); - }, - - getEventRecordFromEl: function(el) { - return this.getEventRecord(this.getEventIdFromEl(el)); - }, - - // private - getParams: function() { - return { - viewStart: this.viewStart, - viewEnd: this.viewEnd, - startDate: this.startDate, - dayCount: this.dayCount, - weekCount: this.weekCount, - title: this.getTitle() - }; - }, - - getTitle: function() { - return this.startDate.format('F Y'); - }, - - /* - * Shared click handling. Each specific view also provides view-specific - * click handling that calls this first. This method returns true if it - * can handle the click (and so the subclass should ignore it) else false. - */ - onClick: function(e, t) { - var el = e.getTarget(this.eventSelector, 5); - if (el) { - var id = this.getEventIdFromEl(el); - this.fireEvent('eventclick', this, this.getEventRecord(id), el); - return true; - } - }, - - // private - onMouseOver: function(e, t) { - if (this.trackMouseOver !== false && (this.dragZone == undefined || !this.dragZone.dragging)) { - if (!this.handleEventMouseEvent(e, t, 'over')) { - this.handleDayMouseEvent(e, t, 'over'); - } - } - }, - - // private - onMouseOut: function(e, t) { - if (this.trackMouseOver !== false && (this.dragZone == undefined || !this.dragZone.dragging)) { - if (!this.handleEventMouseEvent(e, t, 'out')) { - this.handleDayMouseEvent(e, t, 'out'); - } - } - }, - - // private - handleEventMouseEvent: function(e, t, type) { - var el = e.getTarget(this.eventSelector, 5, true), - rel, - els, - evtId; - if (el) { - rel = Ext.get(e.getRelatedTarget()); - if (el == rel || el.contains(rel)) { - return true; - } - - evtId = this.getEventIdFromEl(el); - - if (this.eventOverClass != '') { - els = this.getEventEls(evtId); - els[type == 'over' ? 'addClass': 'removeClass'](this.eventOverClass); - } - this.fireEvent('event' + type, this, this.getEventRecord(evtId), el); - return true; - } - return false; - }, - - // private - getDateFromId: function(id, delim) { - var parts = id.split(delim); - return parts[parts.length - 1]; - }, - - // private - handleDayMouseEvent: function(e, t, type) { - t = e.getTarget('td', 3); - if (t) { - if (t.id && t.id.indexOf(this.dayElIdDelimiter) > -1) { - var dt = this.getDateFromId(t.id, this.dayElIdDelimiter), - rel = Ext.get(e.getRelatedTarget()), - relTD, - relDate; - - if (rel) { - relTD = rel.is('td') ? rel: rel.up('td', 3); - relDate = relTD && relTD.id ? this.getDateFromId(relTD.id, this.dayElIdDelimiter) : ''; - } - if (!rel || dt != relDate) { - var el = this.getDayEl(dt); - if (el && this.dayOverClass != '') { - el[type == 'over' ? 'addClass': 'removeClass'](this.dayOverClass); - } - this.fireEvent('day' + type, this, Date.parseDate(dt, "Ymd"), el); - } - } - } - }, - - // private - renderItems: function() { - throw 'This method must be implemented by a subclass'; - } -}); -/** - * @class Ext.calendar.MonthView - * @extends Ext.calendar.CalendarView - *

Displays a calendar view by month. This class does not usually need ot be used directly as you can - * use a {@link Ext.calendar.CalendarPanel CalendarPanel} to manage multiple calendar views at once including - * the month view.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.MonthView = Ext.extend(Ext.calendar.CalendarView, { - /** - * @cfg {Boolean} showTime - * True to display the current time in today's box in the calendar, false to not display it (defautls 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 (defautls to true) - */ - showTodayText: 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 {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 {@link Ext.calendar.WeekView view} - * for each individual week, false to not show it (defaults to false). 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', - - //private properties -- do not override: - daySelector: '.ext-cal-day', - moreSelector: '.ext-cal-ev-more', - weekLinkSelector: '.ext-cal-week-link', - weekCount: -1, - // defaults to auto by month - dayCount: 7, - moreElIdDelimiter: '-more-', - weekLinkIdDelimiter: 'ext-cal-week-', - - // private - initComponent: function() { - Ext.calendar.MonthView.superclass.initComponent.call(this); - this.addEvents({ - /** - * @event dayclick - * Fires after the user clicks within the view container and not on an event element - * @param {Ext.calendar.MonthView} 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 {Ext.calendar.MonthView} this - * @param {Date} dt The start date of the week that was clicked on - */ - weekclick: true, - // inherited docs - dayover: true, - // inherited docs - dayout: true - }); - }, - - // private - initDD: function() { - var cfg = { - view: this, - createText: this.ddCreateEventText, - moveText: this.ddMoveEventText, - ddGroup: 'MonthViewDD' - }; - - this.dragZone = new Ext.calendar.DragZone(this.el, cfg); - this.dropZone = new Ext.calendar.DropZone(this.el, cfg); - }, - - // private - onDestroy: function() { - Ext.destroy(this.ddSelector); - Ext.destroy(this.dragZone); - Ext.destroy(this.dropZone); - Ext.calendar.MonthView.superclass.onDestroy.call(this); - }, - - // private - afterRender: function() { - if (!this.tpl) { - this.tpl = new Ext.calendar.MonthViewTemplate({ - id: this.id, - showTodayText: this.showTodayText, - todayText: this.todayText, - showTime: this.showTime, - showHeader: this.showHeader, - showWeekLinks: this.showWeekLinks, - showWeekNumbers: this.showWeekNumbers - }); - } - this.tpl.compile(); - this.addClass('ext-cal-monthview ext-cal-ct'); - - Ext.calendar.MonthView.superclass.afterRender.call(this); - }, - - // private - onResize: function() { - if (this.monitorResize) { - this.maxEventsPerDay = this.getMaxEventsPerDay(); - this.refresh(); - } - }, - - // private - forceSize: function() { - // Compensate for the week link gutter width if visible - if (this.showWeekLinks && this.el && this.el.child) { - var hd = this.el.select('.ext-cal-hd-days-tbl'), - bgTbl = this.el.select('.ext-cal-bg-tbl'), - evTbl = this.el.select('.ext-cal-evt-tbl'), - wkLinkW = this.el.child('.ext-cal-week-link').getWidth(), - w = this.el.getWidth() - wkLinkW; - - hd.setWidth(w); - bgTbl.setWidth(w); - evTbl.setWidth(w); - } - Ext.calendar.MonthView.superclass.forceSize.call(this); - }, - - //private - initClock: function() { - if (Ext.fly(this.id + '-clock') !== null) { - this.prevClockDay = new Date().getDay(); - if (this.clockTask) { - Ext.TaskMgr.stop(this.clockTask); - } - this.clockTask = Ext.TaskMgr.start({ - run: function() { - var el = Ext.fly(this.id + '-clock'), - t = new Date(); - - if (t.getDay() == this.prevClockDay) { - if (el) { - el.update(t.format('g:i a')); - } - } - else { - this.prevClockDay = t.getDay(); - this.moveTo(t); - } - }, - scope: this, - interval: 1000 - }); - } - }, - - // inherited docs - getEventBodyMarkup: function() { - if (!this.eventBodyMarkup) { - this.eventBodyMarkup = ['{Title}', - '', - ' ', - '', - '', - ' ', - '', - '', - ' ', - '', - '', - ' ', - '' - ].join(''); - } - return this.eventBodyMarkup; - }, - - // inherited docs - getEventTemplate: function() { - if (!this.eventTpl) { - var tpl, - body = this.getEventBodyMarkup(); - - tpl = !(Ext.isIE || Ext.isOpera) ? - new Ext.XTemplate( - '
', - body, - '
' - ) - : new Ext.XTemplate( - '', - '
', - '
', - '
', - '', - '', - '
', - '', - body, - '', - '
', - '
', - '', - '
' - ); - tpl.compile(); - this.eventTpl = tpl; - } - return this.eventTpl; - }, - - // private - getTemplateEventData: function(evt) { - var M = Ext.calendar.EventMappings, - selector = this.getEventSelectorCls(evt[M.EventId.name]), - title = evt[M.Title.name]; - - return Ext.applyIf({ - _selectorCls: selector, - _colorCls: 'ext-color-' + (evt[M.CalendarId.name] ? - evt[M.CalendarId.name] : 'default') + (evt._renderAsAllDay ? '-ad': ''), - _elId: selector + '-' + evt._weekIndex, - _isRecurring: evt.Recurrence && evt.Recurrence != '', - _isReminder: evt[M.Reminder.name] && evt[M.Reminder.name] != '', - Title: (evt[M.IsAllDay.name] ? '': evt[M.StartDate.name].format('g:ia ')) + (!title || title.length == 0 ? '(No title)': title) - }, - evt); - }, - - // private - refresh: function() { - if (this.detailPanel) { - this.detailPanel.hide(); - } - Ext.calendar.MonthView.superclass.refresh.call(this); - - if (this.showTime !== false) { - this.initClock(); - } - }, - - // private - renderItems: function() { - Ext.calendar.WeekEventRenderer.render({ - eventGrid: this.allDayOnly ? this.allDayGrid: this.eventGrid, - viewStart: this.viewStart, - tpl: this.getEventTemplate(), - maxEventsPerDay: this.maxEventsPerDay, - id: this.id, - templateDataFn: this.getTemplateEventData.createDelegate(this), - evtMaxCount: this.evtMaxCount, - weekCount: this.weekCount, - dayCount: this.dayCount - }); - this.fireEvent('eventsrendered', this); - }, - - // private - getDayEl: function(dt) { - return Ext.get(this.getDayId(dt)); - }, - - // private - getDayId: function(dt) { - if (Ext.isDate(dt)) { - dt = dt.format('Ymd'); - } - return this.id + this.dayElIdDelimiter + dt; - }, - - // private - getWeekIndex: function(dt) { - var el = this.getDayEl(dt).up('.ext-cal-wk-ct'); - return parseInt(el.id.split('-wk-')[1], 10); - }, - - // private - getDaySize: function(contentOnly) { - var box = this.el.getBox(), - w = box.width / this.dayCount, - h = box.height / this.getWeekCount(); - - if (contentOnly) { - var hd = this.el.select('.ext-cal-dtitle').first().parent('tr'); - h = hd ? h - hd.getHeight(true) : h; - } - return { - height: h, - width: w - }; - }, - - // private - getEventHeight: function() { - if (!this.eventHeight) { - var evt = this.el.select('.ext-cal-evt').first(); - this.eventHeight = evt ? evt.parent('tr').getHeight() : 18; - } - return this.eventHeight; - }, - - // private - getMaxEventsPerDay: function() { - var dayHeight = this.getDaySize(true).height, - h = this.getEventHeight(), - max = Math.max(Math.floor((dayHeight - h) / h), 0); - - return max; - }, - - // private - getDayAt: function(x, y) { - var box = this.el.getBox(), - daySize = this.getDaySize(), - dayL = Math.floor(((x - box.x) / daySize.width)), - dayT = Math.floor(((y - box.y) / daySize.height)), - days = (dayT * 7) + dayL, - dt = this.viewStart.add(Date.DAY, days); - return { - date: dt, - el: this.getDayEl(dt) - }; - }, - - // inherited docs - moveNext: function() { - return this.moveMonths(1); - }, - - // inherited docs - movePrev: function() { - return this.moveMonths( - 1); - }, - - // private - onInitDrag: function() { - Ext.calendar.MonthView.superclass.onInitDrag.call(this); - Ext.select(this.daySelector).removeClass(this.dayOverClass); - if (this.detailPanel) { - this.detailPanel.hide(); - } - }, - - // private - onMoreClick: function(dt) { - if (!this.detailPanel) { - this.detailPanel = new Ext.Panel({ - id: this.id + '-details-panel', - title: dt.format('F j'), - layout: 'fit', - floating: true, - renderTo: Ext.getBody(), - tools: [{ - id: 'close', - handler: function(e, t, p) { - p.hide(); - } - }], - items: { - xtype: 'monthdaydetailview', - id: this.id + '-details-view', - date: dt, - view: this, - store: this.store, - listeners: { - 'eventsrendered': this.onDetailViewUpdated.createDelegate(this) - } - } - }); - } - else { - this.detailPanel.setTitle(dt.format('F j')); - } - this.detailPanel.getComponent(this.id + '-details-view').update(dt); - }, - - // private - onDetailViewUpdated: function(view, dt, numEvents) { - var p = this.detailPanel, - frameH = p.getFrameHeight(), - evtH = this.getEventHeight(), - bodyH = frameH + (numEvents * evtH) + 3, - dayEl = this.getDayEl(dt), - box = dayEl.getBox(); - - p.updateBox(box); - p.setHeight(bodyH); - p.setWidth(Math.max(box.width, 220)); - p.show(); - p.getPositionEl().alignTo(dayEl, 't-t?'); - }, - - // private - onHide: function() { - Ext.calendar.MonthView.superclass.onHide.call(this); - if (this.detailPanel) { - this.detailPanel.hide(); - } - }, - - // private - onClick: function(e, t) { - if (this.detailPanel) { - this.detailPanel.hide(); - } - if (Ext.calendar.MonthView.superclass.onClick.apply(this, arguments)) { - // The superclass handled the click already so exit - return; - } - if (this.dropZone) { - this.dropZone.clearShims(); - } - var el = e.getTarget(this.weekLinkSelector, 3), - dt, - parts; - if (el) { - dt = el.id.split(this.weekLinkIdDelimiter)[1]; - this.fireEvent('weekclick', this, Date.parseDate(dt, 'Ymd')); - return; - } - el = e.getTarget(this.moreSelector, 3); - if (el) { - dt = el.id.split(this.moreElIdDelimiter)[1]; - this.onMoreClick(Date.parseDate(dt, 'Ymd')); - return; - } - el = e.getTarget('td', 3); - if (el) { - if (el.id && el.id.indexOf(this.dayElIdDelimiter) > -1) { - parts = el.id.split(this.dayElIdDelimiter); - dt = parts[parts.length - 1]; - - this.fireEvent('dayclick', this, Date.parseDate(dt, 'Ymd'), false, Ext.get(this.getDayId(dt))); - return; - } - } - }, - - // private - handleDayMouseEvent: function(e, t, type) { - var el = e.getTarget(this.weekLinkSelector, 3, true); - if (el) { - el[type == 'over' ? 'addClass': 'removeClass'](this.weekLinkOverClass); - return; - } - Ext.calendar.MonthView.superclass.handleDayMouseEvent.apply(this, arguments); - } -}); - -Ext.reg('monthview', Ext.calendar.MonthView); -/** - * @class Ext.calendar.DayHeaderView - * @extends Ext.calendar.MonthView - *

This is the header area container within the day and week views where all-day events are displayed. - * Normally you should not need to use this class directly -- instead you should use {@link Ext.calendar.DayView DayView} - * which aggregates this class and the {@link Ext.calendar.DayBodyView DayBodyView} into the single unified view - * presented by {@link Ext.calendar.CalendarPanel CalendarPanel}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DayHeaderView = Ext.extend(Ext.calendar.MonthView, { - // private configs - weekCount: 1, - dayCount: 1, - allDayOnly: true, - monitorResize: false, - - /** - * @event dayclick - * Fires after the user clicks within the day view container and not on an event element - * @param {Ext.calendar.DayBodyView} 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 - * DayHeaderView always return true for this param. - * @param {Ext.Element} el The Element that was clicked on - */ - - // private - afterRender: function() { - if (!this.tpl) { - this.tpl = new Ext.calendar.DayHeaderTemplate({ - id: this.id, - showTodayText: this.showTodayText, - todayText: this.todayText, - showTime: this.showTime - }); - } - this.tpl.compile(); - this.addClass('ext-cal-day-header'); - - Ext.calendar.DayHeaderView.superclass.afterRender.call(this); - }, - - // private - forceSize: Ext.emptyFn, - - // private - refresh: function() { - Ext.calendar.DayHeaderView.superclass.refresh.call(this); - this.recalcHeaderBox(); - }, - - // private - recalcHeaderBox: function() { - var tbl = this.el.child('.ext-cal-evt-tbl'), - h = tbl.getHeight(); - - this.el.setHeight(h + 7); - - if (Ext.isIE && Ext.isStrict) { - this.el.child('.ext-cal-hd-ad-inner').setHeight(h + 4); - } - if (Ext.isOpera) { - //TODO: figure out why Opera refuses to refresh height when - //the new height is lower than the previous one - // var ct = this.el.child('.ext-cal-hd-ct'); - // ct.repaint(); - } - }, - - // private - moveNext: function(noRefresh) { - this.moveDays(this.dayCount, noRefresh); - }, - - // private - movePrev: function(noRefresh) { - this.moveDays( - this.dayCount, noRefresh); - }, - - // private - onClick: function(e, t) { - var el = e.getTarget('td', 3), - parts, - dt; - if (el) { - if (el.id && el.id.indexOf(this.dayElIdDelimiter) > -1) { - parts = el.id.split(this.dayElIdDelimiter); - dt = parts[parts.length - 1]; - - this.fireEvent('dayclick', this, Date.parseDate(dt, 'Ymd'), true, Ext.get(this.getDayId(dt))); - return; - } - } - Ext.calendar.DayHeaderView.superclass.onClick.apply(this, arguments); - } -}); - -Ext.reg('dayheaderview', Ext.calendar.DayHeaderView); -/**S - * @class Ext.calendar.DayBodyView - * @extends Ext.calendar.CalendarView - *

This is the scrolling container within the day and week views where non-all-day events are displayed. - * Normally you should not need to use this class directly -- instead you should use {@link Ext.calendar.DayView DayView} - * which aggregates this class and the {@link Ext.calendar.DayHeaderView DayHeaderView} into the single unified view - * presented by {@link Ext.calendar.CalendarPanel CalendarPanel}.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DayBodyView = Ext.extend(Ext.calendar.CalendarView, { - //private - dayColumnElIdDelimiter: '-day-col-', - - //private - initComponent: function() { - Ext.calendar.DayBodyView.superclass.initComponent.call(this); - - this.addEvents({ - /** - * @event eventresize - * Fires after the user drags the resize handle of an event to resize it - * @param {Ext.calendar.DayBodyView} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 day view container and not on an event element - * @param {Ext.calendar.DayBodyView} 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 - }); - }, - - //private - initDD: function() { - var cfg = { - createText: this.ddCreateEventText, - moveText: this.ddMoveEventText, - resizeText: this.ddResizeEventText - }; - - this.el.ddScrollConfig = { - // scrolling is buggy in IE/Opera for some reason. A larger vthresh - // makes it at least functional if not perfect - vthresh: Ext.isIE || Ext.isOpera ? 100: 40, - hthresh: -1, - frequency: 50, - increment: 100, - ddGroup: 'DayViewDD' - }; - this.dragZone = new Ext.calendar.DayViewDragZone(this.el, Ext.apply({ - view: this, - containerScroll: true - }, - cfg)); - - this.dropZone = new Ext.calendar.DayViewDropZone(this.el, Ext.apply({ - view: this - }, - cfg)); - }, - - //private - refresh: function() { - var top = this.el.getScroll().top; - this.prepareData(); - this.renderTemplate(); - this.renderItems(); - - // skip this if the initial render scroll position has not yet been set. - // necessary since IE/Opera must be deferred, so the first refresh will - // override the initial position by default and always set it to 0. - if (this.scrollReady) { - this.scrollTo(top); - } - }, - - /** - * Scrolls the container to the specified vertical position. If the view is large enough that - * there is no scroll overflow then this method will have no affect. - * @param {Number} y The new vertical scroll position in pixels - * @param {Boolean} defer (optional)

True to slightly defer the call, false to execute immediately.

- *

This method will automatically defer itself for IE and Opera (even if you pass false) otherwise - * the scroll position will not update in those browsers. You can optionally pass true, however, to - * force the defer in all browsers, or use your own custom conditions to determine whether this is needed.

- *

Note that this method should not generally need to be called directly as scroll position is managed internally.

- */ - scrollTo: function(y, defer) { - defer = defer || (Ext.isIE || Ext.isOpera); - if (defer) { - (function() { - this.el.scrollTo('top', y); - this.scrollReady = true; - }).defer(10, this); - } - else { - this.el.scrollTo('top', y); - this.scrollReady = true; - } - }, - - // private - afterRender: function() { - if (!this.tpl) { - this.tpl = new Ext.calendar.DayBodyTemplate({ - id: this.id, - dayCount: this.dayCount, - showTodayText: this.showTodayText, - todayText: this.todayText, - showTime: this.showTime - }); - } - this.tpl.compile(); - - this.addClass('ext-cal-body-ct'); - - Ext.calendar.DayBodyView.superclass.afterRender.call(this); - - // default scroll position to 7am: - this.scrollTo(7 * 42); - }, - - // private - forceSize: Ext.emptyFn, - - // private - onEventResize: function(rec, data) { - var D = Ext.calendar.Date, - start = Ext.calendar.EventMappings.StartDate.name, - end = Ext.calendar.EventMappings.EndDate.name; - - if (D.compare(rec.data[start], data.StartDate) === 0 && - D.compare(rec.data[end], data.EndDate) === 0) { - // no changes - return; - } - rec.set(start, data.StartDate); - rec.set(end, data.EndDate); - - this.fireEvent('eventresize', this, rec); - }, - - // inherited docs - getEventBodyMarkup: function() { - if (!this.eventBodyMarkup) { - this.eventBodyMarkup = ['{Title}', - '', - ' ', - '', - '', - ' ', - '' - // '', - // ' ', - // '', - // '', - // ' ', - // '' - ].join(''); - } - return this.eventBodyMarkup; - }, - - // inherited docs - getEventTemplate: function() { - if (!this.eventTpl) { - this.eventTpl = !(Ext.isIE || Ext.isOpera) ? - new Ext.XTemplate( - '
', - '
', this.getEventBodyMarkup(), '
', - '
 
', - '
' - ) - : new Ext.XTemplate( - '
', - '
 
', - '
', - '
', - this.getEventBodyMarkup(), - '
', - '
 
', - '
', - '
 
', - '
' - ); - this.eventTpl.compile(); - } - return this.eventTpl; - }, - - /** - *

Returns the XTemplate that is bound to the calendar's event store (it expects records of type - * {@link Ext.calendar.EventRecord}) to populate the calendar views with all-day events. - * Internally this method by default generates different markup for browsers that support CSS border radius - * and those that don't. This method can be overridden as needed to customize the markup generated.

- *

Note that this method calls {@link #getEventBodyMarkup} to retrieve the body markup for events separately - * from the surrounding container markup. This provdes the flexibility to customize what's in the body without - * having to override the entire XTemplate. If you do override this method, you should make sure that your - * overridden version also does the same.

- * @return {Ext.XTemplate} The event XTemplate - */ - getEventAllDayTemplate: function() { - if (!this.eventAllDayTpl) { - var tpl, - body = this.getEventBodyMarkup(); - - tpl = !(Ext.isIE || Ext.isOpera) ? - new Ext.XTemplate( - '
', - body, - '
' - ) - : new Ext.XTemplate( - '
', - '
', - '
', - '
', - body, - '
', - '
', - '
' - ); - tpl.compile(); - this.eventAllDayTpl = tpl; - } - return this.eventAllDayTpl; - }, - - // private - getTemplateEventData: function(evt) { - var selector = this.getEventSelectorCls(evt[Ext.calendar.EventMappings.EventId.name]), - data = {}, - M = Ext.calendar.EventMappings; - - this.getTemplateEventBox(evt); - - data._selectorCls = selector; - data._colorCls = 'ext-color-' + evt[M.CalendarId.name] + (evt._renderAsAllDay ? '-ad': ''); - data._elId = selector + (evt._weekIndex ? '-' + evt._weekIndex: ''); - data._isRecurring = evt.Recurrence && evt.Recurrence != ''; - data._isReminder = evt[M.Reminder.name] && evt[M.Reminder.name] != ''; - var title = evt[M.Title.name]; - data.Title = (evt[M.IsAllDay.name] ? '': evt[M.StartDate.name].format('g:ia ')) + (!title || title.length == 0 ? '(No title)': title); - - return Ext.applyIf(data, evt); - }, - - // private - getTemplateEventBox: function(evt) { - var heightFactor = 0.7, - start = evt[Ext.calendar.EventMappings.StartDate.name], - end = evt[Ext.calendar.EventMappings.EndDate.name], - startMins = start.getHours() * 60 + start.getMinutes(), - endMins = end.getHours() * 60 + end.getMinutes(), - diffMins = endMins - startMins; - - evt._left = 0; - evt._width = 100; - evt._top = Math.round(startMins * heightFactor) + 1; - evt._height = Math.max((diffMins * heightFactor) - 2, 15); - }, - - // private - renderItems: function() { - var day = 0, - evts = [], - ev, - d, - ct, - item, - i, - j, - l, - overlapCols, - prevCol, - colWidth, - evtWidth, - markup, - target; - for (; day < this.dayCount; day++) { - ev = emptyCells = skipped = 0; - d = this.eventGrid[0][day]; - ct = d ? d.length: 0; - - for (; ev < ct; ev++) { - evt = d[ev]; - if (!evt) { - continue; - } - item = evt.data || evt.event.data; - if (item._renderAsAllDay) { - continue; - } - Ext.apply(item, { - cls: 'ext-cal-ev', - _positioned: true - }); - evts.push({ - data: this.getTemplateEventData(item), - date: this.viewStart.add(Date.DAY, day) - }); - } - } - - // overlapping event pre-processing loop - i = j = overlapCols = prevCol = 0; - l = evts.length; - for (; i < l; i++) { - evt = evts[i].data; - evt2 = null; - prevCol = overlapCols; - for (j = 0; j < l; j++) { - if (i == j) { - continue; - } - evt2 = evts[j].data; - if (this.isOverlapping(evt, evt2)) { - evt._overlap = evt._overlap == undefined ? 1: evt._overlap + 1; - if (i < j) { - if (evt._overcol === undefined) { - evt._overcol = 0; - } - evt2._overcol = evt._overcol + 1; - overlapCols = Math.max(overlapCols, evt2._overcol); - } - } - } - } - - // rendering loop - for (i = 0; i < l; i++) { - evt = evts[i].data; - if (evt._overlap !== undefined) { - colWidth = 100 / (overlapCols + 1); - evtWidth = 100 - (colWidth * evt._overlap); - - evt._width = colWidth; - evt._left = colWidth * evt._overcol; - } - markup = this.getEventTemplate().apply(evt); - target = this.id + '-day-col-' + evts[i].date.format('Ymd'); - - Ext.DomHelper.append(target, markup); - } - - this.fireEvent('eventsrendered', this); - }, - - // private - getDayEl: function(dt) { - return Ext.get(this.getDayId(dt)); - }, - - // private - getDayId: function(dt) { - if (Ext.isDate(dt)) { - dt = dt.format('Ymd'); - } - return this.id + this.dayColumnElIdDelimiter + dt; - }, - - // private - getDaySize: function() { - var box = this.el.child('.ext-cal-day-col-inner').getBox(); - return { - height: box.height, - width: box.width - }; - }, - - // private - getDayAt: function(x, y) { - var sel = '.ext-cal-body-ct', - xoffset = this.el.child('.ext-cal-day-times').getWidth(), - viewBox = this.el.getBox(), - daySize = this.getDaySize(false), - relX = x - viewBox.x - xoffset, - dayIndex = Math.floor(relX / daySize.width), - // clicked col index - scroll = this.el.getScroll(), - row = this.el.child('.ext-cal-bg-row'), - // first avail row, just to calc size - rowH = row.getHeight() / 2, - // 30 minute increment since a row is 60 minutes - relY = y - viewBox.y - rowH + scroll.top, - rowIndex = Math.max(0, Math.ceil(relY / rowH)), - mins = rowIndex * 30, - dt = this.viewStart.add(Date.DAY, dayIndex).add(Date.MINUTE, mins), - el = this.getDayEl(dt), - timeX = x; - - if (el) { - timeX = el.getLeft(); - } - - return { - date: dt, - el: el, - // this is the box for the specific time block in the day that was clicked on: - timeBox: { - x: timeX, - y: (rowIndex * 21) + viewBox.y - scroll.top, - width: daySize.width, - height: rowH - } - }; - }, - - // private - onClick: function(e, t) { - if (this.dragPending || Ext.calendar.DayBodyView.superclass.onClick.apply(this, arguments)) { - // The superclass handled the click already so exit - return; - } - if (e.getTarget('.ext-cal-day-times', 3) !== null) { - // ignore clicks on the times-of-day gutter - return; - } - var el = e.getTarget('td', 3); - if (el) { - if (el.id && el.id.indexOf(this.dayElIdDelimiter) > -1) { - var dt = this.getDateFromId(el.id, this.dayElIdDelimiter); - this.fireEvent('dayclick', this, Date.parseDate(dt, 'Ymd'), true, Ext.get(this.getDayId(dt, true))); - return; - } - } - var day = this.getDayAt(e.xy[0], e.xy[1]); - if (day && day.date) { - this.fireEvent('dayclick', this, day.date, false, null); - } - } -}); - -Ext.reg('daybodyview', Ext.calendar.DayBodyView); -/** - * @class Ext.calendar.DayView - * @extends Ext.Container - *

Unlike other calendar views, is not actually a subclass of {@link Ext.calendar.CalendarView CalendarView}. - * Instead it is a {@link Ext.Container Container} subclass that internally creates and manages the layouts of - * a {@link Ext.calendar.DayHeaderView DayHeaderView} and a {@link Ext.calendar.DayBodyView DayBodyView}. As such - * DayView accepts any config values that are valid for DayHeaderView and DayBodyView and passes those through - * to the contained views. It also supports the interface required of any calendar view and in turn calls methods - * on the contained views as necessary.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DayView = Ext.extend(Ext.Container, { - /** - * @cfg {Boolean} showTime - * True to display the current time in today's box in the calendar, false to not display it (defautls 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 (defautls to true) - */ - showTodayText: 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} 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 {Number} dayCount - * The number of days to display in the view (defaults to 1) - */ - dayCount: 1, - - // private - initComponent : function(){ - // rendering more than 7 days per view is not supported - this.dayCount = this.dayCount > 7 ? 7 : this.dayCount; - - var cfg = Ext.apply({}, this.initialConfig); - cfg.showTime = this.showTime; - cfg.showTodatText = this.showTodayText; - cfg.todayText = this.todayText; - cfg.dayCount = this.dayCount; - cfg.wekkCount = 1; - - var header = Ext.applyIf({ - xtype: 'dayheaderview', - id: this.id+'-hd' - }, cfg); - - var body = Ext.applyIf({ - xtype: 'daybodyview', - id: this.id+'-bd' - }, cfg); - - this.items = [header, body]; - this.addClass('ext-cal-dayview ext-cal-ct'); - - Ext.calendar.DayView.superclass.initComponent.call(this); - }, - - // private - afterRender : function(){ - Ext.calendar.DayView.superclass.afterRender.call(this); - - this.header = Ext.getCmp(this.id+'-hd'); - this.body = Ext.getCmp(this.id+'-bd'); - this.body.on('eventsrendered', this.forceSize, this); - }, - - // private - refresh : function(){ - this.header.refresh(); - this.body.refresh(); - }, - - // private - forceSize: function(){ - // The defer call is mainly for good ol' IE, but it doesn't hurt in - // general to make sure that the window resize is good and done first - // so that we can properly calculate sizes. - (function(){ - var ct = this.el.up('.x-panel-body'), - hd = this.el.child('.ext-cal-day-header'), - h = ct.getHeight() - hd.getHeight(); - - this.el.child('.ext-cal-body-ct').setHeight(h); - }).defer(10, this); - }, - - // private - onResize : function(){ - this.forceSize(); - }, - - // private - getViewBounds : function(){ - return this.header.getViewBounds(); - }, - - /** - * Returns the start date of the view, as set by {@link #setStartDate}. Note that this may not - * be the first date displayed in the rendered calendar -- to get the start and end dates displayed - * to the user use {@link #getViewBounds}. - * @return {Date} The start date - */ - getStartDate : function(){ - return this.header.getStartDate(); - }, - - /** - * Sets the start date used to calculate the view boundaries to display. The displayed view will be the - * earliest and latest dates that match the view requirements and contain the date passed to this function. - * @param {Date} dt The date used to calculate the new view boundaries - */ - setStartDate: function(dt){ - this.header.setStartDate(dt, true); - this.body.setStartDate(dt, true); - }, - - // private - renderItems: function(){ - this.header.renderItems(); - this.body.renderItems(); - }, - - /** - * Returns true if the view is currently displaying today's date, else false. - * @return {Boolean} True or false - */ - isToday : function(){ - return this.header.isToday(); - }, - - /** - * Updates the view to contain the passed date - * @param {Date} dt The date to display - */ - moveTo : function(dt, noRefresh){ - this.header.moveTo(dt, noRefresh); - this.body.moveTo(dt, noRefresh); - }, - - /** - * Updates the view to the next consecutive date(s) - */ - moveNext : function(noRefresh){ - this.header.moveNext(noRefresh); - this.body.moveNext(noRefresh); - }, - - /** - * Updates the view to the previous consecutive date(s) - */ - movePrev : function(noRefresh){ - this.header.movePrev(noRefresh); - this.body.movePrev(noRefresh); - }, - - /** - * Shifts the view by the passed number of days relative to the currently set date - * @param {Number} value The number of days (positive or negative) by which to shift the view - */ - moveDays : function(value, noRefresh){ - this.header.moveDays(value, noRefresh); - this.body.moveDays(value, noRefresh); - }, - - /** - * Updates the view to show today - */ - moveToday : function(noRefresh){ - this.header.moveToday(noRefresh); - this.body.moveToday(noRefresh); - } -}); - -Ext.reg('dayview', Ext.calendar.DayView); -/** - * @class Ext.calendar.WeekView - * @extends Ext.calendar.DayView - *

Displays a calendar view by week. This class does not usually need ot be used directly as you can - * use a {@link Ext.calendar.CalendarPanel CalendarPanel} to manage multiple calendar views at once including - * the week view.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.WeekView = Ext.extend(Ext.calendar.DayView, { - /** - * @cfg {Number} dayCount - * The number of days to display in the view (defaults to 7) - */ - dayCount: 7 -}); - -Ext.reg('weekview', Ext.calendar.WeekView);/** - * @class Ext.calendar.DateRangeField - * @extends Ext.form.Field - *

A combination field that includes start and end dates and times, as well as an optional all-day checkbox.

- * @constructor - * @param {Object} config The config object - */ -Ext.calendar.DateRangeField = Ext.extend(Ext.form.Field, { - /** - * @cfg {String} toText - * The text to display in between the date/time fields (defaults to 'to') - */ - toText: 'to', - /** - * @cfg {String} toText - * The text to display as the label for the all day checkbox (defaults to 'All day') - */ - allDayText: 'All day', - - // private - onRender: function(ct, position) { - if (!this.el) { - this.startDate = new Ext.form.DateField({ - id: this.id + '-start-date', - format: 'n/j/Y', - width: 100, - listeners: { - 'change': { - fn: function() { - this.checkDates('date', 'start'); - }, - scope: this - } - } - }); - this.startTime = new Ext.form.TimeField({ - id: this.id + '-start-time', - hidden: this.showTimes === false, - labelWidth: 0, - hideLabel: true, - width: 90, - listeners: { - 'select': { - fn: function() { - this.checkDates('time', 'start'); - }, - scope: this - } - } - }); - this.endTime = new Ext.form.TimeField({ - id: this.id + '-end-time', - hidden: this.showTimes === false, - labelWidth: 0, - hideLabel: true, - width: 90, - listeners: { - 'select': { - fn: function() { - this.checkDates('time', 'end'); - }, - scope: this - } - } - }); - this.endDate = new Ext.form.DateField({ - id: this.id + '-end-date', - format: 'n/j/Y', - hideLabel: true, - width: 100, - listeners: { - 'change': { - fn: function() { - this.checkDates('date', 'end'); - }, - scope: this - } - } - }); - this.allDay = new Ext.form.Checkbox({ - id: this.id + '-allday', - hidden: this.showTimes === false || this.showAllDay === false, - boxLabel: this.allDayText, - handler: function(chk, checked) { - this.startTime.setVisible(!checked); - this.endTime.setVisible(!checked); - }, - scope: this - }); - this.toLabel = new Ext.form.Label({ - xtype: 'label', - id: this.id + '-to-label', - text: this.toText - }); - - this.fieldCt = new Ext.Container({ - autoEl: { - id: this.id - }, - //make sure the container el has the field's id - cls: 'ext-dt-range', - renderTo: ct, - layout: 'table', - layoutConfig: { - columns: 6 - }, - defaults: { - hideParent: true - }, - items: [ - this.startDate, - this.startTime, - this.toLabel, - this.endTime, - this.endDate, - this.allDay - ] - }); - - this.fieldCt.ownerCt = this; - this.el = this.fieldCt.getEl(); - this.items = new Ext.util.MixedCollection(); - this.items.addAll([this.startDate, this.endDate, this.toLabel, this.startTime, this.endTime, this.allDay]); - } - Ext.calendar.DateRangeField.superclass.onRender.call(this, ct, position); - }, - - // private - checkDates: function(type, startend) { - var startField = Ext.getCmp(this.id + '-start-' + type), - endField = Ext.getCmp(this.id + '-end-' + type), - startValue = this.getDT('start'), - endValue = this.getDT('end'); - - if (startValue > endValue) { - if (startend == 'start') { - endField.setValue(startValue); - } else { - startField.setValue(endValue); - this.checkDates(type, 'start'); - } - } - if (type == 'date') { - this.checkDates('time', startend); - } - }, - - /** - * Returns an array containing the following values in order:
    - *
  • DateTime :
    The start date/time
  • - *
  • DateTime :
    The end date/time
  • - *
  • Boolean :
    True if the dates are all-day, false - * if the time values should be used
    - * @return {Array} The array of return values - */ - getValue: function() { - return [ - this.getDT('start'), - this.getDT('end'), - this.allDay.getValue() - ]; - }, - - // private getValue helper - getDT: function(startend) { - var time = this[startend + 'Time'].getValue(), - dt = this[startend + 'Date'].getValue(); - - if (Ext.isDate(dt)) { - dt = dt.format(this[startend + 'Date'].format); - } - else { - return null; - }; - if (time != '' && this[startend + 'Time'].isVisible()) { - return Date.parseDate(dt + ' ' + time, this[startend + 'Date'].format + ' ' + this[startend + 'Time'].format); - } - return Date.parseDate(dt, this[startend + 'Date'].format); - - }, - - /** - * Sets the values to use in the date range. - * @param {Array/Date/Object} v The value(s) to set into the field. Valid types are as follows:
      - *
    • Array :
      An array containing, in order, a start date, end date and all-day flag. - * This array should exactly match the return type as specified by {@link #getValue}.
    • - *
    • DateTime :
      A single Date object, which will be used for both the start and - * end dates in the range. The all-day flag will be defaulted to false.
    • - *
    • Object :
      An object containing properties for StartDate, EndDate and IsAllDay - * as defined in {@link Ext.calendar.EventMappings}.
      - */ - setValue: function(v) { - if (Ext.isArray(v)) { - this.setDT(v[0], 'start'); - this.setDT(v[1], 'end'); - this.allDay.setValue( !! v[2]); - } - else if (Ext.isDate(v)) { - this.setDT(v, 'start'); - this.setDT(v, 'end'); - this.allDay.setValue(false); - } - else if (v[Ext.calendar.EventMappings.StartDate.name]) { - //object - this.setDT(v[Ext.calendar.EventMappings.StartDate.name], 'start'); - if (!this.setDT(v[Ext.calendar.EventMappings.EndDate.name], 'end')) { - this.setDT(v[Ext.calendar.EventMappings.StartDate.name], 'end'); - } - this.allDay.setValue( !! v[Ext.calendar.EventMappings.IsAllDay.name]); - } - }, - - // private setValue helper - setDT: function(dt, startend) { - if (dt && Ext.isDate(dt)) { - this[startend + 'Date'].setValue(dt); - this[startend + 'Time'].setValue(dt.format(this[startend + 'Time'].format)); - return true; - } - }, - - // inherited docs - isDirty: function() { - var dirty = false; - if (this.rendered && !this.disabled) { - this.items.each(function(item) { - if (item.isDirty()) { - dirty = true; - return false; - } - }); - } - return dirty; - }, - - // private - onDisable: function() { - this.delegateFn('disable'); - }, - - // private - onEnable: function() { - this.delegateFn('enable'); - }, - - // inherited docs - reset: function() { - this.delegateFn('reset'); - }, - - // private - delegateFn: function(fn) { - this.items.each(function(item) { - if (item[fn]) { - item[fn](); - } - }); - }, - - // private - beforeDestroy: function() { - Ext.destroy(this.fieldCt); - Ext.calendar.DateRangeField.superclass.beforeDestroy.call(this); - }, - - /** - * @method getRawValue - * @hide - */ - getRawValue: Ext.emptyFn, - /** - * @method setRawValue - * @hide - */ - setRawValue: Ext.emptyFn -}); - -Ext.reg('daterangefield', Ext.calendar.DateRangeField); -/** - * @class Ext.calendar.ReminderField - * @extends Ext.form.ComboBox - *

      A custom combo used for choosing a reminder setting for an event.

      - *

      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:

      
      -    width: 200,
      -    fieldLabel: 'Reminder',
      -    mode: 'local',
      -    triggerAction: 'all',
      -    forceSelection: true,
      -    displayField: 'desc',
      -    valueField: 'value'
      -
      - * @constructor - * @param {Object} config The config object - */ -Ext.calendar.ReminderField = Ext.extend(Ext.form.ComboBox, { - width: 200, - fieldLabel: 'Reminder', - mode: 'local', - triggerAction: 'all', - forceSelection: true, - displayField: 'desc', - valueField: 'value', - - // private - initComponent: function() { - Ext.calendar.ReminderField.superclass.initComponent.call(this); - - this.store = this.store || new Ext.data.ArrayStore({ - fields: ['value', 'desc'], - idIndex: 0, - data: [ - ['', 'None'], - ['0', 'At start time'], - ['5', '5 minutes before start'], - ['15', '15 minutes before start'], - ['30', '30 minutes before start'], - ['60', '1 hour before start'], - ['90', '1.5 hours before start'], - ['120', '2 hours before start'], - ['180', '3 hours before start'], - ['360', '6 hours before start'], - ['720', '12 hours before start'], - ['1440', '1 day before start'], - ['2880', '2 days before start'], - ['4320', '3 days before start'], - ['5760', '4 days before start'], - ['7200', '5 days before start'], - ['10080', '1 week before start'], - ['20160', '2 weeks before start'] - ] - }); - }, - - // inherited docs - initValue: function() { - if (this.value !== undefined) { - this.setValue(this.value); - } - else { - this.setValue(''); - } - this.originalValue = this.getValue(); - } -}); - -Ext.reg('reminderfield', Ext.calendar.ReminderField); -/** - * @class Ext.calendar.EventEditForm - * @extends Ext.form.FormPanel - *

      A custom form used for detailed editing of events.

      - *

      This is pretty much a standard form that is simply pre-configured for the options needed by the - * calendar components. It is also configured to automatically bind records of type {@link Ext.calendar.EventRecord} - * to and from the form.

      - *

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

      - *

      The default configs are as follows:

      
      -    labelWidth: 65,
      -    title: 'Event Form',
      -    titleTextAdd: 'Add Event',
      -    titleTextEdit: 'Edit Event',
      -    bodyStyle: 'background:transparent;padding:20px 20px 10px;',
      -    border: false,
      -    buttonAlign: 'center',
      -    autoHeight: true,
      -    cls: 'ext-evt-edit-form',
      -
      - * @constructor - * @param {Object} config The config object - */ -Ext.calendar.EventEditForm = Ext.extend(Ext.form.FormPanel, { - labelWidth: 65, - title: 'Event Form', - titleTextAdd: 'Add Event', - titleTextEdit: 'Edit Event', - bodyStyle: 'background:transparent;padding:20px 20px 10px;', - border: false, - buttonAlign: 'center', - autoHeight: true, - // to allow for the notes field to autogrow - cls: 'ext-evt-edit-form', - - // private properties: - newId: 10000, - layout: 'column', - - // private - initComponent: function() { - - this.addEvents({ - /** - * @event eventadd - * Fires after a new event is added - * @param {Ext.calendar.EventEditForm} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was added - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event is updated - * @param {Ext.calendar.EventEditForm} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was updated - */ - eventupdate: true, - /** - * @event eventdelete - * Fires after an event is deleted - * @param {Ext.calendar.EventEditForm} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord 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 {Ext.calendar.EventEditForm} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was canceled - */ - eventcancel: true - }); - - this.titleField = new Ext.form.TextField({ - fieldLabel: 'Title', - name: Ext.calendar.EventMappings.Title.name, - anchor: '90%' - }); - this.dateRangeField = new Ext.calendar.DateRangeField({ - fieldLabel: 'When', - anchor: '90%' - }); - this.reminderField = new Ext.calendar.ReminderField({ - name: 'Reminder' - }); - this.notesField = new Ext.form.TextArea({ - fieldLabel: 'Notes', - name: Ext.calendar.EventMappings.Notes.name, - grow: true, - growMax: 150, - anchor: '100%' - }); - this.locationField = new Ext.form.TextField({ - fieldLabel: 'Location', - name: Ext.calendar.EventMappings.Location.name, - anchor: '100%' - }); - this.urlField = new Ext.form.TextField({ - fieldLabel: 'Web Link', - name: Ext.calendar.EventMappings.Url.name, - anchor: '100%' - }); - - var leftFields = [this.titleField, this.dateRangeField, this.reminderField], - rightFields = [this.notesField, this.locationField, this.urlField]; - - if (this.calendarStore) { - this.calendarField = new Ext.calendar.CalendarPicker({ - store: this.calendarStore, - name: Ext.calendar.EventMappings.CalendarId.name - }); - leftFields.splice(2, 0, this.calendarField); - }; - - this.items = [{ - id: 'left-col', - columnWidth: 0.65, - layout: 'form', - border: false, - items: leftFields - }, - { - id: 'right-col', - columnWidth: 0.35, - layout: 'form', - border: false, - items: rightFields - }]; - - this.fbar = [{ - text: 'Save', - scope: this, - handler: this.onSave - }, - { - cls: 'ext-del-btn', - text: 'Delete', - scope: this, - handler: this.onDelete - }, - { - text: 'Cancel', - scope: this, - handler: this.onCancel - }]; - - Ext.calendar.EventEditForm.superclass.initComponent.call(this); - }, - - // inherited docs - loadRecord: function(rec) { - this.form.loadRecord.apply(this.form, arguments); - this.activeRecord = rec; - this.dateRangeField.setValue(rec.data); - if (this.calendarStore) { - this.form.setValues({ - 'calendar': rec.data[Ext.calendar.EventMappings.CalendarId.name] - }); - } - this.isAdd = !!rec.data[Ext.calendar.EventMappings.IsNew.name]; - if (this.isAdd) { - rec.markDirty(); - this.setTitle(this.titleTextAdd); - Ext.select('.ext-del-btn').setDisplayed(false); - } - else { - this.setTitle(this.titleTextEdit); - Ext.select('.ext-del-btn').setDisplayed(true); - } - this.titleField.focus(); - }, - - // inherited docs - updateRecord: function() { - var dates = this.dateRangeField.getValue(); - - this.form.updateRecord(this.activeRecord); - this.activeRecord.set(Ext.calendar.EventMappings.StartDate.name, dates[0]); - this.activeRecord.set(Ext.calendar.EventMappings.EndDate.name, dates[1]); - this.activeRecord.set(Ext.calendar.EventMappings.IsAllDay.name, dates[2]); - }, - - // private - onCancel: function() { - this.cleanup(true); - this.fireEvent('eventcancel', this, this.activeRecord); - }, - - // private - cleanup: function(hide) { - if (this.activeRecord && this.activeRecord.dirty) { - this.activeRecord.reject(); - } - delete this.activeRecord; - - if (this.form.isDirty()) { - this.form.reset(); - } - }, - - // private - onSave: function() { - if (!this.form.isValid()) { - return; - } - this.updateRecord(); - - if (!this.activeRecord.dirty) { - this.onCancel(); - return; - } - - this.fireEvent(this.isAdd ? 'eventadd': 'eventupdate', this, this.activeRecord); - }, - - // private - onDelete: function() { - this.fireEvent('eventdelete', this, this.activeRecord); - } -}); - -Ext.reg('eventeditform', Ext.calendar.EventEditForm); -/** - * @class Ext.calendar.EventEditWindow - * @extends Ext.Window - *

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

      - *

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

      - * @constructor - * @param {Object} config The config object - */ -Ext.calendar.EventEditWindow = function(config) { - var formPanelCfg = { - xtype: 'form', - labelWidth: 65, - frame: false, - bodyStyle: 'background:transparent;padding:5px 10px 10px;', - bodyBorder: false, - border: false, - items: [{ - id: 'title', - name: Ext.calendar.EventMappings.Title.name, - fieldLabel: 'Title', - xtype: 'textfield', - anchor: '100%' - }, - { - xtype: 'daterangefield', - id: 'date-range', - anchor: '100%', - fieldLabel: 'When' - }] - }; - - if (config.calendarStore) { - this.calendarStore = config.calendarStore; - delete config.calendarStore; - - formPanelCfg.items.push({ - xtype: 'calendarpicker', - id: 'calendar', - name: 'calendar', - anchor: '100%', - store: this.calendarStore - }); - } - - Ext.calendar.EventEditWindow.superclass.constructor.call(this, Ext.apply({ - titleTextAdd: 'Add Event', - titleTextEdit: 'Edit Event', - width: 600, - autocreate: true, - border: true, - closeAction: 'hide', - modal: false, - resizable: false, - buttonAlign: 'left', - savingMessage: 'Saving changes...', - deletingMessage: 'Deleting event...', - - fbar: [{ - xtype: 'tbtext', - text: 'Edit Details...' - }, - '->', { - text: 'Save', - disabled: false, - handler: this.onSave, - scope: this - }, - { - id: 'delete-btn', - text: 'Delete', - disabled: false, - handler: this.onDelete, - scope: this, - hideMode: 'offsets' - }, - { - text: 'Cancel', - disabled: false, - handler: this.onCancel, - scope: this - }], - items: formPanelCfg - }, - config)); -}; - -Ext.extend(Ext.calendar.EventEditWindow, Ext.Window, { - // private - newId: 10000, - - // private - initComponent: function() { - Ext.calendar.EventEditWindow.superclass.initComponent.call(this); - - this.formPanel = this.items.items[0]; - - this.addEvents({ - /** - * @event eventadd - * Fires after a new event is added - * @param {Ext.calendar.EventEditWindow} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was added - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event is updated - * @param {Ext.calendar.EventEditWindow} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was updated - */ - eventupdate: true, - /** - * @event eventdelete - * Fires after an event is deleted - * @param {Ext.calendar.EventEditWindow} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord 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 {Ext.calendar.EventEditWindow} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was canceled - */ - eventcancel: true, - /** - * @event editdetails - * Fires when the user selects the option in this window to continue editing in the detailed edit form - * (by default, an instance of {@link Ext.calendar.EventEditForm}. Handling code should hide this window - * and transfer the current event record to the appropriate instance of the detailed form by showing it - * and calling {@link Ext.calendar.EventEditForm#loadRecord loadRecord}. - * @param {Ext.calendar.EventEditWindow} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} that is currently being edited - */ - editdetails: true - }); - }, - - // private - afterRender: function() { - Ext.calendar.EventEditWindow.superclass.afterRender.call(this); - - this.el.addClass('ext-cal-event-win'); - - Ext.get('tblink').on('click', - function(e) { - e.stopEvent(); - this.updateRecord(); - this.fireEvent('editdetails', this, this.activeRecord); - }, - this); - }, - - /** - * Shows the window, rendering it first if necessary, or activates it and brings it to front if hidden. - * @param {Ext.data.Record/Object} o Either a {@link Ext.data.Record} if showing the form - * for an existing event in edit mode, or a plain object containing a StartDate property (and - * optionally an EndDate property) for showing the form in add mode. - * @param {String/Element} animateTarget (optional) The target element or id from which the window should - * animate while opening (defaults to null with no animation) - * @return {Ext.Window} this - */ - show: function(o, animateTarget) { - // Work around the CSS day cell height hack needed for initial render in IE8/strict: - var anim = (Ext.isIE8 && Ext.isStrict) ? null: animateTarget; - - Ext.calendar.EventEditWindow.superclass.show.call(this, anim, - function() { - Ext.getCmp('title').focus(false, 100); - }); - Ext.getCmp('delete-btn')[o.data && o.data[Ext.calendar.EventMappings.EventId.name] ? 'show': 'hide'](); - - var rec, - f = this.formPanel.form; - - if (o.data) { - rec = o; - this.isAdd = !!rec.data[Ext.calendar.EventMappings.IsNew.name]; - if (this.isAdd) { - // Enable adding the default record that was passed in - // if it's new even if the user makes no changes - rec.markDirty(); - this.setTitle(this.titleTextAdd); - } - else { - this.setTitle(this.titleTextEdit); - } - - f.loadRecord(rec); - } - else { - this.isAdd = true; - this.setTitle(this.titleTextAdd); - - var M = Ext.calendar.EventMappings, - eventId = M.EventId.name, - start = o[M.StartDate.name], - end = o[M.EndDate.name] || start.add('h', 1); - - rec = new Ext.calendar.EventRecord(); - rec.data[M.EventId.name] = this.newId++; - rec.data[M.StartDate.name] = start; - rec.data[M.EndDate.name] = end; - rec.data[M.IsAllDay.name] = !!o[M.IsAllDay.name] || start.getDate() != end.clone().add(Date.MILLI, 1).getDate(); - rec.data[M.IsNew.name] = true; - - f.reset(); - f.loadRecord(rec); - } - - if (this.calendarStore) { - Ext.getCmp('calendar').setValue(rec.data[Ext.calendar.EventMappings.CalendarId.name]); - } - Ext.getCmp('date-range').setValue(rec.data); - this.activeRecord = rec; - - return this; - }, - - // private - roundTime: function(dt, incr) { - incr = incr || 15; - var m = parseInt(dt.getMinutes(), 10); - return dt.add('mi', incr - (m % incr)); - }, - - // private - onCancel: function() { - this.cleanup(true); - this.fireEvent('eventcancel', this); - }, - - // private - cleanup: function(hide) { - if (this.activeRecord && this.activeRecord.dirty) { - this.activeRecord.reject(); - } - delete this.activeRecord; - - if (hide === true) { - // Work around the CSS day cell height hack needed for initial render in IE8/strict: - //var anim = afterDelete || (Ext.isIE8 && Ext.isStrict) ? null : this.animateTarget; - this.hide(); - } - }, - - // private - updateRecord: function() { - var f = this.formPanel.form, - dates = Ext.getCmp('date-range').getValue(), - M = Ext.calendar.EventMappings; - - f.updateRecord(this.activeRecord); - this.activeRecord.set(M.StartDate.name, dates[0]); - this.activeRecord.set(M.EndDate.name, dates[1]); - this.activeRecord.set(M.IsAllDay.name, dates[2]); - this.activeRecord.set(M.CalendarId.name, this.formPanel.form.findField('calendar').getValue()); - }, - - // private - onSave: function() { - if (!this.formPanel.form.isValid()) { - return; - } - this.updateRecord(); - - if (!this.activeRecord.dirty) { - this.onCancel(); - return; - } - - this.fireEvent(this.isAdd ? 'eventadd': 'eventupdate', this, this.activeRecord); - }, - - // private - onDelete: function() { - this.fireEvent('eventdelete', this, this.activeRecord); - } -});/** - * @class Ext.calendar.CalendarPanel - * @extends Ext.Panel - *

      This is the default container for Ext calendar views. It supports day, week and month views as well - * as a built-in event edit form. The only requirement for displaying a calendar is passing in a valid - * {@link #calendarStore} config containing records of type {@link Ext.calendar.EventRecord EventRecord}. In order - * to make the calendar interactive (enable editing, drag/drop, etc.) you can handle any of the various - * events fired by the underlying views and exposed through the CalendarPanel.

      - * {@link #layoutConfig} option if needed.

      - * @constructor - * @param {Object} config The config object - * @xtype calendarpanel - */ -Ext.calendar.CalendarPanel = Ext.extend(Ext.Panel, { - /** - * @cfg {Boolean} showDayView - * True to include the day view (and toolbar button), false to hide them (defaults to true). - */ - showDayView: true, - /** - * @cfg {Boolean} showWeekView - * True to include the week view (and toolbar button), false to hide them (defaults to true). - */ - showWeekView: true, - /** - * @cfg {Boolean} showMonthView - * True to include the month view (and toolbar button), false to hide them (defaults to true). - * If the day and week views are both hidden, the month view will show by default even if - * this config is false. - */ - showMonthView: true, - /** - * @cfg {Boolean} showNavBar - * True to display the calendar navigation toolbar, false to hide it (defaults to true). Note that - * if you hide the default navigation toolbar you'll have to provide an alternate means of navigating the calendar. - */ - showNavBar: true, - /** - * @cfg {String} todayText - * Alternate text to use for the 'Today' nav bar button. - */ - todayText: 'Today', - /** - * @cfg {Boolean} showTodayText - * True to show the value of {@link #todayText} instead of today's date in the calendar's current day box, - * false to display the day number(defaults to true). - */ - showTodayText: true, - /** - * @cfg {Boolean} showTime - * True to display the current time next to the date in the calendar's current day box, false to not show it - * (defaults to true). - */ - showTime: true, - /** - * @cfg {String} dayText - * Alternate text to use for the 'Day' nav bar button. - */ - dayText: 'Day', - /** - * @cfg {String} weekText - * Alternate text to use for the 'Week' nav bar button. - */ - weekText: 'Week', - /** - * @cfg {String} monthText - * Alternate text to use for the 'Month' nav bar button. - */ - monthText: 'Month', - - // private - layoutConfig: { - layoutOnCardChange: true, - deferredRender: true - }, - - // private property - startDate: new Date(), - - // private - initComponent: function() { - this.tbar = { - cls: 'ext-cal-toolbar', - border: true, - buttonAlign: 'center', - items: [{ - id: this.id + '-tb-prev', - handler: this.onPrevClick, - scope: this, - iconCls: 'x-tbar-page-prev' - }] - }; - - this.viewCount = 0; - - if (this.showDayView) { - this.tbar.items.push({ - id: this.id + '-tb-day', - text: this.dayText, - handler: this.onDayClick, - scope: this, - toggleGroup: 'tb-views' - }); - this.viewCount++; - } - if (this.showWeekView) { - this.tbar.items.push({ - id: this.id + '-tb-week', - text: this.weekText, - handler: this.onWeekClick, - scope: this, - toggleGroup: 'tb-views' - }); - this.viewCount++; - } - if (this.showMonthView || this.viewCount == 0) { - this.tbar.items.push({ - id: this.id + '-tb-month', - text: this.monthText, - handler: this.onMonthClick, - scope: this, - toggleGroup: 'tb-views' - }); - this.viewCount++; - this.showMonthView = true; - } - this.tbar.items.push({ - id: this.id + '-tb-next', - handler: this.onNextClick, - scope: this, - iconCls: 'x-tbar-page-next' - }); - this.tbar.items.push('->'); - - 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.addClass('x-calendar-nonav'); - } - - Ext.calendar.CalendarPanel.superclass.initComponent.call(this); - - this.addEvents({ - /** - * @event eventadd - * Fires after a new event is added to the underlying store - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was added - */ - eventadd: true, - /** - * @event eventupdate - * Fires after an existing event is updated - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was updated - */ - eventupdate: true, - /** - * @event eventdelete - * Fires after an event is removed from the underlying store - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord record} that was removed - */ - eventdelete: true, - /** - * @event eventcancel - * Fires after an event add/edit operation is canceled by the user and no store update took place - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The new {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarPanel} this - * @param {Ext.CalendarView} view The view being activated (any valid {@link Ext.calendar.CalendarView 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 - - // - // 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 {Ext.calendar.CalendarPanel} this - */ - /** - * @event eventclick - * Fires after the user clicks on an event element - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} for the event that the cursor exited - * @param {HTMLNode} el The DOM node that was exited - */ - /** - * @event datechange - * Fires after the start date of the view changes - * @param {Ext.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 rangeselect - * Fires after the user drags on the calendar to select a range of dates/times in which to create an event - * @param {Ext.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 eventmove - * Fires after an event element is dragged by the user and dropped in a new position - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord 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 {Ext.calendar.CalendarPanel} this - */ - /** - * @event eventresize - * Fires after the user drags the resize handle of an event to resize it - * @param {Ext.calendar.CalendarPanel} this - * @param {Ext.calendar.EventRecord} rec The {@link Ext.calendar.EventRecord record} for the event that was resized - * containing the updated start and end dates - */ - /** - * @event dayclick - * Fires after the user clicks within a day/week view container and not on an event element - * @param {Ext.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 - */ - }); - - this.layout = 'card'; - // do not allow override - if (this.showDayView) { - var day = Ext.apply({ - xtype: 'dayview', - title: this.dayText, - showToday: this.showToday, - showTodayText: this.showTodayText, - showTime: this.showTime - }, - this.dayViewCfg); - - day.id = this.id + '-day'; - day.store = day.store || this.eventStore; - this.initEventRelay(day); - this.add(day); - } - if (this.showWeekView) { - var wk = Ext.applyIf({ - xtype: 'weekview', - title: this.weekText, - showToday: this.showToday, - showTodayText: this.showTodayText, - showTime: this.showTime - }, - this.weekViewCfg); - - wk.id = this.id + '-week'; - wk.store = wk.store || this.eventStore; - this.initEventRelay(wk); - this.add(wk); - } - if (this.showMonthView) { - var month = Ext.applyIf({ - xtype: 'monthview', - title: this.monthText, - showToday: this.showToday, - showTodayText: this.showTodayText, - showTime: this.showTime, - listeners: { - 'weekclick': { - fn: function(vw, dt) { - this.showWeek(dt); - }, - scope: this - } - } - }, - this.monthViewCfg); - - month.id = this.id + '-month'; - month.store = month.store || this.eventStore; - this.initEventRelay(month); - this.add(month); - } - - this.add(Ext.applyIf({ - xtype: 'eventeditform', - id: this.id + '-edit', - calendarStore: this.calendarStore, - listeners: { - 'eventadd': { - scope: this, - fn: this.onEventAdd - }, - 'eventupdate': { - scope: this, - fn: this.onEventUpdate - }, - 'eventdelete': { - scope: this, - fn: this.onEventDelete - }, - 'eventcancel': { - scope: this, - fn: this.onEventCancel - } - } - }, - this.editViewCfg)); - }, - - // private - initEventRelay: function(cfg) { - cfg.listeners = cfg.listeners || {}; - cfg.listeners.afterrender = { - fn: function(c) { - // relay the view events so that app code only has to handle them in one place - this.relayEvents(c, ['eventsrendered', 'eventclick', 'eventover', 'eventout', 'dayclick', - 'eventmove', 'datechange', 'rangeselect', 'eventdelete', 'eventresize', 'initdrag']); - }, - scope: this, - single: true - }; - }, - - // private - afterRender: function() { - Ext.calendar.CalendarPanel.superclass.afterRender.call(this); - this.fireViewChange(); - }, - - // private - onLayout: function() { - Ext.calendar.CalendarPanel.superclass.onLayout.call(this); - if (!this.navInitComplete) { - this.updateNavState(); - this.navInitComplete = true; - } - }, - - // private - onEventAdd: function(form, rec) { - rec.data[Ext.calendar.EventMappings.IsNew.name] = false; - this.eventStore.add(rec); - this.hideEditForm(); - this.fireEvent('eventadd', this, rec); - }, - - // private - onEventUpdate: function(form, rec) { - rec.commit(); - this.hideEditForm(); - this.fireEvent('eventupdate', this, rec); - }, - - // private - onEventDelete: function(form, rec) { - this.eventStore.remove(rec); - this.hideEditForm(); - this.fireEvent('eventdelete', this, rec); - }, - - // private - onEventCancel: function(form, rec) { - 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}. - * @param {Ext.calendar.EventRecord} record The event record to edit - * @return {Ext.calendar.CalendarPanel} this - */ - showEditForm: function(rec) { - this.preEditView = this.layout.activeItem.id; - this.setActiveView(this.id + '-edit'); - this.layout.activeItem.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. - * @return {Ext.calendar.CalendarPanel} this - */ - hideEditForm: function() { - if (this.preEditView) { - this.setActiveView(this.preEditView); - delete this.preEditView; - } - return this; - }, - - // private - setActiveView: function(id) { - var l = this.layout; - l.setActiveItem(id); - - if (id == this.id + '-edit') { - this.getTopToolbar().hide(); - this.doLayout(); - } - else { - l.activeItem.refresh(); - this.getTopToolbar().show(); - this.updateNavState(); - } - this.activeView = l.activeItem; - this.fireViewChange(); - }, - - // private - fireViewChange: function() { - var info = null, - view = this.layout.activeItem; - - if (view.getViewBounds) { - vb = view.getViewBounds(); - info = { - activeDate: view.getStartDate(), - viewStart: vb.start, - viewEnd: vb.end - }; - }; - this.fireEvent('viewchange', this, view, info); - }, - - // private - updateNavState: function() { - if (this.showNavBar !== false) { - var item = this.layout.activeItem, - suffix = item.id.split(this.id + '-')[1]; - - var btn = Ext.getCmp(this.id + '-tb-' + suffix); - btn.toggle(true); - } - }, - - /** - * Sets the start date for the currently-active calendar view. - * @param {Date} dt - */ - setStartDate: function(dt) { - this.layout.activeItem.setStartDate(dt, true); - this.updateNavState(); - this.fireViewChange(); - }, - - // private - showWeek: function(dt) { - this.setActiveView(this.id + '-week'); - this.setStartDate(dt); - }, - - // private - onPrevClick: function() { - this.startDate = this.layout.activeItem.movePrev(); - this.updateNavState(); - this.fireViewChange(); - }, - - // private - onNextClick: function() { - this.startDate = this.layout.activeItem.moveNext(); - this.updateNavState(); - this.fireViewChange(); - }, - - // private - onDayClick: function() { - this.setActiveView(this.id + '-day'); - }, - - // private - onWeekClick: function() { - this.setActiveView(this.id + '-week'); - }, - - // private - onMonthClick: function() { - this.setActiveView(this.id + '-month'); - }, - - /** - * Return the calendar view that is currently active, which will be a subclass of - * {@link Ext.calendar.CalendarView CalendarView}. - * @return {Ext.calendar.CalendarView} The active view - */ - getActiveView: function() { - return this.layout.activeItem; - } -}); - -Ext.reg('calendarpanel', Ext.calendar.CalendarPanel); \ No newline at end of file