jui.defineUI("ui.datepicker", [ "jquery", "util.base" ], function($, _) { function getStartDate(date) { date.setHours(0); date.setMinutes(0); date.setSeconds(0); date.setMilliseconds(0); return date; } /** * @class ui.datepicker * @extends core * @alias Date Picker * @requires jquery * @requires util.base */ var UI = function() { var year = null, month = null, date = null, selDate = null, items = {}; // 헌재 페이지의 요소 엘리먼트 캐싱 var $head = null, $body = null; var minDate = null, maxDate = null; function setCalendarEvent(self) { self.addEvent($head.children(".prev"), "click", function(e) { self.prev(e); }); self.addEvent($head.children(".next"), "click", function(e) { self.next(e); }); self.addEvent($head.children(".prev-year"), "click", function(e) { self.prev(e, true); }); self.addEvent($head.children(".next-year"), "click", function(e) { self.next(e, true); }); } function setCalendarDate(self, no) { var opts = self.options; if(opts.type == "daily") { var m = (month < 10) ? "0" + month : month, d = (no < 10) ? "0" + no : no; selDate = new Date(year + "/" + m + "/" + d); } else if(opts.type == "monthly") { var m = (no < 10) ? "0" + no : no; selDate = new Date(year + "/" + m + "/01"); } else if(opts.type == "yearly") { selDate = new Date(no + "/01/01"); } // 0시 0분 0초 0밀리 초로 설정 selDate = getStartDate(selDate); } function getCalendarDate(self) { var opts = self.options, tmpDate = null; if(opts.type == "daily") { var m = (month < 10) ? "0" + month : month; tmpDate = new Date(year + "/" + m + "/01"); } else if(opts.type == "monthly") { tmpDate = new Date(year + "/01/01"); } else if(opts.type == "yearly") { tmpDate = new Date(); } return getStartDate(tmpDate); } function getCalendarHtml(self, obj) { var opts = self.options, resHtml = [], tmpItems = []; // 활성화 날짜 캐시 초기화 items = {}; if(self.tpl["date"]) { for(var i = 0; i < obj.objs.length; i++) { tmpItems.push(self.tpl["date"]({ type: obj.objs[i].type, date: obj.objs[i].no, day: tmpItems.length })); if(isNextBr(i)) { resHtml.push("<tr>" + tmpItems.join("") + "</tr>"); tmpItems = []; } } } else { for(var i = 0; i < obj.objs.length; i++) { tmpItems.push(obj.nums[i]); if(isNextBr(i)) { resHtml.push(self.tpl["dates"]({ dates: tmpItems })); tmpItems = []; } } } var $list = $(resHtml.join("")); $list.find("td").each(function(i) { $(this).addClass(obj.objs[i].type); self.addEvent(this, "click", function(e) { if(obj.objs[i].type == "none") return; $body.find("td").removeClass("active"); $(this).addClass("active"); setCalendarDate(self, obj.objs[i].no); self.emit("select", [ self.getFormat(), e ]); }); if(obj.objs[i].type != "none") { items[obj.objs[i].no] = this; } }); function isNextBr(i) { return (opts.type == "daily") ? ((i + 1) % 7 == 0) : ((i + 1) % 3 == 0); } return $list; } function getLastDate(year, month) { if(month == 2) { if(year % 100 != 0 && (year % 4 == 0 || year % 400 == 0)) return 29; else return 28; } else { var months = [ 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; return months[month - 1]; } } function getDateList(self, y, m) { var objs = [], nums = [], no = 1; var d = new Date(), start = new Date(y + "-" + ((m < 10) ? "0" + m : m)).getDay(), ldate = getLastDate(y, m), sdate = 0; var prevYear = (m == 1) ? y - 1 : y, prevMonth = (m == 1) ? 12 : m - 1, prevLastDay = getLastDate(prevYear, prevMonth); // 최소 날짜로 시작일 설정 if(minDate && minDate.getFullYear() == y && minDate.getMonth() + 1 == m) { sdate = minDate.getDate(); } // 최대 날짜로 종료일 설정 if(maxDate && maxDate.getFullYear() == y && maxDate.getMonth() + 1 == m) { ldate = maxDate.getDate(); } for(var i = 0; i < start; i++) { nums[i] = (prevLastDay - start) + (i + 1); objs[i] = { type: "none", no: nums[i] }; } for(var i = start; i < 42; i++) { if(sdate <= no && no <= ldate) { var type = ""; if(d.getMonth() + 1 == m && d.getDate() == no) { type = "now"; } if(selDate != null) { if(selDate.getFullYear() == y && selDate.getMonth() + 1 == m && selDate.getDate() == no) { type = "active"; } } nums[i] = no; objs[i] = { type: type, no: nums[i] }; no++; } else { nums[i] = no - ldate; objs[i] = { type: "none", no: nums[i] }; no++; } } return { objs: objs, nums: nums }; } function getMonthList(y) { var objs = [], nums = []; var d = new Date(); for(var i = 1; i <= 12; i++) { var type = ""; if(d.getFullYear() == y && d.getMonth() + 1 == i) { type = "now"; } if(selDate != null) { if(selDate.getFullYear() == y && selDate.getMonth() + 1 == i) { type = "active"; } } nums.push(i); objs.push({ type: type, no: i }); } return { objs: objs, nums: nums }; } function getYearList(y) { var objs = [], nums = [], startYear = y - 4; var d = new Date(); for(var i = startYear; i < startYear + 12; i++) { var type = ""; if(d.getFullYear() == i) { type = "now"; } if(selDate != null) { if(selDate.getFullYear() == i) { type = "active"; } } nums.push(i); objs.push({ type: type, no: i }); } return { objs: objs, nums: nums }; } function checkDate(y, m, d) { if(minDate) { var minY = minDate.getFullYear(), minM = minDate.getMonth() + 1, minD = minDate.getDate(); if (y < minY || (y == minY && m < minM)) return [minY, minM, minD]; } if(maxDate) { var maxY = maxDate.getFullYear(),maxM = maxDate.getMonth() + 1, maxD = maxDate.getDate() if (y > maxY || (y == maxY && m > maxM)) return [maxY, maxM, maxD]; } return [y, m, d]; } this.init = function() { var opts = this.options; $head = $(this.root).children(".head"); $body = $(this.root).children(".body"); minDate = (_.typeCheck("date", opts.minDate)) ? opts.minDate : null; maxDate = (_.typeCheck("date", opts.maxDate)) ? opts.maxDate : null; if(opts.type == "daily") { // 기본 날짜가 최소 날짜나 최대 날짜보다 작거나 큰 경우 if(opts.date < minDate) { opts.date = minDate; } else if(opts.date < minDate) { opts.date = maxDate; } // 최소 날짜와 최대 날짜가 서로 교차하는 경우 if(minDate && maxDate && maxDate < minDate) { minDate = null; maxDate = null; } } // 이벤트 정의 setCalendarEvent(this); // 기본 날짜 설정 this.select(opts.date); } /** * @method page * Outputs a calendar that fits the year/month entered * * @param {Integer} year * @param {Integer} month */ this.page = function(y, m) { if(arguments.length == 0) return; var opts = this.options; if(opts.type == "daily") { year = y; month = m; $body.find("tr:not(:first-child)").remove(); $body.append(getCalendarHtml(this, getDateList(this, year, month))); } else if(opts.type == "monthly") { year = y; $body.find("tr").remove(); $body.append(getCalendarHtml(this, getMonthList(year))); } else if(opts.type == "yearly") { year = y; $body.find("tr").remove(); $body.append(getCalendarHtml(this, getYearList(year))); } $head.children(".title").html(_.dateFormat(getCalendarDate(this), opts.titleFormat)); } /** * @method prev * Outputs a calendar that fits the previous year/month * */ this.prev = function(e, moveYear) { var opts = this.options; if(opts.type == "daily") { if (moveYear) { var y = year - 1, m = month; } else { var y = (month == 1) ? year - 1 : year, m = (month == 1) ? 12 : month - 1; } if(minDate && minDate.getFullYear() == year && minDate.getMonth() + 1 == month) { return; } this.page(y, m); } else if(opts.type == "monthly") { this.page(year - 1); } else if(opts.type == "yearly") { this.page(year - 12); } this.emit("prev", [ e ]); } /** * @method next * Outputs a calendar that fits the next year/month * */ this.next = function(e, moveYear) { var opts = this.options; if(opts.type == "daily") { if (moveYear) { var y = year + 1, m = month; } else { var y = (month == 12) ? year + 1 : year, m = (month == 12) ? 1 : month + 1; } if(maxDate && maxDate.getFullYear() == year && maxDate.getMonth() + 1 == month) { return; } this.page(y, m); } else if(opts.type == "monthly") { this.page(year + 1); } else if(opts.type == "yearly") { this.page(year + 12); } this.emit("next", [ e ]); } /** * @method select * Selects today if there is no value, or selects a date applicable to a timestamp or year/month/date * * @param {"year"/"month"/"date"/"timestamp"/"Date"} */ this.select = function() { var opts = this.options, args = arguments; if(args.length == 0) { y = year; m = month; d = date; } else if(args.length == 3) { y = args[0]; m = args[1]; d = args[2]; } else if(args.length == 1) { var time = (_.typeCheck("date", args[0])) ? args[0] : new Date(args[0]); y = time.getFullYear(); m = time.getMonth() + 1; d = time.getDate(); } if(opts.type == "daily") { // 최소일과 최대일이 교차하는 경우 if(minDate || maxDate) { var checkedDate = checkDate(y, m, d); this.page(checkedDate[0], checkedDate[1]); this.addTrigger(items[checkedDate[2]], "click"); } this.page(y, m); this.addTrigger(items[d], "click"); } else if(opts.type == "monthly") { this.page(y); this.addTrigger(items[m], "click"); } else if(opts.type == "yearly") { this.page(y); this.addTrigger(items[y], "click"); } } /** * @method addTime * Selects a date corresponding to the time added to the currently selected date * * @param {"Integer"/"Date"} time Timestamp or Date */ this.addTime = function(time) { selDate = new Date(this.getTime() + time); this.select(this.getTime()); } /** * @method getDate * Gets the value of the date currently selected * * @return {Date} Date object */ this.getDate = function() { return selDate; } /** * @method getTime * Gets the timestamp value of the date currently selected * * @return {Integer} Timestamp */ this.getTime = function() { return selDate.getTime(); } /** * @method getFormat * Gets a date string that fits the format entered * * @return {String} format Formatted date string */ this.getFormat = function(format) { return _.dateFormat(selDate, (typeof(format) == "string") ? format : this.options.format); } /** * @method reload * Reloads the datepicker */ this.reload = function() { var opts = this.options; minDate = (_.typeCheck("date", opts.minDate)) ? opts.minDate : null; maxDate = (_.typeCheck("date", opts.maxDate)) ? opts.maxDate : null; if(opts.type == "daily") { // 기본 날짜가 최소 날짜나 최대 날짜보다 작거나 큰 경우 if(minDate && opts.date < minDate) { opts.date = minDate; } else if(maxDate && opts.date > maxDate) { opts.date = maxDate; } } this.select(); this.emit("reload"); } } UI.setup = function() { var now = getStartDate(new Date()); return { /** * @cfg {"daily"/"monthly"/"yearly"} [type="daily"] * Determines the type of a calendar */ type: "daily", /** * @cfg {String} [titleFormat="yyyy.MM"] * Title format of a calendar */ titleFormat: "yyyy.MM", /** * @cfg {String} [format="yyyy-MM-dd"] * Format of the date handed over when selecting a specific date */ format: "yyyy-MM-dd", /** * @cfg {Date} [date="now"] * Selects a specific date as a basic */ date: now, /** * @cfg {Boolean} [animate=false] * @deprecated */ animate: false, /** * @cfg {Date} [minDate="null"] * Selects a specific minimum date */ minDate: null, /** * @cfg {Date} [maxDate="null"] * Selects a specific maximum date */ maxDate: null }; } /** * @event select * Event that occurs when selecting a specific date * * @param {String} value Formatted date string * @param {EventObject} e The event object */ /** * @event prev * Event that occurs when clicking on the previous button * * @param {EventObject} e The event object */ /** * @event next * Event that occurs when clicking on the next button * * @param {EventObject} e The event object */ return UI; });