Clockworkgeek_CalendarView - Version 0.1

Version Notes

Can be skinned entirely by modifying css/calendarview.css

Download this release

Release Info

Developer Magento Core Team
Extension Clockworkgeek_CalendarView
Version 0.1
Comparing to
See all releases


Version 0.1

app/code/community/Clockworkgeek/CalendarView/Block/Html/Date.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the Open Software License (OSL 3.0)
6
+ * that is bundled with this package in the file LICENSE.txt.
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://opensource.org/licenses/osl-3.0.php
9
+ *
10
+ *
11
+ * @category Design
12
+ * @package Clockworkgeek_CalendarView
13
+ * @author Daniel Deady <daniel@clockworkgeek.com>
14
+ * @copyright Copyright (c) 2010, Daniel Deady
15
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
16
+ */
17
+
18
+ class Clockworkgeek_CalendarView_Block_Html_Date extends Mage_Core_Block_Html_Date
19
+ {
20
+
21
+ protected function _toHtml()
22
+ {
23
+ $html = '<input type="text" name="' . $this->getName() . '" id="' . $this->getId() . '" ';
24
+ $html .= 'value="'.$this->getValue().'" class="'.$this->getClass().'" '.$this->getExtraParams().'/> ';
25
+
26
+ $html .= '<img src="' . $this->getImage() . '" alt="' . $this->helper('core')->__('Select Date') . '" class="v-middle" ';
27
+ $html .= 'title="' . $this->helper('core')->__('Select Date') . '" id="' . $this->getId() . '_trig" />';
28
+
29
+ $script = "Calendar.setup({dateField: '{$this->getId()}', triggerElement: '{$this->getId()}_trig'});";
30
+ $html .= Mage::helper('core/js')->getScript($script);
31
+
32
+ return $html;
33
+ }
34
+
35
+ }
36
+
app/code/community/Clockworkgeek/CalendarView/etc/config.xml ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ *
12
+ * @category Design
13
+ * @package Clockworkgeek_CalendarView
14
+ * @author Daniel Deady <daniel@clockworkgeek.com>
15
+ * @copyright Copyright (c) 2010, Daniel Deady
16
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
+ -->
18
+ <config>
19
+
20
+ <modules>
21
+ <Clockworkgeek_CalendarView>
22
+ <version>0.1</version>
23
+ </Clockworkgeek_CalendarView>
24
+ </modules>
25
+
26
+ <global>
27
+ <blocks>
28
+ <calendarview>
29
+ <class>Clockworkgeek_CalendarView_Block</class>
30
+ </calendarview>
31
+ <core>
32
+ <rewrite>
33
+ <html_date>Clockworkgeek_CalendarView_Block_Html_Date</html_date>
34
+ </rewrite>
35
+ </core>
36
+ </blocks>
37
+ </global>
38
+
39
+ <frontend>
40
+ <layout>
41
+ <updates>
42
+ <calendarview>
43
+ <file>calendarview.xml</file>
44
+ </calendarview>
45
+ </updates>
46
+ </layout>
47
+ </frontend>
48
+
49
+ </config>
app/design/frontend/base/default/layout/calendarview.xml ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ *
12
+ * @category Design
13
+ * @package Clockworkgeek_CalendarView
14
+ * @author Daniel Deady <daniel@clockworkgeek.com>
15
+ * @copyright Copyright (c) 2010, Daniel Deady
16
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
+ */
18
+ -->
19
+ <layout>
20
+
21
+ <catalog_product_view>
22
+ <reference name="head">
23
+ <!-- Remove nasty, old, ugly date picker -->
24
+ <action method="removeItem"><type>js_css</type><name>calendar/calendar-win2k-1.css</name><params/></action>
25
+ <action method="removeItem"><type>js</type><name>calendar/calendar.js</name></action>
26
+ <action method="removeItem"><type>js</type><name>calendar/calendar-setup.js</name></action>
27
+
28
+ <!-- Insert new, pretty, streamlined date picker -->
29
+ <action method="addItem"><type>js</type><name>calendarview/calendarview.js</name></action>
30
+ <action method="addItem"><type>skin_css</type><name>css/calendarview.css</name></action>
31
+ </reference>
32
+ </catalog_product_view>
33
+
34
+ </layout>
app/etc/modules/Clockworkgeek_CalendarView.xml ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Open Software License (OSL 3.0)
7
+ * that is bundled with this package in the file LICENSE.txt.
8
+ * It is also available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/osl-3.0.php
10
+ *
11
+ *
12
+ * @category Design
13
+ * @package Clockworkgeek_CalendarView
14
+ * @author Daniel Deady <daniel@clockworkgeek.com>
15
+ * @copyright Copyright (c) 2010, Daniel Deady
16
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
+ -->
18
+ <config>
19
+ <modules>
20
+ <Clockworkgeek_CalendarView>
21
+ <active>true</active>
22
+ <codePool>community</codePool>
23
+ <depends>
24
+ <Mage_Catalog />
25
+ </depends>
26
+ </Clockworkgeek_CalendarView>
27
+ </modules>
28
+ </config>
js/calendarview/calendarview.js ADDED
@@ -0,0 +1,839 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ //
2
+ // CalendarView (for Prototype)
3
+ // calendarview.org
4
+ //
5
+ // Maintained by Justin Mecham <justin@aspect.net>
6
+ //
7
+ // Portions Copyright 2002-2005 Mihai Bazon
8
+ //
9
+ // This calendar is based very loosely on the Dynarch Calendar in that it was
10
+ // used as a base, but completely gutted and more or less rewritten in place
11
+ // to use the Prototype JavaScript library.
12
+ //
13
+ // As such, CalendarView is licensed under the terms of the GNU Lesser General
14
+ // Public License (LGPL). More information on the Dynarch Calendar can be
15
+ // found at:
16
+ //
17
+ // www.dynarch.com/projects/calendar
18
+ //
19
+
20
+ var Calendar = Class.create()
21
+
22
+ //------------------------------------------------------------------------------
23
+ // Constants
24
+ //------------------------------------------------------------------------------
25
+
26
+ Calendar.VERSION = '1.2'
27
+
28
+ Calendar.DAY_NAMES = new Array(
29
+ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday',
30
+ 'Sunday'
31
+ )
32
+
33
+ Calendar.SHORT_DAY_NAMES = new Array(
34
+ 'S', 'M', 'T', 'W', 'T', 'F', 'S', 'S'
35
+ )
36
+
37
+ Calendar.MONTH_NAMES = new Array(
38
+ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
39
+ 'September', 'October', 'November', 'December'
40
+ )
41
+
42
+ Calendar.SHORT_MONTH_NAMES = new Array(
43
+ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov',
44
+ 'Dec'
45
+ )
46
+
47
+ Calendar.NAV_PREVIOUS_YEAR = -2
48
+ Calendar.NAV_PREVIOUS_MONTH = -1
49
+ Calendar.NAV_TODAY = 0
50
+ Calendar.NAV_NEXT_MONTH = 1
51
+ Calendar.NAV_NEXT_YEAR = 2
52
+
53
+ //------------------------------------------------------------------------------
54
+ // Static Methods
55
+ //------------------------------------------------------------------------------
56
+
57
+ // This gets called when the user presses a mouse button anywhere in the
58
+ // document, if the calendar is shown. If the click was outside the open
59
+ // calendar this function closes it.
60
+ Calendar._checkCalendar = function(event) {
61
+ if (!window._popupCalendar)
62
+ return false
63
+ if (Element.descendantOf(Event.element(event), window._popupCalendar.container))
64
+ return
65
+ window._popupCalendar.callCloseHandler()
66
+ return Event.stop(event)
67
+ }
68
+
69
+ //------------------------------------------------------------------------------
70
+ // Event Handlers
71
+ //------------------------------------------------------------------------------
72
+
73
+ Calendar.handleMouseDownEvent = function(event)
74
+ {
75
+ Event.observe(document, 'mouseup', Calendar.handleMouseUpEvent)
76
+ Event.stop(event)
77
+ }
78
+
79
+ // XXX I am not happy with how clicks of different actions are handled. Need to
80
+ // clean this up!
81
+ Calendar.handleMouseUpEvent = function(event)
82
+ {
83
+ var el = Event.element(event)
84
+ var calendar = el.calendar
85
+ var isNewDate = false
86
+
87
+ // If the element that was clicked on does not have an associated Calendar
88
+ // object, return as we have nothing to do.
89
+ if (!calendar) return false
90
+
91
+ // Clicked on a day
92
+ if (typeof el.navAction == 'undefined')
93
+ {
94
+ if (calendar.currentDateElement) {
95
+ Element.removeClassName(calendar.currentDateElement, 'selected')
96
+ Element.addClassName(el, 'selected')
97
+ calendar.shouldClose = (calendar.currentDateElement == el)
98
+ if (!calendar.shouldClose) calendar.currentDateElement = el
99
+ }
100
+ calendar.date.setDateOnly(el.date)
101
+ isNewDate = true
102
+ calendar.shouldClose = !el.hasClassName('otherDay')
103
+ var isOtherMonth = !calendar.shouldClose
104
+ if (isOtherMonth) calendar.update(calendar.date)
105
+ }
106
+
107
+ // Clicked on an action button
108
+ else
109
+ {
110
+ var date = new Date(calendar.date)
111
+
112
+ if (el.navAction == Calendar.NAV_TODAY)
113
+ date.setDateOnly(new Date())
114
+
115
+ var year = date.getFullYear()
116
+ var mon = date.getMonth()
117
+ function setMonth(m) {
118
+ var day = date.getDate()
119
+ var max = date.getMonthDays(m)
120
+ if (day > max) date.setDate(max)
121
+ date.setMonth(m)
122
+ }
123
+ switch (el.navAction) {
124
+
125
+ // Previous Year
126
+ case Calendar.NAV_PREVIOUS_YEAR:
127
+ if (year > calendar.minYear)
128
+ date.setFullYear(year - 1)
129
+ break
130
+
131
+ // Previous Month
132
+ case Calendar.NAV_PREVIOUS_MONTH:
133
+ if (mon > 0) {
134
+ setMonth(mon - 1)
135
+ }
136
+ else if (year-- > calendar.minYear) {
137
+ date.setFullYear(year)
138
+ setMonth(11)
139
+ }
140
+ break
141
+
142
+ // Today
143
+ case Calendar.NAV_TODAY:
144
+ break
145
+
146
+ // Next Month
147
+ case Calendar.NAV_NEXT_MONTH:
148
+ if (mon < 11) {
149
+ setMonth(mon + 1)
150
+ }
151
+ else if (year < calendar.maxYear) {
152
+ date.setFullYear(year + 1)
153
+ setMonth(0)
154
+ }
155
+ break
156
+
157
+ // Next Year
158
+ case Calendar.NAV_NEXT_YEAR:
159
+ if (year < calendar.maxYear)
160
+ date.setFullYear(year + 1)
161
+ break
162
+
163
+ }
164
+
165
+ if (!date.equalsTo(calendar.date)) {
166
+ calendar.setDate(date)
167
+ isNewDate = true
168
+ } else if (el.navAction == 0) {
169
+ isNewDate = (calendar.shouldClose = true)
170
+ }
171
+ }
172
+
173
+ if (isNewDate) event && calendar.callSelectHandler()
174
+ if (calendar.shouldClose) event && calendar.callCloseHandler()
175
+
176
+ Event.stopObserving(document, 'mouseup', Calendar.handleMouseUpEvent)
177
+
178
+ return Event.stop(event)
179
+ }
180
+
181
+ Calendar.defaultSelectHandler = function(calendar)
182
+ {
183
+ if (!calendar.dateField) return false
184
+
185
+ // Update dateField value
186
+ if (calendar.dateField.tagName == 'DIV')
187
+ Element.update(calendar.dateField, calendar.date.print(calendar.dateFormat))
188
+ else if (calendar.dateField.tagName == 'INPUT') {
189
+ calendar.dateField.value = calendar.date.print(calendar.dateFormat) }
190
+
191
+ // Trigger the onchange callback on the dateField, if one has been defined
192
+ if (typeof calendar.dateField.onchange == 'function')
193
+ calendar.dateField.onchange()
194
+
195
+ // Call the close handler, if necessary
196
+ if (calendar.shouldClose) calendar.callCloseHandler()
197
+ }
198
+
199
+ Calendar.defaultCloseHandler = function(calendar)
200
+ {
201
+ calendar.hide()
202
+ }
203
+
204
+
205
+ //------------------------------------------------------------------------------
206
+ // Calendar Setup
207
+ //------------------------------------------------------------------------------
208
+
209
+ Calendar.setup = function(params)
210
+ {
211
+
212
+ function param_default(name, def) {
213
+ if (!params[name]) params[name] = def
214
+ }
215
+
216
+ param_default('dateField', null)
217
+ param_default('triggerElement', null)
218
+ param_default('parentElement', null)
219
+ param_default('selectHandler', null)
220
+ param_default('closeHandler', null)
221
+
222
+ // In-Page Calendar
223
+ if (params.parentElement)
224
+ {
225
+ var calendar = new Calendar(params.parentElement)
226
+ calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
227
+ if (params.dateFormat)
228
+ calendar.setDateFormat(params.dateFormat)
229
+ if (params.dateField) {
230
+ calendar.setDateField(params.dateField)
231
+ calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
232
+ }
233
+ calendar.show()
234
+ return calendar
235
+ }
236
+
237
+ // Popup Calendars
238
+ //
239
+ // XXX There is significant optimization to be had here by creating the
240
+ // calendar and storing it on the page, but then you will have issues with
241
+ // multiple calendars on the same page.
242
+ else
243
+ {
244
+ var triggerElement = $(params.triggerElement || params.dateField)
245
+ triggerElement.onclick = function() {
246
+ var calendar = new Calendar()
247
+ calendar.setSelectHandler(params.selectHandler || Calendar.defaultSelectHandler)
248
+ calendar.setCloseHandler(params.closeHandler || Calendar.defaultCloseHandler)
249
+ if (params.dateFormat)
250
+ calendar.setDateFormat(params.dateFormat)
251
+ if (params.dateField) {
252
+ calendar.setDateField(params.dateField)
253
+ calendar.parseDate(calendar.dateField.innerHTML || calendar.dateField.value)
254
+ }
255
+ if (params.dateField)
256
+ Date.parseDate(calendar.dateField.value || calendar.dateField.innerHTML, calendar.dateFormat)
257
+ calendar.showAtElement(triggerElement)
258
+ return calendar
259
+ }
260
+ }
261
+
262
+ }
263
+
264
+
265
+
266
+ //------------------------------------------------------------------------------
267
+ // Calendar Instance
268
+ //------------------------------------------------------------------------------
269
+
270
+ Calendar.prototype = {
271
+
272
+ // The HTML Container Element
273
+ container: null,
274
+
275
+ // Callbacks
276
+ selectHandler: null,
277
+ closeHandler: null,
278
+
279
+ // Configuration
280
+ minYear: 1900,
281
+ maxYear: 2100,
282
+ dateFormat: '%Y-%m-%d',
283
+
284
+ // Dates
285
+ date: new Date(),
286
+ currentDateElement: null,
287
+
288
+ // Status
289
+ shouldClose: false,
290
+ isPopup: true,
291
+
292
+ dateField: null,
293
+
294
+
295
+ //----------------------------------------------------------------------------
296
+ // Initialize
297
+ //----------------------------------------------------------------------------
298
+
299
+ initialize: function(parent)
300
+ {
301
+ if (parent)
302
+ this.create($(parent))
303
+ else
304
+ this.create()
305
+ },
306
+
307
+
308
+
309
+ //----------------------------------------------------------------------------
310
+ // Update / (Re)initialize Calendar
311
+ //----------------------------------------------------------------------------
312
+
313
+ update: function(date)
314
+ {
315
+ var calendar = this
316
+ var today = new Date()
317
+ var thisYear = today.getFullYear()
318
+ var thisMonth = today.getMonth()
319
+ var thisDay = today.getDate()
320
+ var month = date.getMonth();
321
+ var dayOfMonth = date.getDate();
322
+
323
+ // Ensure date is within the defined range
324
+ if (date.getFullYear() < this.minYear)
325
+ date.setFullYear(this.minYear)
326
+ else if (date.getFullYear() > this.maxYear)
327
+ date.setFullYear(this.maxYear)
328
+
329
+ this.date = new Date(date)
330
+
331
+ // Calculate the first day to display (including the previous month)
332
+ date.setDate(1)
333
+ date.setDate(-(date.getDay()) + 1)
334
+
335
+ // Fill in the days of the month
336
+ Element.getElementsBySelector(this.container, 'tbody tr').each(
337
+ function(row, i) {
338
+ var rowHasDays = false
339
+ row.immediateDescendants().each(
340
+ function(cell, j) {
341
+ var day = date.getDate()
342
+ var dayOfWeek = date.getDay()
343
+ var isCurrentMonth = (date.getMonth() == month)
344
+
345
+ // Reset classes on the cell
346
+ cell.className = ''
347
+ cell.date = new Date(date)
348
+ cell.update(day)
349
+
350
+ // Account for days of the month other than the current month
351
+ if (!isCurrentMonth)
352
+ cell.addClassName('otherDay')
353
+ else
354
+ rowHasDays = true
355
+
356
+ // Ensure the current day is selected
357
+ if (isCurrentMonth && day == dayOfMonth) {
358
+ cell.addClassName('selected')
359
+ calendar.currentDateElement = cell
360
+ }
361
+
362
+ // Today
363
+ if (date.getFullYear() == thisYear && date.getMonth() == thisMonth && day == thisDay)
364
+ cell.addClassName('today')
365
+
366
+ // Weekend
367
+ if ([0, 6].indexOf(dayOfWeek) != -1)
368
+ cell.addClassName('weekend')
369
+
370
+ // Set the date to tommorrow
371
+ date.setDate(day + 1)
372
+ }
373
+ )
374
+ // Hide the extra row if it contains only days from another month
375
+ !rowHasDays ? row.hide() : row.show()
376
+ }
377
+ )
378
+
379
+ this.container.getElementsBySelector('td.title')[0].update(
380
+ Calendar.MONTH_NAMES[month] + ' ' + this.date.getFullYear()
381
+ )
382
+ },
383
+
384
+
385
+
386
+ //----------------------------------------------------------------------------
387
+ // Create/Draw the Calendar HTML Elements
388
+ //----------------------------------------------------------------------------
389
+
390
+ create: function(parent)
391
+ {
392
+
393
+ // If no parent was specified, assume that we are creating a popup calendar.
394
+ if (!parent) {
395
+ parent = document.getElementsByTagName('body')[0]
396
+ this.isPopup = true
397
+ } else {
398
+ this.isPopup = false
399
+ }
400
+
401
+ // Calendar Table
402
+ var table = new Element('table')
403
+
404
+ // Calendar Header
405
+ var thead = new Element('thead')
406
+ table.appendChild(thead)
407
+
408
+ // Title Placeholder
409
+ var row = new Element('tr')
410
+ var cell = new Element('td', { colSpan: 7 } )
411
+ cell.addClassName('title')
412
+ row.appendChild(cell)
413
+ thead.appendChild(row)
414
+
415
+ // Calendar Navigation
416
+ row = new Element('tr')
417
+ this._drawButtonCell(row, '&#x00ab;', 1, Calendar.NAV_PREVIOUS_YEAR)
418
+ this._drawButtonCell(row, '&#x2039;', 1, Calendar.NAV_PREVIOUS_MONTH)
419
+ this._drawButtonCell(row, 'Today', 3, Calendar.NAV_TODAY)
420
+ this._drawButtonCell(row, '&#x203a;', 1, Calendar.NAV_NEXT_MONTH)
421
+ this._drawButtonCell(row, '&#x00bb;', 1, Calendar.NAV_NEXT_YEAR)
422
+ thead.appendChild(row)
423
+
424
+ // Day Names
425
+ row = new Element('tr')
426
+ for (var i = 0; i < 7; ++i) {
427
+ cell = new Element('th').update(Calendar.SHORT_DAY_NAMES[i])
428
+ if (i == 0 || i == 6)
429
+ cell.addClassName('weekend')
430
+ row.appendChild(cell)
431
+ }
432
+ thead.appendChild(row)
433
+
434
+ // Calendar Days
435
+ var tbody = table.appendChild(new Element('tbody'))
436
+ for (i = 6; i > 0; --i) {
437
+ row = tbody.appendChild(new Element('tr'))
438
+ row.addClassName('days')
439
+ for (var j = 7; j > 0; --j) {
440
+ cell = row.appendChild(new Element('td'))
441
+ cell.calendar = this
442
+ }
443
+ }
444
+
445
+ // Calendar Container (div)
446
+ this.container = new Element('div')
447
+ this.container.addClassName('calendar')
448
+ if (this.isPopup) {
449
+ this.container.setStyle({ position: 'absolute', display: 'none' })
450
+ this.container.addClassName('popup')
451
+ }
452
+ this.container.appendChild(table)
453
+
454
+ // Initialize Calendar
455
+ this.update(this.date)
456
+
457
+ // Observe the container for mousedown events
458
+ Event.observe(this.container, 'mousedown', Calendar.handleMouseDownEvent)
459
+
460
+ // Append to parent element
461
+ parent.appendChild(this.container)
462
+
463
+ },
464
+
465
+ _drawButtonCell: function(parent, text, colSpan, navAction)
466
+ {
467
+ var cell = new Element('td')
468
+ if (colSpan > 1) cell.colSpan = colSpan
469
+ cell.className = 'button'
470
+ cell.calendar = this
471
+ cell.navAction = navAction
472
+ cell.innerHTML = text
473
+ cell.unselectable = 'on' // IE
474
+ parent.appendChild(cell)
475
+ return cell
476
+ },
477
+
478
+
479
+
480
+ //------------------------------------------------------------------------------
481
+ // Callbacks
482
+ //------------------------------------------------------------------------------
483
+
484
+ // Calls the Select Handler (if defined)
485
+ callSelectHandler: function()
486
+ {
487
+ if (this.selectHandler)
488
+ this.selectHandler(this, this.date.print(this.dateFormat))
489
+ },
490
+
491
+ // Calls the Close Handler (if defined)
492
+ callCloseHandler: function()
493
+ {
494
+ if (this.closeHandler)
495
+ this.closeHandler(this)
496
+ },
497
+
498
+
499
+
500
+ //------------------------------------------------------------------------------
501
+ // Calendar Display Functions
502
+ //------------------------------------------------------------------------------
503
+
504
+ // Shows the Calendar
505
+ show: function()
506
+ {
507
+ this.container.show()
508
+ if (this.isPopup) {
509
+ window._popupCalendar = this
510
+ Event.observe(document, 'mousedown', Calendar._checkCalendar)
511
+ }
512
+ },
513
+
514
+ // Shows the calendar at the given absolute position
515
+ showAt: function (x, y)
516
+ {
517
+ this.container.setStyle({ left: x + 'px', top: y + 'px' })
518
+ this.show()
519
+ },
520
+
521
+ // Shows the Calendar at the coordinates of the provided element
522
+ showAtElement: function(element)
523
+ {
524
+ var pos = Position.cumulativeOffset(element)
525
+ this.showAt(pos[0], pos[1])
526
+ },
527
+
528
+ // Hides the Calendar
529
+ hide: function()
530
+ {
531
+ if (this.isPopup)
532
+ Event.stopObserving(document, 'mousedown', Calendar._checkCalendar)
533
+ this.container.hide()
534
+ },
535
+
536
+
537
+
538
+ //------------------------------------------------------------------------------
539
+ // Miscellaneous
540
+ //------------------------------------------------------------------------------
541
+
542
+ // Tries to identify the date represented in a string. If successful it also
543
+ // calls this.setDate which moves the calendar to the given date.
544
+ parseDate: function(str, format)
545
+ {
546
+ if (!format)
547
+ format = this.dateFormat
548
+ this.setDate(Date.parseDate(str, format))
549
+ },
550
+
551
+
552
+
553
+ //------------------------------------------------------------------------------
554
+ // Getters/Setters
555
+ //------------------------------------------------------------------------------
556
+
557
+ setSelectHandler: function(selectHandler)
558
+ {
559
+ this.selectHandler = selectHandler
560
+ },
561
+
562
+ setCloseHandler: function(closeHandler)
563
+ {
564
+ this.closeHandler = closeHandler
565
+ },
566
+
567
+ setDate: function(date)
568
+ {
569
+ if (!date.equalsTo(this.date))
570
+ this.update(date)
571
+ },
572
+
573
+ setDateFormat: function(format)
574
+ {
575
+ this.dateFormat = format
576
+ },
577
+
578
+ setDateField: function(field)
579
+ {
580
+ this.dateField = $(field)
581
+ },
582
+
583
+ setRange: function(minYear, maxYear)
584
+ {
585
+ this.minYear = minYear
586
+ this.maxYear = maxYear
587
+ }
588
+
589
+ }
590
+
591
+ // global object that remembers the calendar
592
+ window._popupCalendar = null
593
+
594
+
595
+
596
+
597
+
598
+
599
+
600
+
601
+
602
+
603
+
604
+
605
+
606
+
607
+
608
+
609
+
610
+
611
+
612
+
613
+
614
+
615
+
616
+
617
+
618
+
619
+
620
+
621
+
622
+ //==============================================================================
623
+ //
624
+ // Date Object Patches
625
+ //
626
+ // This is pretty much untouched from the original. I really would like to get
627
+ // rid of these patches if at all possible and find a cleaner way of
628
+ // accomplishing the same things. It's a shame Prototype doesn't extend Date at
629
+ // all.
630
+ //
631
+ //==============================================================================
632
+
633
+ Date.DAYS_IN_MONTH = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
634
+ Date.SECOND = 1000 /* milliseconds */
635
+ Date.MINUTE = 60 * Date.SECOND
636
+ Date.HOUR = 60 * Date.MINUTE
637
+ Date.DAY = 24 * Date.HOUR
638
+ Date.WEEK = 7 * Date.DAY
639
+
640
+ // Parses Date
641
+ Date.parseDate = function(str, fmt) {
642
+ var today = new Date();
643
+ var y = 0;
644
+ var m = -1;
645
+ var d = 0;
646
+ var a = str.split(/\W+/);
647
+ var b = fmt.match(/%./g);
648
+ var i = 0, j = 0;
649
+ var hr = 0;
650
+ var min = 0;
651
+
652
+ for (i = 0; i < a.length; ++i) {
653
+ if (!a[i]) continue;
654
+ switch (b[i]) {
655
+ case "%d":
656
+ case "%e":
657
+ d = parseInt(a[i], 10);
658
+ break;
659
+ case "%m":
660
+ m = parseInt(a[i], 10) - 1;
661
+ break;
662
+ case "%Y":
663
+ case "%y":
664
+ y = parseInt(a[i], 10);
665
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
666
+ break;
667
+ case "%b":
668
+ case "%B":
669
+ for (j = 0; j < 12; ++j) {
670
+ if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) {
671
+ m = j;
672
+ break;
673
+ }
674
+ }
675
+ break;
676
+ case "%H":
677
+ case "%I":
678
+ case "%k":
679
+ case "%l":
680
+ hr = parseInt(a[i], 10);
681
+ break;
682
+ case "%P":
683
+ case "%p":
684
+ if (/pm/i.test(a[i]) && hr < 12)
685
+ hr += 12;
686
+ else if (/am/i.test(a[i]) && hr >= 12)
687
+ hr -= 12;
688
+ break;
689
+ case "%M":
690
+ min = parseInt(a[i], 10);
691
+ break;
692
+ }
693
+ }
694
+ if (isNaN(y)) y = today.getFullYear();
695
+ if (isNaN(m)) m = today.getMonth();
696
+ if (isNaN(d)) d = today.getDate();
697
+ if (isNaN(hr)) hr = today.getHours();
698
+ if (isNaN(min)) min = today.getMinutes();
699
+ if (y != 0 && m != -1 && d != 0)
700
+ return new Date(y, m, d, hr, min, 0);
701
+ y = 0; m = -1; d = 0;
702
+ for (i = 0; i < a.length; ++i) {
703
+ if (a[i].search(/[a-zA-Z]+/) != -1) {
704
+ var t = -1;
705
+ for (j = 0; j < 12; ++j) {
706
+ if (Calendar.MONTH_NAMES[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
707
+ }
708
+ if (t != -1) {
709
+ if (m != -1) {
710
+ d = m+1;
711
+ }
712
+ m = t;
713
+ }
714
+ } else if (parseInt(a[i], 10) <= 12 && m == -1) {
715
+ m = a[i]-1;
716
+ } else if (parseInt(a[i], 10) > 31 && y == 0) {
717
+ y = parseInt(a[i], 10);
718
+ (y < 100) && (y += (y > 29) ? 1900 : 2000);
719
+ } else if (d == 0) {
720
+ d = a[i];
721
+ }
722
+ }
723
+ if (y == 0)
724
+ y = today.getFullYear();
725
+ if (m != -1 && d != 0)
726
+ return new Date(y, m, d, hr, min, 0);
727
+ return today;
728
+ };
729
+
730
+ // Returns the number of days in the current month
731
+ Date.prototype.getMonthDays = function(month) {
732
+ var year = this.getFullYear()
733
+ if (typeof month == "undefined")
734
+ month = this.getMonth()
735
+ if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1)
736
+ return 29
737
+ else
738
+ return Date.DAYS_IN_MONTH[month]
739
+ };
740
+
741
+ // Returns the number of day in the year
742
+ Date.prototype.getDayOfYear = function() {
743
+ var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
744
+ var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
745
+ var time = now - then;
746
+ return Math.floor(time / Date.DAY);
747
+ };
748
+
749
+ /** Returns the number of the week in year, as defined in ISO 8601. */
750
+ Date.prototype.getWeekNumber = function() {
751
+ var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
752
+ var DoW = d.getDay();
753
+ d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
754
+ var ms = d.valueOf(); // GMT
755
+ d.setMonth(0);
756
+ d.setDate(4); // Thu in Week 1
757
+ return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
758
+ };
759
+
760
+ /** Checks date and time equality */
761
+ Date.prototype.equalsTo = function(date) {
762
+ return ((this.getFullYear() == date.getFullYear()) &&
763
+ (this.getMonth() == date.getMonth()) &&
764
+ (this.getDate() == date.getDate()) &&
765
+ (this.getHours() == date.getHours()) &&
766
+ (this.getMinutes() == date.getMinutes()));
767
+ };
768
+
769
+ /** Set only the year, month, date parts (keep existing time) */
770
+ Date.prototype.setDateOnly = function(date) {
771
+ var tmp = new Date(date);
772
+ this.setDate(1);
773
+ this.setFullYear(tmp.getFullYear());
774
+ this.setMonth(tmp.getMonth());
775
+ this.setDate(tmp.getDate());
776
+ };
777
+
778
+ /** Prints the date in a string according to the given format. */
779
+ Date.prototype.print = function (str) {
780
+ var m = this.getMonth();
781
+ var d = this.getDate();
782
+ var y = this.getFullYear();
783
+ var wn = this.getWeekNumber();
784
+ var w = this.getDay();
785
+ var s = {};
786
+ var hr = this.getHours();
787
+ var pm = (hr >= 12);
788
+ var ir = (pm) ? (hr - 12) : hr;
789
+ var dy = this.getDayOfYear();
790
+ if (ir == 0)
791
+ ir = 12;
792
+ var min = this.getMinutes();
793
+ var sec = this.getSeconds();
794
+ s["%a"] = Calendar.SHORT_DAY_NAMES[w]; // abbreviated weekday name [FIXME: I18N]
795
+ s["%A"] = Calendar.DAY_NAMES[w]; // full weekday name
796
+ s["%b"] = Calendar.SHORT_MONTH_NAMES[m]; // abbreviated month name [FIXME: I18N]
797
+ s["%B"] = Calendar.MONTH_NAMES[m]; // full month name
798
+ // FIXME: %c : preferred date and time representation for the current locale
799
+ s["%C"] = 1 + Math.floor(y / 100); // the century number
800
+ s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
801
+ s["%e"] = d; // the day of the month (range 1 to 31)
802
+ // FIXME: %D : american date style: %m/%d/%y
803
+ // FIXME: %E, %F, %G, %g, %h (man strftime)
804
+ s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
805
+ s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
806
+ s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
807
+ s["%k"] = hr; // hour, range 0 to 23 (24h format)
808
+ s["%l"] = ir; // hour, range 1 to 12 (12h format)
809
+ s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
810
+ s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
811
+ s["%n"] = "\n"; // a newline character
812
+ s["%p"] = pm ? "PM" : "AM";
813
+ s["%P"] = pm ? "pm" : "am";
814
+ // FIXME: %r : the time in am/pm notation %I:%M:%S %p
815
+ // FIXME: %R : the time in 24-hour notation %H:%M
816
+ s["%s"] = Math.floor(this.getTime() / 1000);
817
+ s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
818
+ s["%t"] = "\t"; // a tab character
819
+ // FIXME: %T : the time in 24-hour notation (%H:%M:%S)
820
+ s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
821
+ s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON)
822
+ s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN)
823
+ // FIXME: %x : preferred date representation for the current locale without the time
824
+ // FIXME: %X : preferred time representation for the current locale without the date
825
+ s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
826
+ s["%Y"] = y; // year with the century
827
+ s["%%"] = "%"; // a literal '%' character
828
+
829
+ return str.gsub(/%./, function(match) { return s[match] || match });
830
+ };
831
+
832
+ Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
833
+ Date.prototype.setFullYear = function(y) {
834
+ var d = new Date(this);
835
+ d.__msh_oldSetFullYear(y);
836
+ if (d.getMonth() != this.getMonth())
837
+ this.setDate(28);
838
+ this.__msh_oldSetFullYear(y);
839
+ }
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Clockworkgeek_CalendarView</name>
4
+ <version>0.1</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.opensource.org/licenses/osl-3.0.php">OSL v3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Replace date picker with CalendarView</summary>
10
+ <description>Replaces the default (and ugly) (and buggy) javascript date picker with a newer, lightweight one from http://calendarview.org/</description>
11
+ <notes>Can be skinned entirely by modifying css/calendarview.css</notes>
12
+ <authors><author><name>Clockworkgeek</name><user>auto-converted</user><email>nonproffessional@clockworkgeek.com</email></author></authors>
13
+ <date>2010-12-02</date>
14
+ <time>23:17:57</time>
15
+ <contents><target name="magecommunity"><dir name="Clockworkgeek"><dir name="CalendarView"><dir name="Block"><dir name="Html"><file name="Date.php" hash="d4b4e1dd2c5e502acbec34a8be40f852"/></dir></dir><dir name="etc"><file name="config.xml" hash="ed6dd1e6030c299e4fc7833ea163bb7d"/></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="css"><file name="calendarview.css" hash="d70521aa7c6b49cd295231c64c192160"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="calendarview.xml" hash="65478900673f341210f73b6e49649e89"/></dir></dir></dir></dir></target><target name="mageweb"><dir name="js"><dir name="calendarview"><file name="calendarview.js" hash="cc2dc9484e911511d046f7e8e5d8c47d"/></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Clockworkgeek_CalendarView.xml" hash="e15dbdb8dff966babc0afffb340e76d7"/></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies/>
18
+ </package>
skin/frontend/base/default/css/calendarview.css ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ div.calendar
3
+ {
4
+ font-size: smaller;
5
+ color: #000;
6
+ z-index: 100;
7
+ }
8
+
9
+ div.calendar.popup
10
+ {
11
+ margin-left: -40px;
12
+ margin-top: -100px;
13
+ }
14
+
15
+ div.calendar table
16
+ {
17
+ background-color: #eee;
18
+ border: 1px solid #aaa;
19
+ border-collapse: collapse;
20
+ }
21
+
22
+ div.calendar thead {
23
+ background-color: white;
24
+ }
25
+
26
+ div.calendar td,
27
+ div.calendar th
28
+ {
29
+ padding: 3px;
30
+ text-align: center;
31
+ }
32
+
33
+ div.calendar td.title
34
+ {
35
+ font-weight: bold;
36
+ }
37
+
38
+ div.calendar th
39
+ {
40
+ background: #ddd;
41
+ border-bottom: 1px solid #ccc;
42
+ border-top: 1px solid #ccc;
43
+ font-weight: bold;
44
+ color: #555;
45
+ }
46
+
47
+ div.calendar tr.days td {
48
+ width: 2em;
49
+ color: #555;
50
+ text-align: center;
51
+ cursor: pointer;
52
+ }
53
+
54
+ div.calendar tr.days td:hover,
55
+ div.calendar td.button:hover
56
+ {
57
+ background-color: #34ABFA;
58
+ cursor: pointer;
59
+ }
60
+
61
+ div.calendar tr.days td:active
62
+ div.calendar td.button:active
63
+ {
64
+ background-color: #cde;
65
+ }
66
+
67
+ div.calendar tr.days td.selected
68
+ {
69
+ font-weight: bold;
70
+ background-color: #fff;
71
+ color: #000;
72
+ }
73
+
74
+ div.calendar tr.days td.today
75
+ {
76
+ font-weight: bold;
77
+ color: #D50000;
78
+ }
79
+
80
+ div.calendar tr.days td.otherDay
81
+ {
82
+ color: #bbb;
83
+ }