Upgrade to ExtJS 3.3.0 - Released 10/06/2010
[extjs.git] / examples / calendar / src / views / MonthView.js
diff --git a/examples/calendar/src/views/MonthView.js b/examples/calendar/src/views/MonthView.js
new file mode 100644 (file)
index 0000000..f7bedcf
--- /dev/null
@@ -0,0 +1,482 @@
+/*!
+ * Ext JS Library 3.3.0
+ * Copyright(c) 2006-2010 Ext JS, Inc.
+ * licensing@extjs.com
+ * http://www.extjs.com/license
+ */
+/**\r
+ * @class Ext.calendar.MonthView\r
+ * @extends Ext.calendar.CalendarView\r
+ * <p>Displays a calendar view by month. This class does not usually need ot be used directly as you can\r
+ * use a {@link Ext.calendar.CalendarPanel CalendarPanel} to manage multiple calendar views at once including\r
+ * the month view.</p>\r
+ * @constructor\r
+ * @param {Object} config The config object\r
+ */\r
+Ext.calendar.MonthView = Ext.extend(Ext.calendar.CalendarView, {\r
+    /**\r
+     * @cfg {Boolean} showTime\r
+     * True to display the current time in today's box in the calendar, false to not display it (defautls to true)\r
+     */\r
+    showTime: true,\r
+    /**\r
+     * @cfg {Boolean} showTodayText\r
+     * True to display the {@link #todayText} string in today's box in the calendar, false to not display it (defautls to true)\r
+     */\r
+    showTodayText: true,\r
+    /**\r
+     * @cfg {String} todayText\r
+     * The text to display in the current day's box in the calendar when {@link #showTodayText} is true (defaults to 'Today')\r
+     */\r
+    todayText: 'Today',\r
+    /**\r
+     * @cfg {Boolean} showHeader\r
+     * True to display a header beneath the navigation bar containing the week names above each week's column, false not to \r
+     * show it and instead display the week names in the first row of days in the calendar (defaults to false).\r
+     */\r
+    showHeader: false,\r
+    /**\r
+     * @cfg {Boolean} showWeekLinks\r
+     * True to display an extra column before the first day in the calendar that links to the {@link Ext.calendar.WeekView view}\r
+     * for each individual week, false to not show it (defaults to false). If true, the week links can also contain the week \r
+     * number depending on the value of {@link #showWeekNumbers}.\r
+     */\r
+    showWeekLinks: false,\r
+    /**\r
+     * @cfg {Boolean} showWeekNumbers\r
+     * True to show the week number for each week in the calendar in the week link column, false to show nothing (defaults to false).\r
+     * Note that if {@link #showWeekLinks} is false this config will have no affect even if true.\r
+     */\r
+    showWeekNumbers: false,\r
+    /**\r
+     * @cfg {String} weekLinkOverClass\r
+     * The CSS class name applied when the mouse moves over a week link element (only applies when {@link #showWeekLinks} is true,\r
+     * defaults to 'ext-week-link-over').\r
+     */\r
+    weekLinkOverClass: 'ext-week-link-over',\r
+\r
+    //private properties -- do not override:\r
+    daySelector: '.ext-cal-day',\r
+    moreSelector: '.ext-cal-ev-more',\r
+    weekLinkSelector: '.ext-cal-week-link',\r
+    weekCount: -1,\r
+    // defaults to auto by month\r
+    dayCount: 7,\r
+    moreElIdDelimiter: '-more-',\r
+    weekLinkIdDelimiter: 'ext-cal-week-',\r
+\r
+    // private\r
+    initComponent: function() {\r
+        Ext.calendar.MonthView.superclass.initComponent.call(this);\r
+        this.addEvents({\r
+            /**\r
+             * @event dayclick\r
+             * Fires after the user clicks within the view container and not on an event element\r
+             * @param {Ext.calendar.MonthView} this\r
+             * @param {Date} dt The date/time that was clicked on\r
+             * @param {Boolean} allday True if the day clicked on represents an all-day box, else false. Clicks within the \r
+             * MonthView always return true for this param.\r
+             * @param {Ext.Element} el The Element that was clicked on\r
+             */\r
+            dayclick: true,\r
+            /**\r
+             * @event weekclick\r
+             * Fires after the user clicks within a week link (when {@link #showWeekLinks is true)\r
+             * @param {Ext.calendar.MonthView} this\r
+             * @param {Date} dt The start date of the week that was clicked on\r
+             */\r
+            weekclick: true,\r
+            // inherited docs\r
+            dayover: true,\r
+            // inherited docs\r
+            dayout: true\r
+        });\r
+    },\r
+\r
+    // private\r
+    initDD: function() {\r
+        var cfg = {\r
+            view: this,\r
+            createText: this.ddCreateEventText,\r
+            moveText: this.ddMoveEventText,\r
+            ddGroup: 'MonthViewDD'\r
+        };\r
+\r
+        this.dragZone = new Ext.calendar.DragZone(this.el, cfg);\r
+        this.dropZone = new Ext.calendar.DropZone(this.el, cfg);\r
+    },\r
+\r
+    // private\r
+    onDestroy: function() {\r
+        Ext.destroy(this.ddSelector);\r
+        Ext.destroy(this.dragZone);\r
+        Ext.destroy(this.dropZone);\r
+        Ext.calendar.MonthView.superclass.onDestroy.call(this);\r
+    },\r
+\r
+    // private\r
+    afterRender: function() {\r
+        if (!this.tpl) {\r
+            this.tpl = new Ext.calendar.MonthViewTemplate({\r
+                id: this.id,\r
+                showTodayText: this.showTodayText,\r
+                todayText: this.todayText,\r
+                showTime: this.showTime,\r
+                showHeader: this.showHeader,\r
+                showWeekLinks: this.showWeekLinks,\r
+                showWeekNumbers: this.showWeekNumbers\r
+            });\r
+        }\r
+        this.tpl.compile();\r
+        this.addClass('ext-cal-monthview ext-cal-ct');\r
+\r
+        Ext.calendar.MonthView.superclass.afterRender.call(this);\r
+    },\r
+\r
+    // private\r
+    onResize: function() {\r
+        if (this.monitorResize) {\r
+            this.maxEventsPerDay = this.getMaxEventsPerDay();\r
+            this.refresh();\r
+        }\r
+    },\r
+\r
+    // private\r
+    forceSize: function() {\r
+        // Compensate for the week link gutter width if visible\r
+        if (this.showWeekLinks && this.el && this.el.child) {\r
+            var hd = this.el.select('.ext-cal-hd-days-tbl'),\r
+            bgTbl = this.el.select('.ext-cal-bg-tbl'),\r
+            evTbl = this.el.select('.ext-cal-evt-tbl'),\r
+            wkLinkW = this.el.child('.ext-cal-week-link').getWidth(),\r
+            w = this.el.getWidth() - wkLinkW;\r
+\r
+            hd.setWidth(w);\r
+            bgTbl.setWidth(w);\r
+            evTbl.setWidth(w);\r
+        }\r
+        Ext.calendar.MonthView.superclass.forceSize.call(this);\r
+    },\r
+\r
+    //private\r
+    initClock: function() {\r
+        if (Ext.fly(this.id + '-clock') !== null) {\r
+            this.prevClockDay = new Date().getDay();\r
+            if (this.clockTask) {\r
+                Ext.TaskMgr.stop(this.clockTask);\r
+            }\r
+            this.clockTask = Ext.TaskMgr.start({\r
+                run: function() {\r
+                    var el = Ext.fly(this.id + '-clock'),\r
+                    t = new Date();\r
+\r
+                    if (t.getDay() == this.prevClockDay) {\r
+                        if (el) {\r
+                            el.update(t.format('g:i a'));\r
+                        }\r
+                    }\r
+                    else {\r
+                        this.prevClockDay = t.getDay();\r
+                        this.moveTo(t);\r
+                    }\r
+                },\r
+                scope: this,\r
+                interval: 1000\r
+            });\r
+        }\r
+    },\r
+\r
+    // inherited docs\r
+    getEventBodyMarkup: function() {\r
+        if (!this.eventBodyMarkup) {\r
+            this.eventBodyMarkup = ['{Title}',\r
+            '<tpl if="_isReminder">',\r
+            '<i class="ext-cal-ic ext-cal-ic-rem">&nbsp;</i>',\r
+            '</tpl>',\r
+            '<tpl if="_isRecurring">',\r
+            '<i class="ext-cal-ic ext-cal-ic-rcr">&nbsp;</i>',\r
+            '</tpl>',\r
+            '<tpl if="spanLeft">',\r
+            '<i class="ext-cal-spl">&nbsp;</i>',\r
+            '</tpl>',\r
+            '<tpl if="spanRight">',\r
+            '<i class="ext-cal-spr">&nbsp;</i>',\r
+            '</tpl>'\r
+            ].join('');\r
+        }\r
+        return this.eventBodyMarkup;\r
+    },\r
+\r
+    // inherited docs\r
+    getEventTemplate: function() {\r
+        if (!this.eventTpl) {\r
+            var tpl,\r
+            body = this.getEventBodyMarkup();\r
+\r
+            tpl = !(Ext.isIE || Ext.isOpera) ?\r
+            new Ext.XTemplate(\r
+            '<div id="{_elId}" class="{_selectorCls} {_colorCls} {values.spanCls} ext-cal-evt ext-cal-evr">',\r
+            body,\r
+            '</div>'\r
+            )\r
+            : new Ext.XTemplate(\r
+            '<tpl if="_renderAsAllDay">',\r
+            '<div id="{_elId}" class="{_selectorCls} {values.spanCls} {_colorCls} ext-cal-evt ext-cal-evo">',\r
+            '<div class="ext-cal-evm">',\r
+            '<div class="ext-cal-evi">',\r
+            '</tpl>',\r
+            '<tpl if="!_renderAsAllDay">',\r
+            '<div id="{_elId}" class="{_selectorCls} {_colorCls} ext-cal-evt ext-cal-evr">',\r
+            '</tpl>',\r
+            body,\r
+            '<tpl if="_renderAsAllDay">',\r
+            '</div>',\r
+            '</div>',\r
+            '</tpl>',\r
+            '</div>'\r
+            );\r
+            tpl.compile();\r
+            this.eventTpl = tpl;\r
+        }\r
+        return this.eventTpl;\r
+    },\r
+\r
+    // private\r
+    getTemplateEventData: function(evt) {\r
+        var M = Ext.calendar.EventMappings,\r
+        selector = this.getEventSelectorCls(evt[M.EventId.name]),\r
+        title = evt[M.Title.name];\r
+\r
+        return Ext.applyIf({\r
+            _selectorCls: selector,\r
+            _colorCls: 'ext-color-' + (evt[M.CalendarId.name] ?\r
+            evt[M.CalendarId.name] : 'default') + (evt._renderAsAllDay ? '-ad': ''),\r
+            _elId: selector + '-' + evt._weekIndex,\r
+            _isRecurring: evt.Recurrence && evt.Recurrence != '',\r
+            _isReminder: evt[M.Reminder.name] && evt[M.Reminder.name] != '',\r
+            Title: (evt[M.IsAllDay.name] ? '': evt[M.StartDate.name].format('g:ia ')) + (!title || title.length == 0 ? '(No title)': title)\r
+        },\r
+        evt);\r
+    },\r
+\r
+    // private\r
+    refresh: function() {\r
+        if (this.detailPanel) {\r
+            this.detailPanel.hide();\r
+        }\r
+        Ext.calendar.MonthView.superclass.refresh.call(this);\r
+\r
+        if (this.showTime !== false) {\r
+            this.initClock();\r
+        }\r
+    },\r
+\r
+    // private\r
+    renderItems: function() {\r
+        Ext.calendar.WeekEventRenderer.render({\r
+            eventGrid: this.allDayOnly ? this.allDayGrid: this.eventGrid,\r
+            viewStart: this.viewStart,\r
+            tpl: this.getEventTemplate(),\r
+            maxEventsPerDay: this.maxEventsPerDay,\r
+            id: this.id,\r
+            templateDataFn: this.getTemplateEventData.createDelegate(this),\r
+            evtMaxCount: this.evtMaxCount,\r
+            weekCount: this.weekCount,\r
+            dayCount: this.dayCount\r
+        });\r
+        this.fireEvent('eventsrendered', this);\r
+    },\r
+\r
+    // private\r
+    getDayEl: function(dt) {\r
+        return Ext.get(this.getDayId(dt));\r
+    },\r
+\r
+    // private\r
+    getDayId: function(dt) {\r
+        if (Ext.isDate(dt)) {\r
+            dt = dt.format('Ymd');\r
+        }\r
+        return this.id + this.dayElIdDelimiter + dt;\r
+    },\r
+\r
+    // private\r
+    getWeekIndex: function(dt) {\r
+        var el = this.getDayEl(dt).up('.ext-cal-wk-ct');\r
+        return parseInt(el.id.split('-wk-')[1], 10);\r
+    },\r
+\r
+    // private\r
+    getDaySize: function(contentOnly) {\r
+        var box = this.el.getBox(),\r
+        w = box.width / this.dayCount,\r
+        h = box.height / this.getWeekCount();\r
+\r
+        if (contentOnly) {\r
+            var hd = this.el.select('.ext-cal-dtitle').first().parent('tr');\r
+            h = hd ? h - hd.getHeight(true) : h;\r
+        }\r
+        return {\r
+            height: h,\r
+            width: w\r
+        };\r
+    },\r
+\r
+    // private\r
+    getEventHeight: function() {\r
+        if (!this.eventHeight) {\r
+            var evt = this.el.select('.ext-cal-evt').first();\r
+            this.eventHeight = evt ? evt.parent('tr').getHeight() : 18;\r
+        }\r
+        return this.eventHeight;\r
+    },\r
+\r
+    // private\r
+    getMaxEventsPerDay: function() {\r
+        var dayHeight = this.getDaySize(true).height,\r
+            h = this.getEventHeight(),\r
+            max = Math.max(Math.floor((dayHeight - h) / h), 0);\r
+\r
+        return max;\r
+    },\r
+\r
+    // private\r
+    getDayAt: function(x, y) {\r
+        var box = this.el.getBox(),\r
+            daySize = this.getDaySize(),\r
+            dayL = Math.floor(((x - box.x) / daySize.width)),\r
+            dayT = Math.floor(((y - box.y) / daySize.height)),\r
+            days = (dayT * 7) + dayL,\r
+            dt = this.viewStart.add(Date.DAY, days);\r
+        return {\r
+            date: dt,\r
+            el: this.getDayEl(dt)\r
+        };\r
+    },\r
+\r
+    // inherited docs\r
+    moveNext: function() {\r
+        return this.moveMonths(1);\r
+    },\r
+\r
+    // inherited docs\r
+    movePrev: function() {\r
+        return this.moveMonths( - 1);\r
+    },\r
+\r
+    // private\r
+    onInitDrag: function() {\r
+        Ext.calendar.MonthView.superclass.onInitDrag.call(this);\r
+        Ext.select(this.daySelector).removeClass(this.dayOverClass);\r
+        if (this.detailPanel) {\r
+            this.detailPanel.hide();\r
+        }\r
+    },\r
+\r
+    // private\r
+    onMoreClick: function(dt) {\r
+        if (!this.detailPanel) {\r
+            this.detailPanel = new Ext.Panel({\r
+                id: this.id + '-details-panel',\r
+                title: dt.format('F j'),\r
+                layout: 'fit',\r
+                floating: true,\r
+                renderTo: Ext.getBody(),\r
+                tools: [{\r
+                    id: 'close',\r
+                    handler: function(e, t, p) {\r
+                        p.hide();\r
+                    }\r
+                }],\r
+                items: {\r
+                    xtype: 'monthdaydetailview',\r
+                    id: this.id + '-details-view',\r
+                    date: dt,\r
+                    view: this,\r
+                    store: this.store,\r
+                    listeners: {\r
+                        'eventsrendered': this.onDetailViewUpdated.createDelegate(this)\r
+                    }\r
+                }\r
+            });\r
+        }\r
+        else {\r
+            this.detailPanel.setTitle(dt.format('F j'));\r
+        }\r
+        this.detailPanel.getComponent(this.id + '-details-view').update(dt);\r
+    },\r
+\r
+    // private\r
+    onDetailViewUpdated: function(view, dt, numEvents) {\r
+        var p = this.detailPanel,\r
+        frameH = p.getFrameHeight(),\r
+        evtH = this.getEventHeight(),\r
+        bodyH = frameH + (numEvents * evtH) + 3,\r
+        dayEl = this.getDayEl(dt),\r
+        box = dayEl.getBox();\r
+\r
+        p.updateBox(box);\r
+        p.setHeight(bodyH);\r
+        p.setWidth(Math.max(box.width, 220));\r
+        p.show();\r
+        p.getPositionEl().alignTo(dayEl, 't-t?');\r
+    },\r
+\r
+    // private\r
+    onHide: function() {\r
+        Ext.calendar.MonthView.superclass.onHide.call(this);\r
+        if (this.detailPanel) {\r
+            this.detailPanel.hide();\r
+        }\r
+    },\r
+\r
+    // private\r
+    onClick: function(e, t) {\r
+        if (this.detailPanel) {\r
+            this.detailPanel.hide();\r
+        }\r
+        if (Ext.calendar.MonthView.superclass.onClick.apply(this, arguments)) {\r
+            // The superclass handled the click already so exit\r
+            return;\r
+        }\r
+        if (this.dropZone) {\r
+            this.dropZone.clearShims();\r
+        }\r
+        var el = e.getTarget(this.weekLinkSelector, 3),\r
+            dt,\r
+            parts;\r
+        if (el) {\r
+            dt = el.id.split(this.weekLinkIdDelimiter)[1];\r
+            this.fireEvent('weekclick', this, Date.parseDate(dt, 'Ymd'));\r
+            return;\r
+        }\r
+        el = e.getTarget(this.moreSelector, 3);\r
+        if (el) {\r
+            dt = el.id.split(this.moreElIdDelimiter)[1];\r
+            this.onMoreClick(Date.parseDate(dt, 'Ymd'));\r
+            return;\r
+        }\r
+        el = e.getTarget('td', 3);\r
+        if (el) {\r
+            if (el.id && el.id.indexOf(this.dayElIdDelimiter) > -1) {\r
+                parts = el.id.split(this.dayElIdDelimiter);\r
+                dt = parts[parts.length - 1];\r
+\r
+                this.fireEvent('dayclick', this, Date.parseDate(dt, 'Ymd'), false, Ext.get(this.getDayId(dt)));\r
+                return;\r
+            }\r
+        }\r
+    },\r
+\r
+    // private\r
+    handleDayMouseEvent: function(e, t, type) {\r
+        var el = e.getTarget(this.weekLinkSelector, 3, true);\r
+        if (el) {\r
+            el[type == 'over' ? 'addClass': 'removeClass'](this.weekLinkOverClass);\r
+            return;\r
+        }\r
+        Ext.calendar.MonthView.superclass.handleDayMouseEvent.apply(this, arguments);\r
+    }\r
+});\r
+\r
+Ext.reg('monthview', Ext.calendar.MonthView);\r