// Copyright (c) 2006 spinelz.org (http://script.spinelz.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var Calendar = Class.create();
Calendar.className = {
container: 'calendar',
header: 'calendar_header',
preYears: 'calendar_preYears',
nextYears: 'calendar_nextYears',
years: 'calendar_years',
mark: 'calendar_mark',
ym: 'calendar_ym',
table: 'calendar_table',
thRight: 'right',
tdRight: 'right',
tdBottom: 'bottom',
date: 'calendar_date',
holiday: 'calendar_holiday',
regularHoliday: 'calendar_regularHoliday',
schedule: 'calendar_schedule',
highlightDay: 'calendar_highlightDay',
highlightTime: 'calendar_highlightTime',
scheduleListContainer: 'calendar_scheduleListContainer',
scheduleItem: 'calendar_scheduleItem',
scheduleTimeArea: 'calendar_scheduleItemTimeArea',
scheduleHandler: 'calendar_scheduleHandler',
holidayName: 'calendar_holidayName',
// holidayContainer: 'calendar_holidayContainer',
dateContainer: 'calendar_dateContainer',
tableHeader: 'calendar_tableHeader',
rowContent: 'calendar_rowContent',
selected: 'calendar_selected',
nextYearMark: 'calendar_nextYearMark',
nextMonthMark: 'calendar_nextMonthMark',
nextWeekMark: 'calendar_nextWeekMark',
preYearMark: 'calendar_preYearMark',
preMonthMark: 'calendar_preMonthMark',
preWeekMark: 'calendar_preWeekMark',
weekTable: 'calendar_weekContainerTable',
weekMainTable: 'calendar_weekMainTable',
timeLine: 'calendar_timeline',
timeLineTimeTop: 'calendar_timelineTimeTop',
timeLineTime: 'calendar_timelineTime',
headerColumn: 'calendar_headerColumn',
columnTopDate: 'calendar_columnTopDate',
columnDate: 'calendar_columnDate',
columnDateOdd: 'calendar_columnOddDate',
scheduleItemSamll: 'calendar_scheduleItemSmall',
scheduleItemLarge: 'calendar_scheduleItemLarge',
scheduleItemNoBorder: 'calendar_scheduleItemNoBorder',
scheduleItemSelect: 'calendar_scheduleItemSelect',
skipNode: 'calendar_skipNode',
deleteImg: 'calendar_deleteImage',
privateImg: 'calendar_privateImage',
scheduleContainer: 'calendar_weekScheduleContainer',
selector: 'calendar_selector',
cover: 'calendar_cover'
}
Calendar.smallClassName = {
container: 'calendar_small',
header: 'calendar_header_small',
calendar: 'calendar_calendar_small',
table: 'calendar_tableSmall'
}
Calendar.size = {
large: 'large',
small: 'small'
}
/**
* Calendar Class
*/
Calendar.prototype = {
initialize: function(element) {
this.building = true;
this.element = $(element);
this.options = Object.extend({
initDate: new Date(),
cssPrefix: 'custom_',
holidays: [],
schedules: [],
size: Calendar.size.large,
regularHoliday: [0, 6],
displayIndexes: [0, 1, 2, 3, 4, 5, 6],
displayTime: [{hour: 0, min: 0}, {hour: 24, min: 0}],
weekIndex: 0,
dblclickListener: null,
afterSelect: Prototype.emptyFunction,
beforeRefresh: Prototype.emptyFunction,
changeSchedule: Prototype.emptyFunction,
changeCalendar: Prototype.emptyFunction,
displayType: 'month',
highlightDay: true,
beforeRemoveSchedule: function() { return true; },
dblclickSchedule: null,
updateTirm: Prototype.emptyFunction,
displayTimeLine: true,
clickDateText: null,
monthHeaderFormat: null,
weekHeaderFormat: null,
weekSubHeaderFormat: null,
dayHeaderFormat: null,
dayOfWeek: DateUtil.dayOfWeek,
skipString: '... more',
noEvent: false,
build: true
}, arguments[1] || {});
this.date = this.options.initDate;
this.options.holidays = this.toHolidayHash(this.options.holidays);
if (this.options.build) {
Element.setStyle(this.element, {visibility: 'hidden'});
Element.hide(this.element);
this.setIndex();
this.makeCss();
this.element.innerHTML = this.build();
Element.setStyle(this.element, {visibility: 'visible'});
Element.show(this.element);
this.builder.afterBuild();
this.builder.setEvent();
} else {
this.makeCss();
this.build();
this.builder.afterBuild();
}
Event.observe(document, "mouseup", this.onMouseUp.bindAsEventListener(this));
this.building = false;
this.windowResize = this.onResize.bind(this);
if (this.options.size != 'small') Event.observe(window, "resize", this.windowResize);
},
makeCss: function() {
this.classNames = null;
if (this.options.size == Calendar.size.large) {
this.classNames = Calendar.className;
} else {
this.classNames = $H({}).merge(Calendar.className);
this.classNames = this.classNames.merge(Calendar.smallClassName);
}
this.css = CssUtil.getInstance(this.options.cssPrefix, this.classNames);
this.classNames = this.css.allJoinClassNames();
},
onResize: function() {
try {
var oldDimentions = this.builder.containerDimensions;
var dimentions = Element.getDimensions(this.builder.container);
if (dimentions.height != oldDimentions.height || dimentions.width != oldDimentions.width) {
this.refresh();
}
} catch(e) {}
},
destroy: function() {
Event.stopObserving(window, 'resize', this.windowResize);
},
setIndex: function() {
var options = this.options;
options.displayIndexes = this.sortWeekIndex(options.displayIndexes);
this.setLastWday();
},
sortWeekIndex: function(indexes) {
var options = this.options;
var bottom = [];
var up = [];
var index = null;
indexes.sort();
indexes.each(function(i) {
if (index == null) {
if (options.weekIndex <= i) {
index = i;
up.push(i);
} else {
bottom.push(i);
}
} else {
up.push(i);
}
});
return up.concat(bottom);
},
setLastWday: function() {
var firstIndex = this.options.weekIndex;
var sat = 6;
var sun = 0;
var week = $R(firstIndex, sat, false).toArray();
if (firstIndex != sun) {
week = week.concat($R(sun, firstIndex - 1, false).toArray());
}
this.lastWday = week.last();
this.wdays = week;
},
build: function() {
if (this.builder) {
this.builder.destroy();
}
if (this.options.displayType == 'week') {
this.builder = new CalendarWeek(this);
} else if (this.options.displayType == 'day') {
this.builder = new CalendarDay(this);
} else {
this.builder = new CalendarMonth(this);
}
this.builder.beforeBuild();
if (this.options.build) return this.builder.build();
},
/*** Calendar ***/
/********************************** public method **********************************/
undo: function() {
if (this.cached) {
this.cached.start = this.cached.start_old;
this.cached.finish = this.cached.finish_old;
this.cached = null;
this.refreshSchedule();
}
},
hideSatSun: function() {
var sun = 0;
var sat = 6;
this.options.displayIndexes = this.options.displayIndexes.without(sun, sat);
this.setIndex();
this.refresh();
},
showSatSun: function() {
var sun = 0;
var sat = 6;
var indexes = this.options.displayIndexes;
if (!indexes.include(sun)) {
indexes.push(sun);
}
if (!indexes.include(sat)) {
indexes.push(sat);
}
this.setIndex();
this.refresh();
},
changeDisplayIndexes: function(indexes) {
this.options.displayIndexes = indexes;
this.setIndex();
this.refresh();
},
changeDisplayTime: function(time) {
this.options.displayTime = time;
this.refresh();
},
refresh: function() {
try {
if (!this.building) {
this.building = true;
this.options.build = true;
this.options.beforeRefresh(this);
this.destroy();
this.selectedBase = null;
this.element.innerHTML = this.build();
this.builder.afterBuild();
this.builder.setEvent();
if (this.options.size != 'small') Event.observe(window, 'resize', this.windowResize);
this.building = false;
}
} catch (e) {
// do nothing
}
},
changeCalendar: function(event) {
this.builder.changeCalendar(event);
},
changeDisplayType: function(type) {
this.options.displayType = type;
this.refresh();
},
selectDate: function(event) {
var calendar = this;
this.abstractSelect(event, function(date, element) {
if (calendar.selectedBase || calendar.hasSelectedDate()) {
if (event.ctrlKey) {
if (Element.hasClassName(element, Calendar.className.selected)) {
calendar.addSelectedClass(element);
return;
}
} else if (calendar.selectedBase) {
var selectedId = calendar.selectedBase.id;
$(selectedId).className = calendar.selectedBase.className;
calendar.clearSelected();
if (selectedId == element.id) {
calendar.selectedBase = null;
return;
}
}
}
calendar.selectedBase = {id: element.id, date: date, className: element.className};
calendar.addSelectedClass(element);
if (date && calendar.options.displayType == 'month' && calendar.options.size == Calendar.size.small) {
calendar.options.afterSelect(date, calendar);
}
});
if (calendar.options.displayType != 'month' || calendar.options.size != Calendar.size.small) {
this.mouseDown = true;
}
},
clearSelect: function() {
this.selectedBase = null;
this.clearSelected();
},
showDayOfWeek: function(dayOfWeek) {
var indexes = this.options.displayIndexes;
this.recurrence(dayOfWeek, function(d) {
if (!indexes.include(d)) {
indexes.push(d);
}
});
this.setIndex();
this.refresh();
},
hideDayOfWeek: function(dayOfWeek) {
var indexes = this.options.displayIndexes;
var self = this;
this.recurrence(dayOfWeek, function(d) {
var index = self.findIndex(indexes, d);
if (index) {
indexes.remove(index);
} else if (!index.isNaN) {
indexes.shift();
}
});
this.refresh();
},
addHoliday: function(object) {
object = this.inspectArgument(object);
var newHash = this.toHolidayHash(object);
this.options.holidays = this.options.holidays.merge(newHash);
this.refresh();
},
removeHoliday: function(date) {
var calendar = this;
date = calendar.inspectDateArgument(date);
if (!date) return;
this.recurrence(date, function(d) {
var key = d.toDateString();
if (calendar.options.holidays[key])
delete calendar.options.holidays[key];
});
this.refresh();
},
refreshHoliday: function(object, rebuild) {
object = this.inspectArgument(object);
this.options.holidays = this.toHolidayHash(object);
if (rebuild) this.refresh();
},
clearHoliday: function() {
this.refreshHoliday([], true);
},
getHoliday: function(date) {
date = this.inspectDateArgument(date);
if (!date) return;
var calendar = this;
var holidays = [];
this.recurrence(date, function(o) {
var h = calendar.options.holidays[o.toDateString()];
if (h) holidays.push(h);
});
return holidays;
},
addSchedule: function(schedule) {
var schedules = this.options.schedules;
if (schedule.constructor == Array) {
schedule.each(function(s) {
var find = schedules.detect(function(tmp) {return s.id == tmp.id});
if (!find) schedules.push(s);
});
} else {
var find = schedules.detect(function(tmp) {return tmp.id == schedule.id});
if (!find) schedules.push(schedule);
}
this.refreshSchedule();
},
replaceSchedule: function(schedules) {
this.options.schedules = schedules;
this.refreshSchedule();
},
removeSchedule: function(ids, refresh) {
if (ids.constructor != Array) ids = [ids];
var self = this;
ids.each(function(id) {
var index = null;
self.options.schedules.each(function(s, i) {
if (s.id == id) {
index = i;
throw $break;
}
});
if (index != null) {
var schedule = self.options.schedules[index];
if (schedule) {
self.options.schedules.remove(index);
}
}
});
if (refresh) this.refreshSchedule();
},
refreshSchedule: function() {
this.builder.scheduleNodes.each(function(node) { Element.remove(node); });
(this.builder.skipNode || []).each(function(pair) { Element.remove(pair.value); });
this.builder.afterBuild();
},
mergeSchedule: function(schedule) {
var index = -1;
this.options.schedules.each(function(s, i) {
if (s.id == schedule.id) {
index = i;
throw $break;
}
});
if (index != -1) {
this.options.schedules[index] = schedule;
this.refreshSchedule();
} else {
this.addSchedule(schedule);
}
},
clearSchedule: function() {
this.options.schedules = [];
this.refreshSchedule();
},
getSchedule: function(object) {
var result = [];
var calendar = this;
object = this.inspectArgument(object || {});
this.recurrence(object, function(o) {
var schedule = calendar.options.schedules[o.date.toDateString()];
if (!schedule) return;
if (o.start) {
schedule = schedule.detect(function(s) {
return ((s.start.hour == o.start.hour) && (s.start.min == o.start.min));
});
if (schedule) result.push(schedule);
} else if (o.number) {
schedule = schedule[o.number];
if (schedule) result.push(schedule);
} else {
result = result.concat(schedule);
}
});
return result;
},
getSelected: function() {
return this.element.getElementsByClassName(Calendar.className.selected, this.element);
},
changeSchedule: function() {
var calendar = this;
return function(drag, drop) {
var array = drag.id.split('_');
var i = array.pop();
var date = array.pop();
date = calendar.getDate(date);
var newDate = calendar.getDate(drop);
var schedule = calendar.getSchedule({date: date, number: i});
if (schedule.length != 1) return;
schedule = schedule.pop();
schedule.date = newDate;
calendar.removeSchedule({date: date, number: i}, false);
calendar.addSchedule(schedule);
calendar.options.changeSchedule(schedule);
}
},
getSelectedDates: function() {
return this.builder.getSelectedDates();
},
getSelectedTerm: function() {
return this.builder.getSelectedTerm();
},
/********************************** private method **********************************/
abstractSelect: function(event, method) {
this.builder.abstractSelect(event, method);
},
createRange: function(a, b) {
var range = null;
if (a <= b)
range = $R(a, b);
else
range = $R(b, a);
return range;
},
formatTime: function(time) {
var hour = (time.hour < 10) ? '0' + time.hour : time.hour;
var min = (time.min < 10) ? '0' + time.min : time.min;
return hour + ':' + min;
},
clearSelected: function() {
var elements = this.getSelected();
var self = this;
elements.each(function(e) {
if (Element.hasClassName(e, Calendar.className.selected))
self.removeSelectedClass(e);
});
},
onDblClick: function(event) {
this.abstractSelect(event, this.options.dblclickListener);
},
onMouseUp: function(event) {
var e = event || window.event;
var calendar = this;
if (calendar.mouseDown) {
setTimeout(function() {
calendar.mouseDown = false;
calendar.options.afterSelect(event);
}, 10);
}
},
setRegularHolidayClass: function(node) {
this.classNames.refreshClassNames(node, 'regularHoliday');
},
// setHolidayClass: function(node) {
// this.classNames.refreshClassNames(node, 'holiday');
// },
getHolidayClass: function() {
this.classNames.refreshClassNames(node, 'holiday');
},
setWorkdayClass: function(node) {
this.classNames.refreshClassNames(node, 'date');
},
setScheduleClass: function(node) {
this.classNames.refreshClassNames(node, 'schedule');
},
// addHighlightClass: function(node) {
// Element.addClassName(node, Calendar.className.highlightDay);
// },
addSelectedClass: function(node) {
this.css.addClassNames(node, 'selected');
},
removeSelectedClass: function(node) {
this.css.removeClassNames(node, 'selected');
},
getDatasWithMonthAndYear: function(array) {
var calendar = this;
var result = array.findAll(function(h) {
return calendar.isSameYearAndMonth(h.date);
});
return result;
},
isSameYearAndMonth: function(a, b) {
if (a.constructor == Date) {
if (!b) b = this.date;
return ((a.getYear() == b.getYear()) && (a.getMonth() == b.getMonth()));
} else {
return (a.year == b.year && a.month == b.month && a.day == a.day);
}
},
isSameDate: function(a, b) {
if (a.constructor == Date) {
if (!b) b = this.date;
return (this.isSameYearAndMonth(a, b) && (a.getDate() == b.getDate()));
} else {
return (this.isSameYearAndMonth(a, b) && a.day == b.day);
}
},
isSameTime: function(a, b) {
return ((a.hour == b.hour) && (a.min == b.min));
},
betweenDate: function(schedule, date) {
var start = this.toDateNumber(schedule.start);
var finish = this.toDateNumber(schedule.finish);
date = this.toDateNumber(date);
return start <= date && date <= finish;
},
toDateNumber: function(date) {
if (date.constructor == Date) {
return date.getFullYear() * 10000 + date.getMonth() * 100 + date.getDate();
} else {
return date.year * 10000 + date.month * 100 + date.day;
}
},
getTimeDiff: function(a, b) {
var time = {hour: b.hour - a.hour, min: b.min - a.min};
if (time.min >= 60) {
time.hour++;
time.min -= 60;
} else if (time.min < 0) {
time.hour--;
time.min += 60;
}
return time;
},
findIndex: function(array, value) {
var index = null;
array.each(function(v, i) {
if (v == value) {
index = i;
throw $break;
}
});
return index;
},
recurrence: function(object, method) {
var calendar = this;
if (object.constructor == Array) {
object.each(function(o) {calendar.recurrence(o, method)});
} else if (object.keys) {
object.each(function(pair) {calendar.recurrence(pair[1], method)});
} else {
method(object);
}
},
toHolidayHash: function(object) {
var calendar = this;
var hash = {};
this.recurrence(object, function(o) {
if (!o.name) return;
if (o.date.constructor == Object)
o.date = new Date(o.date.year, o.date.month, o.date.day);
hash[o.date.toDateString()] = o;
});
return $H(hash);
},
inspectArgument: function(object, time) {
return this.builder.inspectArgument(object, time);
},
inspectDateArgument: function(date) {
return this.builder.inspectDateArgument(date);
},
sortSchedule: function(a, b) {
if (a.start.hour == b.start.hour) {
if (a.start.min == b.start.min)
return 0;
if (a.start.min < b.start.min)
return -1;
return 1;
}
if (a.start.hour < b.start.hour) return -1;
return 1;
},
hasSelectedDate: function() {
return (this.getSelected().length != 0);
},
getDate: function(element) {
return this.builder.getDate(element);
},
isRegularHoliday: function(day) {
return this.options.regularHoliday.include(day);
},
isHoliday: function(date) {
return this.options.holidays[date.toDateString()];
},
isScheduleDay: function(date) {
return this.options.schedules[date.toDateString()];
},
cacheSchedule: function(schedule) {
this.cached = schedule;
schedule.start_old = Object.clone(schedule.start);
schedule.finish_old = Object.clone(schedule.finish);
}
}
/**
* AbstractCalendar Class
*/
var AbstractCalendar = Class.create();
AbstractCalendar.id = {
container: 'container',
scheduleContainer: 'scheduleContainer',
selector: 'selector'
}
AbstractCalendar.prototype = {
destroy: Prototype.emptyFunction,
beforeBuild: Prototype.emptyFunction,
build: function() {
return "
" +
this.buildHeader() +
this.buildCalendar() +
"
";
},
buildHeader: function() {
var noEvent = this.calendar.options.noEvent;
return "";
},
buildSelector: function() {
var style = "display: none; zindex:" + ZindexManager.getIndex();
return "" + "
";
},
buildCover: function() {
this.cover = Builder.node('div', {id: this.calendar.element.id.appendSuffix('cover')});
this.calendar.css.addClassNames(this.cover, 'cover');
if (!this.calendar.options.noEvent) {
Event.observe(this.cover, 'mousedown', this.calendar.selectDate.bindAsEventListener(this.calendar));
if (this.calendar.options.displayType != 'month' || this.calendar.options.size != 'samll') {
Event.observe(this.cover, 'mousemove', this.multipleSelection.bindAsEventListener(this));
}
}
return this.cover;
},
changeCalendar: function(event) {
var element = Event.element(event);
var date = this.calendar.date;
var oldDate = new Date(date.toDateString());
if (this.hasClassName(element, Calendar.className.preYearMark)) {
date.setDate(1);
date.setFullYear(date.getFullYear() - 1);
} else if (this.hasClassName(element, Calendar.className.preMonthMark)) {
date.setDate(1);
date.setMonth(date.getMonth() - 1);
} else if (this.hasClassName(element, Calendar.className.preWeekMark)) {
date.setDate(date.getDate() - 7);
} else if (this.hasClassName(element, Calendar.className.nextYearMark)) {
date.setDate(1);
date.setFullYear(date.getFullYear() + 1);
} else if (this.hasClassName(element, Calendar.className.nextMonthMark)) {
date.setDate(1);
date.setMonth(date.getMonth() + 1);
} else if (this.hasClassName(element, Calendar.className.nextWeekMark)) {
date.setDate(date.getDate() + 7);
}
this.calendar.options.changeCalendar(date, oldDate);
this.calendar.refresh();
},
hasClassName: function(element, className) {
return Element.hasClassName(element, className) || Element.hasClassName(element, className + 'Hover')
},
clickDeleteImage: function(schedule) {
if (this.calendar.options.beforeRemoveSchedule(schedule)) {
this.calendar.removeSchedule(schedule.id, true);
}
},
showDeleteImage: function(img) {
Element.show(img);
},
hideDeleteImage: function(img) {
Element.hide(img);
},
_constrain: function(n, lower, upper) {
if (n > upper) return upper;
else if (n < lower) return lower;
else return n;
},
getContainerId: function() {
return this.calendar.element.id.appendSuffix(AbstractCalendar.id.container);
},
getScheduleContainerId: function() {
return this.calendar.element.id.appendSuffix(AbstractCalendar.id.scheduleContainer);
},
setColumnWidth: function() {
var adjustSize = this.getAdjustSize();
var container = $(this.getScheduleContainerId()) || this.container;
var indexes = this.calendar.options.displayIndexes;
this.column.width = container.offsetWidth / indexes.length - adjustSize;
if (this.column.width < 0) this.column.width = 0;
},
setCover: function() {
var container = $(this.getScheduleContainerId()) || this.container;
this.cover = this.cover || $(this.calendar.element.id.appendSuffix('cover'));
if (!this.cover) {
container.appendChild(this.buildCover());
}
Element.setStyle(this.cover, {height: Element.getHeight(container) + 'px'});
},
getDragDistance: function() {
var adjustSize = this.getAdjustSize();
// return [this.column.width + adjustSize, this.column.height];
return [this.column.width + adjustSize, this.column.height / 2];
},
getWeek: function() {
var date = this.calendar.date;
var indexes = this.calendar.sortWeekIndex([0, 1, 2, 3, 4, 5, 6]);
var baseWday = date.getDay();
var baseWdayIndex = indexes.indexOf(baseWday);
return this.calendar.options.displayIndexes.map(function(wday) {
var diff = wday - baseWday;
var index = indexes.indexOf(wday);
if ((index < baseWdayIndex) && (diff > 0)) {
diff -= 7;
} else if ((index > baseWdayIndex) && (diff < 0)) {
diff += 7;
}
return DateUtil.afterDays(date, diff);
});
},
isSameStartDate: function(schedule, date) {
return ((date.getFullYear() == schedule.start.year) &&
(date.getMonth() == schedule.start.month) && (date.getDate() == schedule.start.day));
},
isSameFinishDate: function(schedule, date) {
return ((date.getFullYear() == schedule.finish.year) &&
(date.getMonth() == schedule.finish.month) && (date.getDate() == schedule.finish.day));
},
getSelectorId: function() {
return this.calendar.element.id.appendSuffix(AbstractCalendar.id.selector);
},
clickDateText: function(event, date) {
Event.stop(event);
this.calendar.date = date;
this.calendar.options.displayType = 'day';
this.calendar.refresh();
},
getAdjustSize: function() {
// return UserAgent.isIE() ? 3 : 3;
return 3;
},
setContainerInfo: function() {
this.container = $(this.getScheduleContainerId());
this.containerDimensions = Element.getDimensions(this.container);
this.containerOffset = Position.cumulativeOffset(this.container);
},
mouseOverSubSchedule: function(items) {
items.each(function(item) {
Element.addClassName(item, Calendar.className.scheduleItemSelect);
});
},
mouseOutSubSchedule: function(items) {
items.each(function(item) {
Element.removeClassName(item, Calendar.className.scheduleItemSelect);
});
},
toDate: function(hash) {
return DateUtil.toDate(hash);
},
getCalendarTableId: function() {
return this.ids.calTable;
}
}
/**
* CalenderMonth Class
*/
var CalendarMonth = Class.create();
CalendarMonth.id = [
'year',
'month',
'column',
'nextYear',
'nextMonth',
'preYear',
'preMonth',
'calTable',
'scheduleContainer',
'container',
'emptyRow'
]
Object.extend(CalendarMonth.prototype, AbstractCalendar.prototype);
Object.extend(CalendarMonth.prototype, {
initialize: function(calendar) {
this.calendar = calendar;
this.week = this.getWeek();
this.ids = SpinelzUtil.concat(this.calendar.element.id, CalendarMonth.id);
this.columnIds = [];
},
/*** Month ***/
/********************************** build functions **********************************/
buildHeaderLeft: function() {
return "" +
"" +
"" +
" | ";
},
buildHeaderCenter: function() {
var text = [];
if (this.calendar.options.monthHeaderFormat) {
var date = this.calendar.date;
var headerText = new Template(this.calendar.options.monthHeaderFormat).evaluate({
year: date.getFullYear(),
month: date.getMonth() + 1
});
text = [headerText, ' '];
}
return "" +
"" +
(text[0] || DateUtil.months[this.calendar.date.getMonth()]) +
"" +
"" +
(text[1] || this.calendar.date.getFullYear()) +
"" +
" | ";
},
buildHeaderRight: function() {
return "" +
"" +
"" +
" | ";
},
buildCalendar: function() {
return "" +
this.buildTableHeader() +
this.buildScheduleContainer() +
"
";
},
buildTableHeader: function() {
var width = 100 / this.calendar.options.displayIndexes.length + '%';
var lastIndex = this.calendar.options.displayIndexes.last();
var columnId = this.ids.column;
var headers = this.calendar.options.displayIndexes.inject('', function(html, i) {
var id = columnId.appendSuffix(i);
this.columnIds.push(id);
var className = (lastIndex == i) ? this.calendar.classNames.thRight : '';
html += "" +
this.calendar.options.dayOfWeek[i] +
" | ";
return html;
}.bind(this));
return "" +
"" + headers + "
" +
"
";
},
buildScheduleContainer: function() {
var style = (this.calendar.options.size == 'large') ? 'position: relative' : '';
return "" +
this.buildTableData() +
this.buildSelector() +
"
";
},
buildTableData: function() {
var indexes = this.calendar.options.displayIndexes;
var today = new Date();
var year = this.calendar.date.getFullYear();
var month = this.calendar.date.getMonth();
var firstDay = DateUtil.getFirstDate(year, month).getDay();
var lastDate = DateUtil.getLastDate(year, month).getDate();
var trs = [];
var tds = '';
var width = 100 / indexes.length + '%';
var lastIndex = indexes.last();
var node, hday, sday, tmp_date, isOutside, i = null;
this.dateMap = {};
// set start index
var weekIndex = this.calendar.options.weekIndex;
var length = DateUtil.dayOfWeek.length * 5;
var i = null;
var day = 1;
if (weekIndex <= firstDay) {
i = weekIndex;
length += i;
} else {
i = weekIndex - 7;
length -= i;
}
var diff = firstDay - weekIndex;
if (diff < 0) diff + indexes.length;
if ((lastDate + diff) > length) {
length += indexes.length;
}
var wday = weekIndex;
var find = 0;
for (; i < length; i++) {
if (indexes.include(wday)) {
var tdClass = (wday == lastIndex) ? this.calendar.classNames.tdRight : '';
if (i < firstDay) {
var idSuffx = i - firstDay + 1;
tmp_date = new Date(
this.calendar.date.getFullYear(),
this.calendar.date.getMonth(),
idSuffx
);
tds += this.buildEmptyRow(tmp_date, width, tdClass, idSuffx);
} else if (day > lastDate) {
tmp_date = new Date(
this.calendar.date.getFullYear(),
this.calendar.date.getMonth(),
day
);
tds += this.buildEmptyRow(tmp_date, width, tdClass, day);
} else {
if (i == firstDay) length += find;
tmp_date = new Date(
this.calendar.date.getFullYear(),
this.calendar.date.getMonth(),
day
);
hday = this.calendar.options.holidays[tmp_date.toDateString()];
if (this.calendar.options.size == Calendar.size.large) {
tds += this.buildLargeRow(tmp_date, hday, today, width, tdClass);
} else {
sday = this.calendar.options.schedules.detect(function(schedule) {
var startDate = DateUtil.toDate(schedule.start);
return tmp_date.sameDate(startDate)
});
tds += this.buildSmallRow(tmp_date, hday, sday, today, width, tdClass);
}
}
find++;
}
if (i >= firstDay) day++;
if (wday == lastIndex) {
trs.push("" + tds + "
");
tds = '';
}
if (wday >= 6) {
wday = 0;
} else {
wday++;
}
}
this.rowMax = trs.length - 1;
return "";
},
buildEmptyRow: function(date, width, className, idSuffix) {
var id = this.ids.emptyRow.appendSuffix(idSuffix);
this.dateMap[id] = date;
return " | ";
},
buildLargeRow: function(date, holiday, today, width, className) {
var dateNode = null;
var dateNodeClass = (date.days() == today.days()) ? this.calendar.classNames.highlightDay : '';
var clickDateText = this.calendar.options.clickDateText;
if (clickDateText || (clickDateText == null)) {
dateNode = "" + date.getDate() + "";
} else {
dateNode = "" + date.getDate() + "";
}
var rowClass = "";
var name = "";
if (holiday) {
rowClass = this.calendar.classNames.holiday;
name = "" + holiday.name + "";
// if (holiday.onclick) {
// Event.observe(name, "click", holiday.onclick.bindAsEventListener(this));
// }
} else if (this.calendar.isRegularHoliday(date.getDay())) {
rowClass = this.calendar.classNames.regularHoliday;
} else {
rowClass = this.calendar.classNames.date;
}
className = [rowClass, className];
var id = this.getDateId(date);
this.dateMap[id] = date;
return "" +
" " +
dateNode + name +
" " +
" | ";
},
buildSmallRow: function(date, holiday, schedule, today, width, className) {
var id = this.getDateId(date);
this.dateMap[id] = date;
var attributes = $H({
id: id,
width: width
});
className = [];
if (schedule) {
className.push(this.calendar.classNames.schedule);
var first = schedule[0];
if (first) attributes.title = first.description;
} else if (holiday) {
className.push(this.calendar.classNames.holiday);
attributes.title = holiday.name.stripTags();
} else if (this.calendar.isRegularHoliday(date.getDay())) {
className.push(this.calendar.classNames.regularHoliday);
} else {
className.push(this.calendar.classNames.date);
}
if (date.days() == today.days()) {
className.push(Calendar.className.highlightDay);
}
className.push(className);
className = className.join(' ');
attributes = attributes.inject('', function(html, pair) {
return html + " " + pair.key + "='" + pair.value + "'";
});
return "" + date.getDate() + " | ";
},
beforeBuild: function() {
this.column = {};
var rule = CssUtil.getCssRuleBySelectorText('.' + Calendar.className.table + ' td');
this.column.height = parseInt(rule.style['height'], 10);
rule = CssUtil.getCssRuleBySelectorText('.' + Calendar.className.dateContainer);
this.column.dateTextHeight = parseInt(rule.style['height'], 10);
},
/**********************************
***** for make schedule item *****
**********************************/
buildSchedule: function(schedule) {
var id = 'scheduleItem_' + schedule.id;
var canEdit = (schedule.edit == undefined || schedule.edit);
var item = Builder.node('DIV', {id: id});
var start = DateUtil.toDate(schedule.start);
var finish = DateUtil.toDate(schedule.finish);
var noEvent = this.calendar.options.noEvent;
var styles = {};
if (noEvent) styles.cursor = 'default';
if (start.sameDate(finish)) {
this.calendar.css.addClassNames(item, 'scheduleItemNoBorder');
} else {
if (schedule.background_color) styles.backgroundColor = schedule.background_color;
if (schedule.frame_color) styles.border = '2px solid ' + schedule.frame_color;
this.calendar.css.addClassNames(item, 'scheduleItemLarge');
}
Element.setStyle(item, styles);
if (canEdit) {
var deleteImg = Builder.node('DIV',
{
id: 'scheduleDeleteImg_' + schedule.id,
className: this.calendar.css.joinClassNames('deleteImg')
}
);
Element.hide(deleteImg);
item.appendChild(deleteImg);
// set click event on a image.
if (!noEvent) {
Event.observe(deleteImg, 'click', this.clickDeleteImage.bind(this, schedule));
Event.observe(item, 'mouseover', this.showDeleteImage.bind(this, deleteImg));
Event.observe(item, 'mouseout', this.hideDeleteImage.bind(this, deleteImg));
}
}
// set dblclick event on a schedule item.
if (!noEvent && this.calendar.options.dblclickSchedule) {
Event.observe(
item, 'dblclick', this.calendar.options.dblclickSchedule.bind(this, schedule));
}
// drag handler
var handler = null;
if (canEdit) {
handler = Builder.node('DIV', {className: this.calendar.css.joinClassNames('scheduleHandler')});
if (noEvent) Element.hide(handler);
item.appendChild(handler);
}
var icon = null;
if (schedule.icon) {
icon = Builder.node('IMG', {src: schedule.icon, alt: 'icon', style: 'float: left;', width: 16, height: 16});
item.appendChild(icon);
}
// private mark
if (!schedule.publicity) {
icon = Builder.node('DIV', {id: 'private_img_' + schedule.id});
this.calendar.css.addClassNames(icon, 'privateImg');
item.appendChild(icon);
}
var body = Builder.node('DIV');
var text = this.getTimeText(schedule.start, schedule.finish);
text = Builder.node('DIV', {id: id + '_text', style: 'float: left;'}, [text]);
this.calendar.css.addClassNames(text, 'scheduleTimeArea');
item.appendChild(text);
var description = schedule.description.unescapeHTML();
item.appendChild(Builder.node('DIV', {id: id + '_description'}, [description]));
item.title = description;
item.schedule = schedule;
return [item, handler];
},
adjustScheduleStyle: function(item, rowIndex, cellIndex, holder) {
var self = this;
var height = parseInt(Element.getStyle(item, 'height'), 10);
var top = parseInt(Element.getStyle(item, 'top'), 10);
var range = this.getScheduleRange(item);
var tops = [];
var displayMax = 3;
holder.each(function(holded) {
var holdedRange = self.getScheduleRange(holded);
if (range.any(function(r) {return holdedRange.include(r)})) {
tops.push(holded.topIndex);
}
});
var index = $R(0, tops.length, true).detect(function(i) {return !tops.include(i)});
if (isNaN(index)) index = tops.length;
item.topIndex = index;
Element.setStyle(item, {top: top + (height + 2) * index + 'px'});
if (index >= displayMax) {
Element.hide(item);
var node = this.buildSkipSchedule(rowIndex + '_' + cellIndex);
if (node) {
var left = Element.getStyle(item, 'left');
Element.setStyle(node, {top: top + (height + 2) * index + 'px', left: left});
}
return node;
}
},
buildSkipSchedule: function(idSuffix) {
var id = this.calendar.element.id.appendSuffix(idSuffix);
if (!this.skipNode[id]) {
var node = Builder.node('div', {id: id}, [this.calendar.options.skipString]);
this.calendar.css.addClassNames(node, 'skipNode');
this.skipNode[id] = node;
return node;
}
},
getScheduleRange: function(item) {
return $R(0, item.length, true).map(function(i) {return item.cellIndex + i});
},
setScheduleBaseStyle: function(item, rowIndex, cellIndex, length) {
var oneDay = this.column.height;
var top = oneDay * rowIndex + this.column.dateTextHeight;
var adjustSize = this.getAdjustSize() + (UserAgent.isIE() ? 0.5 : 0);
Element.setStyle(item, {
top: top + 'px',
width: this.column.width * length + adjustSize * (length - 1) + 'px',
left: this.column.width * cellIndex + cellIndex * adjustSize + 'px'
});
},
afterBuild: function() {
this.scheduleNodes = [];
this.skipNode = $H({});
if (this.calendar.options.size != Calendar.size.small) {
this.calendarTable = $(this.getCalendarTableId());
this.setContainerInfo();
this.setColumnWidth();
this.setCover();
this.setSelector();
var self = this;
var indexes = this.calendar.options.displayIndexes;
var distance = this.getDragDistance();
var holders = $R(0, $(this.getCalendarTableId()).rows.length).map(function() {return []});
var date = this.calendar.date;
var calStartDate = DateUtil.getFirstDate(date.getFullYear(), date.getMonth());
var calStart = calStartDate.days();
var calFinish = DateUtil.getLastDate(date.getFullYear(), date.getMonth()).days();
self.calendar.options.schedules.each(function(schedule, index) {
var startDate = self.toDate(schedule.start);
var start = startDate.days();
var finishDate = self.toDate(schedule.finish);
var finish = finishDate.days();
var days = self.getDayDiff(schedule);
if ((start >= calStart && start <= calFinish) || (finish >= calStart && finish <= calFinish)) {
if (!calStartDate.sameMonth(startDate)) startDate = calStartDate;
self.setSchedule(schedule, holders, distance, days);
}
});
}
},
setEvent: function() {
if (!this.calendar.options.noEvent) {
Event.observe(this.ids.preYear, "click", this.calendar.changeCalendar.bindAsEventListener(this.calendar));
Event.observe(this.ids.preMonth, "click", this.calendar.changeCalendar.bindAsEventListener(this.calendar));
Event.observe(this.ids.nextMonth, "click", this.calendar.changeCalendar.bindAsEventListener(this.calendar));
Event.observe(this.ids.nextYear, "click", this.calendar.changeCalendar.bindAsEventListener(this.calendar));
new Hover(this.ids.preYear);
new Hover(this.ids.preMonth);
new Hover(this.ids.nextMonth);
new Hover(this.ids.nextYear);
if (this.calendar.options.size == 'small') {
$H(this.dateMap).each(function(pair) {
var node = $(pair.key);
if (node) Event.observe(node, 'mousedown', this.calendar.selectDate.bindAsEventListener(this.calendar));
}.bind(this));
}
}
},
setSchedule: function(schedule, holders, distance, days) {
var items = [];
var rowMax = 6;
var startDate = DateUtil.toDate(schedule.start);
var date = startDate;
var indexes = this.calendar.options.displayIndexes;
var targetDate = this.calendar.date;
var noEvent = this.calendar.options.noEvent;
while (days >= 0) {
var lastWday = this.getLastWday(date);
var length = days + 1;
var firstDay = date.getDay();
var finishDate = date.advance({days: length - 1});
if (finishDate.getTime() > lastWday.getTime()) {
finishDate = lastWday;
length = finishDate.days() - date.days() + 1;
}
var finishDay = finishDate.getDay();
var wdays = null;
if (firstDay <= finishDay) {
wdays = $R(firstDay, finishDay, false);
} else {
wdays = $R(0, finishDay, false).toArray().concat($R(firstDay, rowMax, false).toArray());
}
var itemLength = wdays.findAll(function(day) {
return indexes.include(day);
}).length;
var cellDate = new Date(date.getTime());
while (cellDate.days() <= finishDate.days()) {
if (cellDate.getMonth() == targetDate.getMonth()) {
var cellPosition = this.getCellPosition(cellDate.getDate());
if (cellPosition) {
var rowIndex = cellPosition.rowIndex;
var cellIndex = cellPosition.cellIndex;
// create a schedule node.
var result = this.buildSchedule(schedule);
var item = result.first();
item.length = itemLength;
item.cellIndex = cellIndex;
this.container.appendChild(item);
// set style(position and size) of a schedule item.
this.setScheduleBaseStyle(item, rowIndex, cellIndex, itemLength);
var skipNode = this.adjustScheduleStyle(item, rowIndex, cellIndex, holders[rowIndex]);
if (skipNode) this.container.appendChild(skipNode);
if (!noEvent && ((schedule.edit == undefined) || schedule.edit)) {
this.setDraggable(item, result.last(), distance);
this.setResize(item);
}
holders[rowIndex].push(item);
this.scheduleNodes.push(item);
break;
} else if (indexes.include(cellDate.getDay())) {
itemLength--;
}
} else if (indexes.include(cellDate.getDay())) {
itemLength--;
}
cellDate = cellDate.advance({days: 1});
}
if (items.length == 0) {
days -= length;
} else {
days -= 7;
}
var date = finishDate.advance({days: 1});
if (item) items.push(item);
}
var self = this;
if (!noEvent) {
items.each(function(item) {
Event.observe(item, 'mouseover', self.mouseOverSubSchedule.bind(this, items));
Event.observe(item, 'mouseout', self.mouseOutSubSchedule.bind(this, items));
});
}
},
getLastWday: function(date) {
if (!this.calendar.wdays) {
this.calendar.setIndex();
}
var index = this.calendar.wdays.indexOf(date.getDay()) + 1;
return date.advance({days: this.calendar.wdays.length - index});
},
setSelector: function() {
var selector = $(this.getSelectorId());
Element.setStyle(selector, {
width: this.column.width + 'px',
height: this.column.height - 2 + 'px'
});
Element.setOpacity(selector, 0.6);
},
// set draggalbe event
setDraggable: function(item, handle, distance) {
var self = this;
var offset = Position.cumulativeOffset(this.container);
var selector = $(this.getSelectorId());
var cWidth = this.column.width + (UserAgent.isIE() ? 0.5 : 0);
var cHeight = this.column.height + (UserAgent.isIE() ? 1 : 0);
var rowMax = this.rowMax || $(this.getCalendarTableId()).rows.length;
var cellMax = this.calendar.options.displayIndexes.length - 1;
var adjustSize = this.getAdjustSize();
new Draggable(item,
{
handle: handle,
scroll: window,
starteffect: Prototype.emptyFunction,
endeffect: Prototype.emptyFunction,
onStart: function(draggalbe) {
Element.show(selector);
},
onDrag: function(draggable, event) {
var element = draggable.element;
var top = parseInt(Element.getStyle(element, 'top'), 10);
var rowIndex = Math.floor(top / cHeight);
var left = parseInt(Element.getStyle(element, 'left'), 10);
var cellIndex = Math.floor(left / cWidth);
if ((cellIndex >= 0 && rowIndex >= 0) &&
(cellIndex <= cellMax && rowIndex <= rowMax)) {
Element.setStyle(selector, {
left: cWidth * cellIndex + adjustSize * cellIndex + 'px',
top: cHeight * rowIndex + 'px'
});
}
},
onEnd: function(draggable) {
Element.hide(selector);
self.changeSchedule(draggable);
}
}
);
},
// set resize event
setResize: function(item) {
var self = this;
new CalendarResizeableEx(item, {
left: 0,
top: 0,
bottom: 0,
distance: this.column.width,
restriction: true,
resize: function(element) {
self.updateTirm(element);
}
});
},
/********************************** public method **********************************/
getDate: function(element) {
var date = this.calendar.date;
if (element.constructor == String)
return new Date(date.getFullYear(), date.getMonth(), element);
else
return new Date(date.getFullYear(), date.getMonth(), element.id.getSuffix());
},
abstractSelect: function(event, method) {
var element = null;
if (this.calendar.options.size == 'large') {
element = this.findClickedElement(event);
} else {
element = Event.element(event);
if (element.tagName != 'TD') {
element = Element.getParentByTagName(['TD'], element);
}
}
if (element && element.id) {
var date = this.getDate(element);
method(date, element);
}
},
getSelectedTerm: function() {
var self = this;
var elements = this.calendar.getSelected();
return [elements.first(), elements.last()].map(function(e) {
return self.getDate(e);
});
},
/********************************** private method **********************************/
selectDay: function(event) {
var calendar = this.calendar;
var th = Event.element(event);
if (th.tagName != 'TH')
th = Element.getParentByTagName('TH', th);
this.iterateTable({doCell: function(cell) {
if ((cell.cellIndex == th.cellIndex) && cell.id)
calendar.addSelectedClass(cell);
}});
},
inspectArgument: function(object, time) {
var self = this;
var dates = this.calendar.getSelected();
var result = [];
self.calendar.recurrence(object, function(o) {
if (!o.date) {
dates.each(function(d) {
var param = {};
if (!o.date) {
param = {date: self.getDate(d)};
if (time) {
param.start = {hour: 0, min: 0};
param.finish = {hour: 0, min: 0};
}
}
Object.extend(param, o);
result.push(param);
});
} else if (o.date.constructor == Object) {
o.date = new Date(o.date.year, o.date.month, o.date.day);
result.push(o);
} else {
result.push(o);
}
});
return result;
},
inspectDateArgument: function(date) {
if (date) {
map = [];
this.calendar.recurrence(date, function(d) {
if (d.constructor == Object)
map.push(new Date(d.year, d.month, d.day));
else
map.push(d);
});
return map;
} else {
var calendar = this;
var dates = this.calendar.getSelected();
if (dates.length == 0) return null;
return dates.collect(function(d) {
return calendar.getDate(d);
});
}
},
findClickedElement: function(event) {
var container = $(this.getScheduleContainerId());
var position = Position.cumulativeOffset(container);
var scrollTop = Position.realOffset(container).last();
scrollTop -= document.documentElement.scrollTop || document.body.scrollTop;
var x = Event.pointerX(event) - position[0];
var y = Event.pointerY(event) - position[1] + scrollTop;
var rowIndex = Math.floor(y / this.column.height);
var cellIndex = Math.floor(x / this.column.width);
return $(this.calendarTable.rows[rowIndex].cells[cellIndex]);
},
multipleSelection: function(event) {
if (!this.calendar.selectedBase || !this.calendar.mouseDown) return;
var self = this;
var calendar = this.calendar;
var selected = this.calendar.selectedBase;
this.abstractSelect(event, function(date, element) {
var selectedElement = $(selected.id);
var range = calendar.createRange(
parseInt(selectedElement.id.getSuffix()),
parseInt(element.id.getSuffix())
);
self.iterateTable({doCell: function(cell) {
if (cell.tagName != 'TD' || !cell.id) throw $continue;
var id = parseInt(cell.id.getSuffix());
if (range.include(id)) {
calendar.addSelectedClass(cell);
} else {
calendar.removeSelectedClass(cell);
}
}});
});
},
iterateTable: function() {
var options = Object.extend({
doTable: null,
doRow: null,
doCell: null
}, arguments[0]);
var calendar = $(this.getCalendarTableId());
if (options.doTable) {
options.doTable(calendar)
};
$A(calendar.rows).each(function(row) {
if (options.doRow) {
options.doRow(row);
}
$A(row.cells).each(function(cell) {
if (options.doCell) {
options.doCell(cell);
}
});
});
},
findRow: function(rowIndex) {
var table = $(this.getCalendarTableId());
return $A(table.rows).detect(function(row) {
return row.rowIndex == rowIndex;
});
},
findCell: function(rowIndex, cellIndex) {
return $A(this.findRow(rowIndex).cells).detect(function(cell) {
return cell.cellIndex == cellIndex;
});
},
getDateId: function(date) {
var day = null;
if (date.constructor == Date) {
day = date.getDate();
} else {
day = date;
}
return this.calendar.element.id.appendSuffix(day);
},
getCell: function(day) {
return $(this.getDateId(day));
},
getCellPosition: function(day) {
var cell = this.getCell(day);
if (cell) {
var row = Element.getParentByTagName(['tr'], cell);
return {cellIndex: cell.cellIndex, rowIndex: row.rowIndex};
}
},
changeSchedule: function(draggable) {
var element = draggable.element;
var schedule = element.schedule;
this.calendar.cacheSchedule(schedule);
var top = parseInt(Element.getStyle(element, 'top'), 10);
var rowIndex = Math.floor(top / this.column.height);
var left = parseInt(Element.getStyle(element, 'left'), 10);
var cellIndex = Math.floor(left / this.column.width);
var table = $(this.getCalendarTableId());
var rowMax = table.rows.length - 1;
var cellMax = this.calendar.options.displayIndexes.length - 1;
if ((cellIndex >= 0 && rowIndex >= 0) &&
(cellIndex <= cellMax && rowIndex <= rowMax)) {
var cell = this.findCell(rowIndex, cellIndex);
var date = new Date(this.calendar.date.getTime());
date.setDate(parseInt(cell.id.getSuffix(), 10));
var diff = this.getDayDiff(schedule);
var finish = date.advance({days: diff});
if (
schedule.start.month == date.getMonth() &&
schedule.start.day == date.getDate() &&
schedule.finish.month == finish.getMonth() &&
schedule.finish.day == finish.getDate()
) {this.calendar.refreshSchedule(); return;}
schedule.start.month = date.getMonth();
schedule.start.day = date.getDate();
schedule.finish.month = finish.getMonth();
schedule.finish.day = finish.getDate();
this.calendar.refreshSchedule();
this.calendar.options.changeSchedule(schedule);
} else {
this.calendar.refreshSchedule();
}
},
updateTirm: function(element) {
var schedule = element.schedule;
var width = parseInt(Element.getStyle(element, 'width'));
var top = parseInt(Element.getStyle(element, 'top'));
var left = parseInt(Element.getStyle(element, 'left'));
var cellIndex = Math.round((left + width) / this.column.width) - 1;
var rowIndex = Math.round(top / this.column.height);
var cell = this.findCell(rowIndex, cellIndex);
var oldFinish = schedule.finish;
var newFinish = this.dateMap[cell.id].toHash();
newFinish.hour = oldFinish.hour;
newFinish.min = oldFinish.min;
if (DateUtil.toDate(schedule.start).getTime() >= DateUtil.toDate(newFinish).getTime()) {
var maxHour = 23;
var maxMin = 55;
if (schedule.start.hour == maxHour && schedule.start.min == maxMin) {
this.calendar.refreshSchedule();
this.calendar.options.updateTirm();
return;
} else {
newFinish.hour = maxHour;
newFinish.min = maxMin;
}
}
schedule.finish = newFinish;
this.calendar.refreshSchedule();
this.calendar.options.updateTirm(schedule);
},
getTimeText: function(start, finish) {
var calendar = this.calendar;
return calendar.formatTime(start);
},
getDayDiff: function(schedule) {
return DateUtil.numberOfDays(this.toDate(schedule.start), this.toDate(schedule.finish));
}
});
/**
* CalendarWeek Class
*/
var CalendarWeek= Class.create();
CalendarWeek.id = [
'calTable',
'columnContainer',
'columnHeader',
'column',
'next',
'pre',
'headerText'
];
Object.extend(CalendarWeek.prototype, AbstractCalendar.prototype);
Object.extend(CalendarWeek.prototype, {
initialize: function(calendar) {
this.calendar = calendar;
this.week = this.getWeek();
this.ids = SpinelzUtil.concat(this.calendar.element.id, CalendarWeek.id);
this.setDisplayTime();
},
/*** Week ***/
/********************************** build functions **********************************/
buildHeaderLeft: function() {
return "" +
"" +
" | ";
},
buildHeaderCenter: function() {
var texts = [];
if (this.calendar.options.weekHeaderFormat) {
texts = [this.formatHeaderDate(this.week.first()), '-', this.formatHeaderDate(this.week.last())];
}
return "" +
"" +
(texts[0] || this.week[0].toDateString()) +
"" +
"" +
(texts[1] || '-') +
"" +
"" +
(texts[2] || this.week.last().toDateString()) +
"" +
" | ";
},
formatHeaderDate: function(date) {
if (this.calendar.options.weekHeaderFormat) {
return new Template(this.calendar.options.weekHeaderFormat).evaluate({
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
wday: this.calendar.options.dayOfWeek[date.getDay()]
});
}
return [];
},
buildHeaderRight: function() {
return "" +
"" +
" | ";
},
buildCalendar: function() {
var tableRows = (this.calendar.options.displayTimeLine) ? this.buildTimeLine() : '';
tableRows += this.buildCalendarContainer();
return "" +
"" + tableRows + "
" +
"
";
},
buildTimeLine: function() {
var time = new Date();
var hour = 0, hoursOfDay = 24;
time.setHours(hour);
time.setMinutes(0);
var nodes = this.buildTimeLineTop();
var now = new Date().getHours();
while (hour < hoursOfDay) {
if (this.includeDisplayTime(hour)) {
var style = 'pointer: default;';
if (nodes.length == 0) style += "border-top: none;";
var className = this.calendar.classNames.timeLineTime;
if (hour == now) className += ' ' + this.calendar.classNames.highlightTime;
nodes += "" + this.formatTime(time) + "
";
}
hour++;
time.setHours(hour);
}
return "" + nodes + " | ";
},
buildTimeLineTop: function() {
return "";
},
buildCalendarContainer: function() {
return "" +
"" +
this.buildCalendarHeader() +
this.buildCalendarMain() +
" " +
" | ";
},
buildCalendarHeader: function() {
var indexes = this.calendar.options.displayIndexes;
var ths = '';
var today = new Date().days();
var width = 100 / indexes.length + '%';
var thIdBase = this.calendar.element.id.appendSuffix(this.ids.column);
var linkIdBase = this.calendar.element.id.appendSuffix(this.ids.headerText);
this.headers = [];
var noEvent = this.calendar.options.noEvent;
var subHeaderTempl = (this.calendar.options.weekSubHeaderFormat) ?
new Template(this.calendar.options.weekSubHeaderFormat) : null;
this.week.each(function(w, index) {
var text = null;
if (subHeaderTempl) {
text = subHeaderTempl.evaluate({
month: w.getMonth().succ(),
day: w.getDate(),
wday: this.calendar.options.dayOfWeek[w.getDay()]
});
} else {
text = w.toDateString().split(' ');
text.pop();
text = text.join(' ');
}
var linkClass = (w.days() == today) ? this.calendar.classNames.highlightDay : '';
var linkId = linkIdBase.appendSuffix(index);
var node = "";
if (noEvent) {
node += "
" + text + "";
} else {
node += "" + text + "";
}
node += " ";
this.headers.push({id: linkId, wday: w});
ths += "" + node + " | ";
}.bind(this));
return "" +
"" +
"" +
" | " +
"
";
},
buildCalendarMain: function() {
var indexes = this.calendar.options.displayIndexes;
var tds = '';
var width = 100.0 / indexes.length + '%';
this.dateMap = {};
this.week.each(function(w, index) {
var schedules = this.calendar.options.schedules[w.toDateString()];
var nodes = '';
var i = 0, j = 0;
while (i < 24) {
if (this.includeDisplayTime(i)) {
var className = '';
if (nodes.length == 0) {
className = this.calendar.classNames.columnTopDate;
} else if (i % 1 == 0) {
className = this.calendar.classNames.columnDate;
} else {
className = this.calendar.classNames.columnDateOdd;
}
var id = this.getDateId(w, i, index);
var hour = i / 1;
var min = i % 1 * 60;
this.dateMap[id] = new Date(w.getFullYear(), w.getMonth(), w.getDate(), hour, min, 0);
nodes += "";
}
i += 0.5;
}
tds += "" + nodes + " | ";
}.bind(this));
return "" +
"" +
"" +
" | " +
"
";
},
setColumnEvent: function(node) {
// do nothing
},
beforeBuild: function() {
this.column = {};
var rule = CssUtil.getCssRuleBySelectorText('.' + Calendar.className.columnDate);
this.column.height = parseInt(rule.style['height'], 10) + 1;
},
/**********************************
***** for make schedule item *****
**********************************/
buildSchedule: function(schedule) {
var id = 'scheduleItem_' + schedule.id;
var canEdit = (schedule.edit == undefined || schedule.edit);
var item = Builder.node('DIV', {id: id});
this.calendar.css.addClassNames(item, 'scheduleItemLarge');
var noEvent = this.calendar.options.noEvent;
var styles = {};
if (schedule.background_color) styles.backgroundColor = schedule.background_color;
if (schedule.frame_color) styles.border = '2px solid ' + schedule.frame_color;
if (noEvent) styles.cursor = 'default';
Element.setStyle(item, styles);
if (canEdit) {
var deleteImg = Builder.node('DIV',
{
id: 'scheduleDeleteImg_' + schedule.id,
className: this.calendar.css.joinClassNames('deleteImg')
}
);
Element.hide(deleteImg);
item.appendChild(deleteImg);
// set event on a image.
if (!noEvent) {
Event.observe(deleteImg, 'click', this.clickDeleteImage.bind(this, schedule));
Event.observe(item, 'mouseover', this.showDeleteImage.bind(this, deleteImg));
Event.observe(item, 'mouseout', this.hideDeleteImage.bind(this, deleteImg));
}
}
// set dblclick event on a schedule item.
if (!noEvent && this.calendar.options.dblclickSchedule) {
Event.observe(item, 'dblclick', this.calendar.options.dblclickSchedule.bind(this, schedule));
}
// drag handler
var handler = null;
if (canEdit) {
handler = Builder.node('DIV', {className: this.calendar.css.joinClassNames('scheduleHandler')});
if (noEvent) Element.hide(handler);
item.appendChild(handler);
}
var icon = null;
if (schedule.icon) {
icon = Builder.node('IMG', {src: schedule.icon, alt: 'icon', style: 'float: left;', width: 16, height: 16});
item.appendChild(icon);
}
// private mark
if (!schedule.publicity) {
icon = Builder.node('DIV', {id: 'private_img_' + schedule.id});
this.calendar.css.addClassNames(icon, 'privateImg');
item.appendChild(icon);
}
var text = this.getTimeText(schedule.start, schedule.finish);
text = Builder.node('DIV', {id: id + '_text'}, [text]);
this.calendar.css.addClassNames(text, 'scheduleTimeArea');
item.appendChild(text);
var description = schedule.description.unescapeHTML();
item.appendChild(Builder.node('DIV', {id: id + '_description'}, [description]));
item.title = description;
item.schedule = schedule;
return [item, handler];
},
adjustScheduleStyle: function(item, index, holder) {
var schedule = item.schedule;
var time = this.convertHours(schedule);
var start = time[0];
var finish = time[1];
var same = [];
var self = this;
holder.each(function(h) {
var hTime = self.convertHours(h.schedule);
var hStart = hTime[0];
var hFinish = hTime[1];
if (
((hStart <= start) && (hFinish > start)) || ((hStart < finish) && (hFinish >= finish)) ||
((start <= hStart) && (finish > hStart)) || ((start < hFinish) && (finish >= hFinish))
) {
same.push(h);
}
});
var adjustSize = index * this.getAdjustSize();
var left = this.column.width * index + adjustSize;
if (same.length == 0) {
Element.setStyle(item, {left: left + 'px'});
} else {
same.push(item);
var width = parseInt(Element.getStyle(item, 'width'), 10) / (same.length) - (UserAgent.isIE() ? 1: 2);
same.each(function(s, i) {
var adjustLeft = left + width * i + (2 * i);
// if (i != 0) adjustLeft += 2;
Element.setStyle(s, {
width: width + 'px',
left: adjustLeft + 'px'
});
});
}
return left;
},
setScheduleBaseStyle: function(item) {
var schedule = item.schedule;
if (!this.calendar.isSameDate(schedule.start, schedule.finish)) {
schedule.finish.hour = 24;
schedule.finish.min = 0;
}
var time = this.convertHours(schedule);
var startTime = time.first();
var finishTime = time.last();
var oneHour = this.column.height * 2;
var diff = this.calendar.getTimeDiff(schedule.start, schedule.finish);
var rate = (diff.hour + (diff.min / 60)) || 1;
var over = 0;
var top = 0;
var height = 0;
var includeStart = this.includeDisplayTime(startTime);
var includeFinish = this.includeDisplayTime(finishTime);
if (!includeStart && !includeFinish) {
if ((this.startTime <= startTime && this.startTime <= finishTime) ||
(startTime < this.finishTime && finishTime < this.finishTime)) {
top = height = 0;
Element.hide(item);
} else {
top = 0;
height = oneHour * (this.finishTime - this.startTime) - 3;
}
} else {
if (includeStart) {
top = oneHour * (startTime - this.startTime);
height = oneHour * rate - 3;
} else {
top = 0;
over = this.startTime - startTime;
height = oneHour * (rate - over);
}
if (includeFinish) {
} else {
over = finishTime - this.finishTime;
height -= oneHour * over;
}
}
try {
Element.setStyle(item, {
top: top + 'px',
width: this.column.width + 'px',
height: height + 'px'
});
} catch (e) {}
},
afterBuild: function() {
this.calendarTable = $(this.getCalendarTableId());
this.setContainerInfo();
this.setColumnWidth();
this.setCover();
var self = this;
var container = $(this.getScheduleContainerId());
var distance = this.getDragDistance();
this.scheduleNodes = [];
var holders = this.week.map(function() {return []});
var weekSize = this.week.legth - 1;
var noEvent = this.calendar.options.noEvent;
this.calendar.options.schedules.each(function(schedule) {
var items = [];
var sub, subItem = null;
self.week.each(function(date, index) {
if (self.calendar.betweenDate(schedule, date)) {
if (self.isSameStartDate(schedule, date) && self.isSameFinishDate(schedule, date)) {
items.push(self.setSchedule(schedule, index, holders, container, distance));
} else {
sub = self.copyOneDaySchedule(schedule, date);
subItem = self.setSchedule(sub, index, holders, container, distance);
subItem.originalSchedule = schedule;
items.push(subItem);
}
} else if (sub) {
throw $break;
}
});
if (!noEvent) {
items.each(function(item) {
Event.observe(item, 'mouseover', self.mouseOverSubSchedule.bind(this, items));
Event.observe(item, 'mouseout', self.mouseOutSubSchedule.bind(this, items));
});
}
});
},
setEvent: function() {
if (!this.calendar.options.noEvent) {
Event.observe(this.ids.pre, "click", this.calendar.changeCalendar.bindAsEventListener(this.calendar));
Event.observe(this.ids.next, "click", this.calendar.changeCalendar.bindAsEventListener(this.calendar));
new Hover(this.ids.pre);
new Hover(this.ids.next);
var clickDateText = this.calendar.options.clickDateText || this.clickDateText;
if (this.headers) {
this.headers.each(function(header) {
Event.observe(header.id, 'mousedown', clickDateText.bindAsEventListener(this, header.wday));
}.bind(this));
}
}
},
copyOneDaySchedule: function(schedule, date) {
var sub = null;
if (this.isSameStartDate(schedule, date)) {
sub = this.copySchedule(schedule, date);
sub.finish.hour = 24;
sub.finish.min = 0;
} else if (this.isSameFinishDate(schedule, date)) {
sub = this.copySchedule(schedule, date);
sub.start.hour = 0;
sub.start.min = 0;
} else {
sub = this.copySchedule(schedule, date);
sub.start.hour = 0;
sub.start.min = 0;
sub.finish.hour = 24;
sub.finish.min = 0;
}
return sub;
},
copySchedule: function(schedule, date) {
sub = Object.extend({}, schedule);
sub.start = {
year: date.getFullYear(),
month: date.getMonth(),
day: date.getDate(),
hour: schedule.start.hour,
min: schedule.start.min
}
sub.finish = {
year: date.getFullYear(),
month: date.getMonth(),
day: date.getDate(),
hour: schedule.finish.hour,
min: schedule.finish.min
}
return sub;
},
setSchedule: function(schedule, index, holders, container, distance) {
// create a schedule node.
var result = this.buildSchedule(schedule);
var item = result.first();
container.appendChild(item);
// set style(position and size) of a schedule item.
this.setScheduleBaseStyle(item);
var left = this.adjustScheduleStyle(item, index, holders[index]);
var adjustSize = index * this.getAdjustSize();
var snapLeft = this.column.width + adjustSize + 'px';
if (!this.calendar.options.noEvent && ((schedule.edit == undefined) || schedule.edit)) {
this.setDraggable(item, result.last(), container, distance);
this.setResize(item);
}
holders[index].push(item);
this.scheduleNodes.push(item);
return item;
},
getDragDistance: function() {
var adjustSize = this.getAdjustSize();
return [this.column.width + adjustSize, this.column.height / 2];
},
// set draggalbe event
setDraggable: function(item, handle, container, distance) {
var self = this;
new Draggable(item,
{
handle: handle,
scroll: window,
starteffect: Prototype.emptyFunction,
endeffect: Prototype.emptyFunction,
snap: function(x, y) {
var eDimensions = Element.getDimensions(item);
var pDimensions = Element.getDimensions(container);
var xy = [x, y].map(function(v, i) { return Math.floor(v/distance[i]) * distance[i]; });
xy = [
self._constrain(xy[0], 0, pDimensions.width - eDimensions.width),
self._constrain(xy[1], 0, pDimensions.height - eDimensions.height)
];
return xy;
},
onEnd: function(draggable, event) {
self.changeSchedule(draggable, event);
},
change: function(draggable) {
self.changeTimeDisplay(draggable.element);
}
}
);
},
// set resize event
setResize: function(item) {
new CalendarResizeableEx(item, {
left: 0,
right: 0,
distance: this.column.height / 2,
restriction: true,
resize: function(element) {
this.updateTirm(element);
}.bind(this),
change: function(element) {
this.changeTimeDisplay(element);
}.bind(this)
});
},
/********************************** public method **********************************/
getDate: function(element) {
return element.date;
},
abstractSelect: function(event, method) {
var element = this.findClickedElement(event);
if (element) {
if (Element.hasClassName(element, Calendar.className.columnDate) ||
Element.hasClassName(element, Calendar.className.columnDateOdd) ||
Element.hasClassName(element, Calendar.className.columnTopDate)) {
var date = this.getDate(element);
method(date, element);
}
}
},
getSelectedTerm: function() {
var elements = this.calendar.getSelected();
if (elements.length == 0) return;
if (this.calendar.options.build) {
var last = elements.last();
if (last) {
last = this.dateMap[last.id];
} else {
last = this.dateMap[elements.first().id];
}
last = new Date(last.getFullYear(), last.getMonth(),
last.getDate(), last.getHours(), last.getMinutes(), 0);
last.setMinutes(last.getMinutes() + 30);
return [this.dateMap[elements.first().id], last];
} else {
var last = this._getDateTimeFromElement(elements.last());
last.setMinutes(last.getMinutes() + 30);
return [this._getDateTimeFromElement(elements.first()), last];
}
},
/*** Week ***/
/********************************** private method **********************************/
setWidth: function(node) {
Element.setStyle(node, {width: this.column.width + 'px'});
},
inspectArgument: function(object, time) {
if (object.date) return object;
var self = this;
var dates = this.calendar.getSelected();
var result = [];
this.calendar.recurrence(object, function(o) {
var param = {};
if (!o.date) {
param = {date: self.getDate(dates[0])};
if (!o.start)
param.start = dates[0].time;
if (!o.finish)
param.finish = dates[dates.length - 1].time;
}
Object.extend(param, o);
result.push(param);
});
return result;
},
inspectDateArgument: function(date) {
if (date) return date;
var calendar = this;
var dates = this.getSelected();
if (dates.length == 0) return null;
return dates.collect(function(d) {
return calendar.getDate(d);
});
},
addColumnClass: function(element) {
if (document.all)
this.calendar.css.addClassNames(element, 'columnWin');
else
this.calendar.css.addClassNames(element, 'column');
},
getHeaderId: function() {
return this.calendar.element.id.appendSuffix(CalendarWeek.id.columnHeader);
},
getColumnId: function(i) {
return this.calendar.element.id.appendSuffix(CalendarWeek.id.column + '_' + i);
},
changeSchedule: function(draggable, event) {
var element = draggable.element;
var schedule = element.schedule;
var time = this.getTimeByElement(element);
this.calendar.cacheSchedule(schedule);
var container = $(this.getScheduleContainerId());
var dimensions = Element.getDimensions(container);
var offset = Position.cumulativeOffset(container);
var x = Event.pointerX(event);
var y = Event.pointerY(event);
if (
offset[0] > x ||
(offset[0] + dimensions.width) < x ||
offset[1] > y ||
(offset[1] + dimensions.height) < y
) {this.calendar.refreshSchedule(); return};
var left = parseInt(Element.getStyle(element, 'left'));
var weekIndex = Math.round(left / this.column.width);
var date = this.week[weekIndex];
if (
schedule.start.year == date.getFullYear() &&
schedule.start.month == date.getMonth() &&
schedule.start.day == date.getDate() &&
schedule.start.hour == time[0].hour &&
schedule.start.min == time[0].min &&
schedule.finish.year == date.getFullYear() &&
schedule.finish.month == date.getMonth() &&
schedule.finish.day == date.getDate() &&
schedule.finish.hour == time[1].hour &&
schedule.finish.min == time[1].min
) {this.calendar.refreshSchedule(); return};
if (element.originalSchedule) schedule = element.originalSchedule;
var newStart = {
year: date.getFullYear(),
month: date.getMonth(),
day: date.getDate(),
hour: time[0].hour,
min: time[0].min
}
var diff = DateUtil.toDate(newStart).getTime() - DateUtil.toDate(schedule.start).getTime();
schedule.start = newStart;
schedule.finish = new Date(DateUtil.toDate(schedule.finish).getTime() + diff).toHash();
this.calendar.refreshSchedule();
this.calendar.options.changeSchedule(schedule);
},
updateTirm: function(element) {
var schedule = element.schedule;
var time = this.getTimeByElement(element);
this.calendar.cacheSchedule(schedule);
var left = parseInt(Element.getStyle(element, 'left'));
var weekIndex = Math.round(left / this.column.width);
var date = this.week[weekIndex];
var isChange = this.isChengeSchedule(element, time);
if (element.originalSchedule) schedule = element.originalSchedule;
if (isChange.start) {
schedule.start.year = date.getFullYear();
schedule.start.month = date.getMonth();
schedule.start.day = date.getDate();
schedule.start.hour = time[0].hour;
schedule.start.min = time[0].min;
} else if (isChange.finish) {
schedule.finish.year = date.getFullYear();
schedule.finish.month = date.getMonth();
schedule.finish.day = date.getDate();
schedule.finish.hour = time[1].hour;
schedule.finish.min = time[1].min;
} else {
return;
}
this.calendar.refreshSchedule();
this.calendar.options.updateTirm(schedule);
},
changeTimeDisplay: function(element) {
var schedule = element.schedule;
var time = this.getTimeByElement(element);
var textNode = Element.getElementsByClassName(element, Calendar.className.scheduleTimeArea)[0];
var text = this.getTimeText(time[0], time[1]);
textNode.innerHTML = text;
},
findClickedElement: function(event) {
var container = $(this.getScheduleContainerId());
var position = Position.cumulativeOffset(container);
var scrollTop = Position.realOffset(container).last();
scrollTop -= document.documentElement.scrollTop || document.body.scrollTop;
var x = Event.pointerX(event) - position[0];
var y = Event.pointerY(event) - position[1] + scrollTop;
var cellIndex = Math.floor(y / this.column.height);
var rowIndex = Math.floor(x / this.column.width);
return $(this.calendarTable.rows[0].cells[rowIndex]).down(cellIndex);
},
multipleSelection: function(event) {
if (!this.calendar.selectedBase || !this.calendar.mouseDown) return;
var self = this;
var calendar = this.calendar;
var selected = this.calendar.selectedBase;
var selectedDate = this._getDateFromElement(selected).getDate();
this.abstractSelect(event, function(date, element) {
var selectedElement = $(selected.id);
if (selectedDate != self._getDateFromElement(element).getDate()) return;
var nodes = $A(selectedElement.parentNode.childNodes);
var ids = [this._getTime(selected), this._getTime(element)];
ids.sort(function(a, b) {return a - b;});
nodes.each(function(n) {
if (!n.id) throw $continue;
var id = this._getTime(n);
if ((id < ids[0]) || (ids[1] < id)) {
calendar.removeSelectedClass(n);
} else if (!Element.hasClassName(n, Calendar.className.selected)) {
calendar.addSelectedClass(n);
}
}.bind(this));
}.bind(this));
},
getTimeByElement: function(element) {
var schedule = element.schedule;
var top = parseInt(Element.getStyle(element, 'top'), 10);
var height = parseInt(Element.getStyle(element, 'height'), 10);
var oneHour = this.column.height * 2;
var distance = 15 / 60; // 5 minutes
var startTime = top / oneHour + this.startTime;
startTime = Math.round(startTime / distance) * distance;
var start = {};
start.hour = Math.floor(startTime);
start.min = (startTime - start.hour) * 60;
var finishTime = Math.round(height / oneHour / distance) * distance + startTime;
var finish = {};
finish.hour = Math.floor(finishTime);
finish.min = Math.round((finishTime - finish.hour) * 60);
if (finish.min == 60) {
finish.hour += 1;
finish.min = 0;
}
return [start, finish];
},
getDateId: function(date, time, index) {
var id = this.calendar.element.id.appendSuffix(index + '_' + date.getDate());
return id.appendSuffix(time * 10);
},
dateIdToTime: function(id) {
id = id.getSuffix() / 10;
var hour = Math.floor(id);
return {hour: hour, min: (id - hour) * 60};
},
formatTime: function(date) {
var time = date.toTimeString();
time = time.split(' ');
time = time[0].split(':');
time.pop();
return time.join(':');
},
/**
* hours are 0, 0.5, 1, ..., 23.5, 24
*/
includeDisplayTime: function(hours) {
return (this.startTime <= hours) && (hours < this.finishTime);
},
/**
* exsample
*
* {hour: 1, min: 30} => 1.5
*/
convertHours: function(schedule) {
return [
schedule.start.hour + schedule.start.min / 60,
schedule.finish.hour + schedule.finish.min / 60
];
},
setDisplayTime: function() {
this.startTime = this.calendar.options.displayTime.first().hour;
var finishTime = this.calendar.options.displayTime.last();
this.finishTime = Math.ceil(finishTime.hour + finishTime.min / 60);
},
getTimeText: function(start, finish) {
var calendar = this.calendar;
return calendar.formatTime(start) + ' - ' + calendar.formatTime(finish);
},
isChengeSchedule: function(scheduleElement, newTime) {
var schedule = scheduleElement.schedule;
var changeStart = ((schedule.start.hour != newTime[0].hour) || (schedule.start.min != newTime[0].min));
var changeFinish = ((schedule.finish.hour != newTime[1].hour) || (schedule.finish.min != newTime[1].min));
if (scheduleElement.originalSchedule) {
if (changeStart && changeFinish) {
var currentDateStart = DateUtil.toDate(schedule.start).getTime();
var OriginalDateStart = DateUtil.toDate(scheduleElement.originalSchedule.start).getTime();
if (currentDateStart == OriginalDateStart) {
changeFinish = false;
} else {
changeStart = false;
}
}
}
return {start: changeStart, finish: changeFinish};
},
_getDateFromElement: function(element) {
var arr = element.id.split('_');
var index = arr[arr.length - 3];
return this.week[index];
},
_getDateTimeFromElement: function(element) {
var id = element.id.split('_');
var index = id[id.length - 3];
if (this.week[index]) {
var date = new Date(this.week[index].getTime());
date.setMinutes(parseInt(id.pop(), 10));
date.setHours(parseInt(id.pop(), 10));
return date;
} else {
return this._getDate(element);
}
},
_getDate: function(element) {
var id = element.id.split('_');
var date = new Date(this.calendar.date.getTime());
date.setMinutes(parseInt(id.pop(), 10));
date.setHours(parseInt(id.pop(), 10));
return date;
},
_getTimeString: function(element) {
var arr = element.id.split('_');
var min = arr[arr.length - 1];
if (min == '0') min = '00';
return arr[arr.length - 2] + min;
},
_getTime: function(element) {
return parseInt(this._getTimeString(element), 10);
}
});
/**
* CalendarDay Class
*/
var CalendarDay = Class.create();
CalendarDay.id = ['dayHeader'];
Object.extend(CalendarDay.prototype, CalendarWeek.prototype);
Object.extend(CalendarDay.prototype, {
initialize: function(calendar) {
var day = calendar.date.getDay();
this.calendar = calendar;
this.ids = SpinelzUtil.concat(this.calendar.element.id, CalendarWeek.id);
this.dayIds = SpinelzUtil.concat(this.calendar.element.id, CalendarDay.id);
this.setDisplayTime();
this.calendar.options.displayIndexesOld = this.calendar.options.displayIndexes;
this.calendar.options.displayIndexes = [day];
this.calendar.options.weekIndexOld = this.calendar.options.weekIndex;
this.calendar.options.weekIndex = day;
this.week = this.getWeek();
},
destroy: function() {
this.calendar.options.displayIndexes = this.calendar.options.displayIndexesOld;
this.calendar.options.weekIndex = this.calendar.options.weekIndexOld;
delete this.calendar.options.displayIndexesOld;
delete this.calendar.options.weekIndexOld;
},
/*** Day ***/
/********************************** build functions **********************************/
buildHeaderCenter: function() {
var headerText = this.calendar.date.toDateString();
if (this.calendar.options.dayHeaderFormat) {
var date = this.calendar.date;
headerText = new Template(this.calendar.options.dayHeaderFormat).evaluate({
year: date.getFullYear(),
month: date.getMonth() + 1,
day: date.getDate(),
wday: this.calendar.options.dayOfWeek[date.getDay()]
});
}
return "" +
"" +
" | ";
},
buildTimeLineTop: function() { return '' },
buildCalendarHeader: function() { return '' },
/*** Day ***/
/********************************** private method **********************************/
changeCalendar: function(event) {
var element = Event.element(event);
var oldDate = new Date(this.calendar.date.toDateString());
if (this.hasClassName(element, Calendar.className.preWeekMark)) {
this.calendar.date.setDate(this.calendar.date.getDate() - 1);
} else if (this.hasClassName(element, Calendar.className.nextWeekMark)) {
this.calendar.date.setDate(this.calendar.date.getDate() + 1);
}
this.calendar.options.changeCalendar(this.calendar.date, oldDate);
this.calendar.refresh();
}
});
//
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
var CalendarResizeableEx = Class.create();
Object.extend(CalendarResizeableEx.prototype, Resizeable.prototype);
Object.extend(CalendarResizeableEx.prototype, {
initialize: function(element) {
var options = Object.extend({
top: 6,
bottom: 6,
left: 6,
right: 6,
minHeight: 0,
minWidth: 0,
zindex: 1000,
resize: null,
distance: 1, // add by spinelz
change: Prototype.emptyFunction,
restriction: true
}, arguments[1] || {});
this.element = $(element);
this.handle = this.element;
Element.makePositioned(this.element); // fix IE
this.options = options;
this.active = false;
this.resizing = false;
this.currentDirection = '';
this.eventMouseDown = this.startResize.bindAsEventListener(this);
this.eventMouseUp = this.endResize.bindAsEventListener(this);
this.eventMouseMove = this.update.bindAsEventListener(this);
this.eventCursorCheck = this.cursor.bindAsEventListener(this);
this.eventKeypress = this.keyPress.bindAsEventListener(this);
this.registerEvents();
},
startResize: function(event) {
Event.stop(event);
if(Event.isLeftClick(event)) {
// abort on form elements, fixes a Firefox issue
var src = Event.element(event);
if(src.tagName && (
src.tagName=='INPUT' ||
src.tagName=='SELECT' ||
src.tagName=='BUTTON' ||
src.tagName=='TEXTAREA')) return;
var dir = this.directions(event);
if (dir.length > 0) {
this.active = true;
// var offsets = Position.cumulativeOffset(this.element);
this.startTop = parseInt(Element.getStyle(this.element, 'top'), 10);
this.startLeft = parseInt(Element.getStyle(this.element, 'left'), 10);
this.startWidth = parseInt(Element.getStyle(this.element, 'width'), 10);
this.startHeight = parseInt(Element.getStyle(this.element, 'height'), 10);
this.startX = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
this.startY = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
this.currentDirection = dir;
if (this.options.restriction) {
var container = this.element.parentNode;
this.restDimensions = Element.getDimensions(container);
this.restOffset = Position.cumulativeOffset(container);
}
}
}
},
draw: function(event) {
Event.stop(event);
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var style = this.element.style;
if (this.currentDirection.indexOf('n') != -1) {
if (this.restOffset[1] >= pointer[1]) return;
var pointerMoved = this.startY - pointer[1];
// var margin = Element.getStyle(this.element, 'margin-top') || "0";
var newHeight = this.map(this.startHeight + pointerMoved);
if (newHeight > this.options.minHeight) {
style.height = newHeight + "px";
style.top = this.map(this.startTop - pointerMoved) + "px";
}
}
if (this.currentDirection.indexOf('w') != -1) {
var pointerMoved = this.map(this.startX - pointer[0]);
var margin = Element.getStyle(this.element, 'margin-left') || "0";
var newWidth = this.startWidth + pointerMoved;
if (newWidth > this.options.minWidth) {
style.left = (this.startLeft - pointerMoved - parseInt(margin)) + "px";
style.width = newWidth + "px";
}
}
if (this.currentDirection.indexOf('s') != -1) {
var bottom = this.restDimensions.height + this.restOffset[1];
var pointerMoved = pointer[1] - this.startY;
if (bottom <= pointer[1]) return;
var newHeight = this.map(this.startHeight + pointer[1] - this.startY);
if (newHeight > this.options.minHeight) {
style.height = newHeight + "px";
// style.top = this.startTop + "px";
}
}
if (this.currentDirection.indexOf('e') != -1) {
var newWidth = this.map(this.startWidth + pointer[0] - this.startX);
if (newWidth > this.options.minWidth) {
style.width = newWidth + "px";
}
}
if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
this.options.change(this.element);
},
directions: function(event) {
var pointer = [Event.pointerX(event), Event.pointerY(event)];
var offsets = Position.cumulativeOffset(this.element);
var bodyScrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scroll = Position.realOffset(this.element)[1] - bodyScrollTop;
var cursor = '';
if (this.between(pointer[1] - offsets[1] + scroll, 0, this.options.top)) cursor += 'n';
if (this.between((offsets[1] + this.element.offsetHeight) - pointer[1] - scroll, 0, this.options.bottom)) cursor += 's';
if (this.between(pointer[0] - offsets[0], 0, this.options.left)) cursor += 'w';
if (this.between((offsets[0] + this.element.offsetWidth) - pointer[0], 0, this.options.right)) cursor += 'e';
return cursor;
},
map: function(length) {
return Math.round(length / this.options.distance) * this.options.distance;
}
});