1 (function () {
2 var db = document.body;
3 var Calendar = function (opts) {
4 return new Calendar.prototype.init(opts);
5 };
6
7 Calendar.prototype = {
8 constructor: Calendar,
9 isHidden: true,
10 init: function (opts) {
11 this.opts = extend({
12 target: '',
13 initial: '09/27/2012',
14 format: 'MM/DD/YYYY',
15 callback: function () { }
16 }, opts || {});
17 var _this = this;
18 this.target = $(this.opts.target);
19 addEvent(this.target, 'click', function () { _this.create(); });
20 },
21 create: function () {
22 var de = this.target.getAttribute('data-date');
23 this.defaultValue = this.defaultValue || (de && new Date(de)) || (this.initial ? new Date(this.initial) : new Date());
24 var year = this.defaultValue.getFullYear(), month = this.defaultValue.getMonth(), date = this.defaultValue.getDate(), _this = this;
25 var days = this.calculateDays(year, month), fragment = document.createDocumentFragment(), ul = document.createElement('ul');
26 this.close();
27
28 var date_wrapper = this.opts.target + 'date_wrapper';
29 var date_header = this.opts.target + 'date_header';
30 var yearBox = this.opts.target + 'yearBox';
31 var prevYear = this.opts.target + 'prevYear';
32 var nextYear = this.opts.target + 'nextYear';
33 var monthBox = this.opts.target + 'monthBox';
34 var prevMonth = this.opts.target + 'prevMonth';
35 var nextMonth = this.opts.target + 'nextMonth';
36 var date_weekBox = this.opts.target + 'date_weekBox';
37 var date_dateBox = this.opts.target + 'date_dateBox';
38
39 var fmtdate_wrapper = this.opts.target + 'date_wrapper' + "' class='" + 'date_wrapper';
40 var fmtdate_header = this.opts.target + 'date_header' + "' class='" + 'date_header';
41 var fmtyearBox = this.opts.target + 'yearBox' + "' class='" + 'yearBox';
42 var fmtprevYear = this.opts.target + 'prevYear' + "' class='" + 'prevYear';
43 var fmtnextYear = this.opts.target + 'nextYear' + "' class='" + 'nextYear';
44 var fmtmonthBox = this.opts.target + 'monthBox' + "' class='" + 'monthBox';
45 var fmtprevMonth = this.opts.target + 'prevMonth' + "' class='" + 'prevMonth';
46 var fmtnextMonth = this.opts.target + 'nextMonth' + "' class='" + 'nextMonth';
47 var fmtdate_weekBox = this.opts.target + 'date_weekBox' + "' class='" + 'date_weekBox';
48 var fmtdate_dateBox = this.opts.target + 'date_dateBox' + "' class='" + 'date_dateBox';
49
50 var elstr =
51 "<div id='" + fmtdate_wrapper + "'>" +
52 "<div id='" + fmtdate_header + "'>" +
53 "<div id='" + fmtyearBox + "'>" +
54 "<span id='" + fmtprevYear + "'>«</span><em>" + year + "</em>" + "<span id='" + fmtnextYear + "'>»</span>" +
55 "</div>" +
56 "<div id='" + fmtmonthBox + "'>" +
57 "<span id='" + fmtprevMonth + "'>«</span><em>" + (month + 1) + "</em><span id='" + fmtnextMonth + "'>»</span>" +
58 "</div>" +
59 "</div>" +
60 "<div id='" + fmtdate_weekBox + "'>" +
61 "<ul><li>Sun</li><li>Mon</li><li>Tue</li><li>Thu</li><li>Wed</li><li>Fri</li><li>Sat</li></ul>" +
62 "</div>" +
63 "<div id='" + fmtdate_dateBox + "'>" +
64 "</div>" +
65 "</div>";
66 this.wrapper = createEl(elstr, db);
67
68 for (var i = 0, len = days.length; i < len; i++) {
69 var li = document.createElement('li');
70 var y = days[i].getFullYear(), m = days[i].getMonth(), d = days[i].getDate();
71 var f = m == month;
72 var fl = year == y && month == m && date == d;
73 li.setAttribute('data-date', days[i]);
74 li.innerHTML = d;
75 addClass(li, f ? 'black' : 'gray');
76 fl && addClass(li, 'current');
77 fragment.appendChild(li);
78 }
79 ul.appendChild(fragment);
80 $(date_dateBox).appendChild(ul);
81
82 setPosition(this.wrapper, this.target);
83
84 addEvent($(prevYear), 'click', function () {
85 _this.defaultValue.setMonth(_this.defaultValue.getMonth() - 12, date);
86 _this.create();
87 });
88 addEvent($(nextYear), 'click', function () {
89 _this.defaultValue.setMonth(_this.defaultValue.getMonth() + 12, date);
90 _this.create();
91 });
92 addEvent($(prevMonth), 'click', function () {
93 _this.defaultValue.setMonth(_this.defaultValue.getMonth() - 1, date);
94 _this.create();
95 });
96 addEvent($(nextMonth), 'click', function () {
97 _this.defaultValue.setMonth(_this.defaultValue.getMonth() + 1, date);
98 _this.create();
99 });
100 addEvent(ul, 'click', function (e) {
101 e = e || window.event;
102 var target = e.target || e.srcElement;
103 if (hasClass(target, 'black')) {
104 var date = target.getAttribute('data-date');
105 _this.target.setAttribute('data-date', date);
106 _this.defaultValue = new Date(date);
107 if (_this.target.type == 'text') _this.target.value = formatDate(date, _this.opts.format);
108 _this.opts.callback && _this.opts.callback(date);
109 _this.close();
110 };
111 });
112 addEvent(document.body, "click", function (e) {
113 e = e || window.event;
114 var target = e.target || e.srcElement;
115 if (target != _this.wrapper && target != _this.target) {
116 _this.close();
117 }
118 });
119 this.isHidden = false;
120 },
121 set: function (d) {
122 this.defaultValue = d ? new Date(d) : new Date();
123 this.create();
124 },
125 get: function () {
126 return this.defaultValue;
127 },
128 close: function () {
129 if (!this.wrapper) return;
130 this.wrapper.parentNode.removeChild(this.wrapper);
131 this.wrapper.innerHTML = "";
132 this.wrapper = null;
133 this.isHidden = true;
134 },
135 trigger: function () {
136 this.create();
137 },
138 calculateDays: function (y, m) {
139 var offset, dFirstDay = new Date(y, m, 1), dLastDay = new Date(y, m + 1, 0), arr = [];
140 dFirstDay.setMonth(m, 1 - dFirstDay.getDay());
141 dLastDay.setMonth(m, dLastDay.getDate() + 6 - dLastDay.getDay());
142 offset = parseInt((dLastDay - dFirstDay) / (1000 * 60 * 60 * 24)) + 1;
143 var _y = dFirstDay.getFullYear(), _m = dFirstDay.getMonth(), _d = dFirstDay.getDate();
144 for (var i = 0; i < offset; i++) {
145 var d = new Date(_y, _m, _d + i);
146 arr.push(d);
147 }
148 return arr;
149 }
150 };
151 Calendar.prototype.init.prototype = Calendar.prototype;
152 window.Calendar = Calendar;
153
154 function $(id) {
155 return typeof id == 'string' ? document.getElementById(id) : id;
156 };
157 function createEl(str, parent) {
158 var div = document.createElement('div'), el;
159 div.innerHTML = str;
160 el = div.firstChild;
161 parent && parent.appendChild(el);
162 return el;
163 };
164 function extend(t, s) {
165 for (var i in s) t[i] = s[i];
166 return t;
167 };
168 function getElementPos(el) {
169 var x = 0, y = 0;
170 if (el.getBoundingClientRect) {
171 var pos = el.getBoundingClientRect();
172 var d_root = document.documentElement, db = document.body;
173 x = pos.left + Math.max(d_root.scrollLeft, db.scrollLeft) - d_root.clientLeft;
174 y = pos.top + Math.max(d_root.scrollTop, db.scrollTop) - d_root.clientTop;
175 } else {
176 while (el != db) {
177 x += el.offsetLeft;
178 y += el.offsetTop;
179 el = el.offsetParent;
180 };
181 };
182 return {
183 x: x,
184 y: y
185 };
186 };
187 function setPosition(target, reference) {
188 var pos = getElementPos(reference);
189 var left = pos.x, top = pos.y;
190 var width = reference.offsetWidth, height = reference.offsetHeight;
191 var w = target.offsetWidth, h = target.offsetHeight;
192 var st = Math.max(document.documentElement.scrollTop, document.body.scrollTop), sl = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
193 var cw = document.documentElement.clientWidth, ch = document.documentElement.clientHeight;
194 if (ch + st - top - height - 1 > h) {
195 target.style.top = top + height + 1 + 'px';
196 } else {
197 target.style.top = top - h - 1 + 'px';
198 };
199 if (cw + sl - left - width > w) {
200 target.style.left = left + 'px';
201 } else {
202 target.style.left = left + width - w + 'px';
203 };
204 };
205 function addEvent(el, type, fn) {
206 if (typeof el.addEventListener != 'undefined') {
207 el.addEventListener(type, fn, false);
208 } else if (typeof el.attachEvent != 'undefined') {
209 el.attachEvent('on' + type, fn);
210 };
211 };
212 function formatDate(t, tpl) {
213 var strs = [], w, keys, year, val, t = t ? new Date(t) : new Date();
214 w = 'Month,Date,FullYear'.split(',');
215 keys = [/MM/g, /M/g, /DD/g, /D/g, /YYYY/g, /YY/g];
216 for (var i = 0; i < 3; i++) {
217 val = t['get' + w[i]]() + (w[i] === 'Month' ? 1 : 0);
218 strs.push(('0' + val).slice(-2), val)
219 };
220 year = (strs.slice(0, 4)).concat([strs[5], strs[4]]);
221 for (var i = 0; i < 6; i++) {
222 tpl = tpl.replace(keys[i], year[i])
223 };
224 return tpl;
225 };
226 function clear(str) {
227 return str.replace(/^\s+|\s+$/g, '').replace(/\s+/, ' ');
228 };
229 function hasClass(el, oClass) {
230 return (' ' + el.className + ' ').indexOf(' ' + oClass + ' ') > -1;
231 };
232 function addClass(el, oClass) {
233 if (hasClass(el, oClass)) return;
234 var c = el.className;
235 el.className = clear(c ? c + ' ' + oClass : oClass);
236 };
237 function removeClass(el, oClass) {
238 if (!hasClass(el, oClass)) return;
239 var c = el.className;
240 el.className = clear((' ' + c + ' ').replace(' ' + oClass + ' ', ''));
241 };
242 })();