Created
February 18, 2013 04:02
-
-
Save myaumyau/4975049 to your computer and use it in GitHub Desktop.
[js]自前カレンダー
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Calendar = function() { | |
this.initialize.apply(this, arguments); | |
} | |
Calendar.config = { | |
tags: { | |
header: "table", | |
headerChild: "tr", | |
thisMonth: "td", | |
prev: "td", | |
next: "td", | |
month: "table", | |
dayOfWeek: "th", | |
week: "tr", | |
day: "td" | |
}, | |
thisMonthFormat: "yyyy年MM月", | |
selectedFormat: "yyyy/MM/dd", | |
dayOfWeekNames: [ "日", "月", "火", "水", "木", "金", "土" ], | |
noClickDate: null | |
} | |
Calendar.prototype = { | |
/* Methods */ | |
initialize: function(config) { | |
if (!config["textboxId"]) throw("not setting textboxId."); | |
if (!config["triggerId"]) throw("not setting triggerId."); | |
if (!config["areaId"]) throw("not setting areaId."); | |
this._textNode = this.getNode(config["textboxId"]); | |
if (!this._textNode) throw("not found textboxId node."); | |
this._triggerNode = this.getNode(config["triggerId"]); | |
if (!this._triggerNode) throw("not found triggerId node."); | |
this._areaId = config["areaId"]; | |
this._config = {}; | |
for( var key in Calendar.config ) { | |
if (!config[key]) { | |
this._config[key] = Calendar.config[key]; | |
} else { | |
this._config[key] = config[key]; | |
} | |
} | |
this._uniqueId = "Calendar_" + DateTime.now().totalMilliseconds(); | |
this._today = DateTime.today(); | |
this._selectedDate = this._today; | |
this._currentMonth = new DateTime(this._today.year(), this._today.month(), 1); | |
this._visible = false; | |
this._iframe = null; | |
this._div = null; | |
this.hide(); | |
this.update(); | |
var __this = this; | |
// regster event | |
addEvent(this._triggerNode, "click", function() { | |
__this.show(); | |
}); | |
addEvent(this._div, "mouseover", function() { | |
__this._visible = false; | |
}); | |
addEvent(this._div, "mouseout", function() { | |
__this._visible = true; | |
}); | |
addEvent(document, "mousedown", function() { | |
if (__this._visible) { | |
__this.hide(); | |
} | |
}); | |
// register global | |
window[this._uniqueId] = this; | |
}, | |
getNode: function(id) { | |
return document.getElementById(id); | |
}, | |
/* | |
toggle: function() { | |
return this._visible ? this.hide() : this.show(); | |
}, | |
*/ | |
select: function(yyyyMMdd) { | |
this._selectedDate = new DateTime(yyyyMMdd.substr(0, 4), yyyyMMdd.substr(4, 2), yyyyMMdd.slice(6)); | |
this._textNode.value = this._selectedDate.toString(this._config.selectedFormat); | |
this.update(); | |
this.hide(); | |
}, | |
prevMonth: function() { | |
this._currentMonth = this._currentMonth.addMonths(-1); | |
this.update(); | |
}, | |
nextMonth: function() { | |
this._currentMonth = this._currentMonth.addMonths(1); | |
this.update(); | |
}, | |
show: function() { | |
this.ensureArea(); | |
this._visible = true; | |
this.setDivStyle(); | |
}, | |
hide: function() { | |
this.ensureArea(); | |
this._visible = false; | |
this.setDivStyle(); | |
}, | |
update: function() { | |
this.render(); | |
}, | |
render: function() { | |
var htmlBuilder = new StringBuilder(); | |
this.renderHeader(htmlBuilder); | |
this.renderMonth(htmlBuilder); | |
var calendarContent = htmlBuilder.toString(); | |
this._div.innerHTML = calendarContent; | |
}, | |
renderHeader: function(htmlBuilder) { | |
htmlBuilder.appendFormat('<{0} class="{1}">', this._config.tags.header, "calendarHeader"); | |
htmlBuilder.appendFormat('<{0}>', this._config.tags.headerChild); | |
// prev | |
var prevClick = String.format("window['{0}'].prevMonth();", this._uniqueId); | |
htmlBuilder.appendFormat('<{0} class="{1}"><a href="javascript:;" onclick="{2}"><span><</span></a></{0}>', this._config.tags.prev, "prev", prevClick); | |
// this month name | |
htmlBuilder.appendFormat('<{0} class="{1}">{2}</{0}>', this._config.tags.thisMonth, "thisMonth", this._currentMonth.toString(this._config.thisMonthFormat)); | |
// next | |
var nextClick = String.format("window['{0}'].nextMonth();", this._uniqueId); | |
htmlBuilder.appendFormat('<{0} class="{1}"><a href="javascript:;" onclick="{2}"><span>></span></a></{0}>', this._config.tags.next, "next", nextClick); | |
htmlBuilder.appendFormat('</{0}>', this._config.tags.headerChild); | |
htmlBuilder.appendFormat('</{0}>', this._config.tags.header); | |
}, | |
renderMonth: function(htmlBuilder) { | |
var renderDate = this.calcFirstDateOnCalendar(); | |
htmlBuilder.appendFormat('<{0} class="calendar">', this._config.tags.month); | |
// render 7 week | |
for (var iWeek = 0; iWeek < 7; iWeek++) { | |
var isDay = iWeek != 0; | |
this.renderWeek(htmlBuilder, renderDate, isDay); | |
if (isDay) { | |
renderDate = renderDate.addDays(7); | |
} | |
} | |
htmlBuilder.appendFormat('</{0}>', this._config.tags.month); | |
}, | |
renderWeek: function(htmlBuilder, renderDate, isDay) { | |
// render 1 week | |
htmlBuilder.appendFormat('<{0} class="{1}">', this._config.tags.week, !isDay ? "dayOfWeek" : ""); | |
for (var iDayOfWeek = 0; iDayOfWeek < 7; iDayOfWeek++) { | |
if (isDay) { | |
this.renderDay(htmlBuilder, renderDate); | |
// next day | |
renderDate = renderDate.addDays(1); | |
} else { | |
this.renderDayOfWeek(htmlBuilder, iDayOfWeek); | |
} | |
} | |
htmlBuilder.appendFormat('</{0}>', this._config.tags.week); | |
}, | |
renderDayOfWeek: function(htmlBuilder, dayOfWeek) { | |
var dayOfWeekName = this._config.dayOfWeekNames[dayOfWeek]; | |
htmlBuilder.appendFormat('<{0}>{1}</{0}>', this._config.tags.dayOfWeek, dayOfWeekName); | |
}, | |
renderDay: function(htmlBuilder, renderDate) { | |
var tdClass = []; | |
// dayOfWeek class | |
var dayOfWeek = renderDate.dayOfWeek(); | |
switch (dayOfWeek) { | |
// sunday | |
case 0: | |
tdClass.push("sunday"); | |
break; | |
// saturday | |
case 6: | |
tdClass.push("satuday"); | |
break; | |
// other | |
default: | |
break; | |
} | |
// other month class | |
if (this._currentMonth.month() != renderDate.month()) { | |
tdClass.push("otherMonth"); | |
} | |
// selected date class | |
if (this._selectedDate.equals(renderDate)) { | |
tdClass.push("selected"); | |
} | |
// today class | |
if (this._today.equals(renderDate)) { | |
tdClass.push("today"); | |
} | |
var noClick = false; | |
if (this._config.noClickDate) { | |
try { | |
var date = this._config.noClickDate; | |
var noClickDate = new DateTime(date.substr(0, 4), date.substr(4, 2), date.substr(6, 2)); | |
noClick = noClickDate.compareTo(renderDate) >= 0; | |
} catch(e) { | |
} | |
} | |
var onclick = String.format("window['{0}'].select('{1}');", this._uniqueId, renderDate.toString("yyyyMMdd")); | |
if (noClick) { | |
onclick = ""; | |
tdClass.push("noclick"); | |
} | |
htmlBuilder.appendFormat( | |
'<{0} class="{1}" onclick="{2}">{3}</{0}>', | |
this._config.tags.day, | |
tdClass.join(' '), | |
onclick, | |
renderDate.day()); | |
}, | |
ensureArea: function() { | |
if(!this._div) { | |
this._div = document.createElement('div'); | |
this._div.id = this._areaId; | |
this._div.className = 'popupCalendarArea'; | |
document.body.appendChild(this._div); | |
} | |
}, | |
calcFirstDateOnCalendar: function() { | |
var date = this._currentMonth; | |
var firstDayOnMonth = new DateTime(date.year(), date.month(), 1); | |
var firstDayOnMonthDayOfWeek = firstDayOnMonth.dayOfWeek(); | |
return firstDayOnMonth.addDays(firstDayOnMonthDayOfWeek == 0 ? 0 : 0 - firstDayOnMonthDayOfWeek); | |
}, | |
getElementScreenPosition: function(elm) { | |
//var html = document.documentElement; | |
var html = elm.ownerDocument.documentElement; | |
var rect = null; | |
if (elm.getBoundingClientRect) { | |
rect = elm.getBoundingClientRect(); | |
} else if (document.getBoxObjectFor) { | |
pos = document.getBoxObjectFor(elm); | |
rect = { left: pos.x, top: pos.y }; | |
} else { | |
return null; | |
} | |
var left = rect.left - (html.clientLeft ? html.clientLeft : 0); | |
var top = rect.top - (html.clientTop ? html.clientTop : 0); | |
return { "left": left, "top": top }; | |
}, | |
getPosition: function(elm){ | |
var height = elm.offsetHeight; | |
// スクロール幅を取得 | |
var html = document.documentElement; | |
var body = document.body; | |
var scrollLeft = (body.scrollLeft || html.scrollLeft); | |
var scrollTop = (body.scrollTop || html.scrollTop); | |
// 画面内座標を取得 | |
var pos = this.getElementScreenPosition(elm); | |
// スクロール幅を加算 | |
var left = pos.left + scrollLeft; | |
var top = pos.top + scrollTop; | |
return {"left" : left, "top" : top }; | |
}, | |
setDivStyle: function() { | |
var elm = this._triggerNode; | |
var pos = this.getPosition(elm); | |
this._div.style.position = 'absolute'; | |
this._div.style.zIndex = 9999; | |
this._div.style.display = this._visible ? "" : "none"; | |
this._div.style.top = pos.top + elm.offsetHeight; | |
this._div.style.left = pos.left; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment