mirror of
https://github.com/OpenXE-org/OpenXE.git
synced 2024-12-25 06:00:28 +01:00
337 lines
11 KiB
JavaScript
337 lines
11 KiB
JavaScript
/**
|
|
* Horde javascript calendar widget.
|
|
*
|
|
* Custom Events:
|
|
* --------------
|
|
* Horde_Calendar:select
|
|
* params: Date object
|
|
* Fired when a date is selected.
|
|
*
|
|
* Horde_Calendar:selectMonth
|
|
* params: Date object
|
|
* Fired when a month is selected.
|
|
*
|
|
* Horde_Calendar:selectWeek
|
|
* params: Date object
|
|
* Fired when a week is selected.
|
|
*
|
|
* Horde_Calendar:selectYear
|
|
* params: Date object
|
|
* Fired when a year is selected.
|
|
*
|
|
* @category Horde
|
|
* @package Core
|
|
*/
|
|
|
|
var Horde_Calendar =
|
|
{
|
|
// Variables set externally: click_month, click_week, click_year,
|
|
// firstDayOfWeek, fullweekdays, months,
|
|
// weekdays
|
|
// Variables defaulting to null: date, month, openDate, trigger, year
|
|
|
|
open: function(trigger, data)
|
|
{
|
|
var date = data ? data : new Date();
|
|
|
|
this.openDate = date.getTime();
|
|
this.trigger = $(trigger);
|
|
this.draw(this.openDate, true);
|
|
},
|
|
|
|
/**
|
|
* Days in the month (month is a zero-indexed javascript month).
|
|
*/
|
|
daysInMonth: function(month, year)
|
|
{
|
|
switch (month) {
|
|
case 3:
|
|
case 5:
|
|
case 8:
|
|
case 10:
|
|
return 30;
|
|
|
|
case 1:
|
|
return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
|
|
? 29
|
|
: 28;
|
|
|
|
default:
|
|
return 31;
|
|
}
|
|
},
|
|
|
|
weeksInMonth: function(month, year)
|
|
{
|
|
var firstWeekDays, weeks,
|
|
firstOfMonth = (new Date(year, month, 1)).getDay();
|
|
|
|
if ((this.firstDayOfWeek == 1 && firstOfMonth == 0) ||
|
|
(this.firstDayOfWeek == 0 && firstOfMonth == 6)) {
|
|
firstWeekDays = 7 - firstOfMonth + this.firstDayOfWeek;
|
|
weeks = 1;
|
|
} else {
|
|
firstWeekDays = this.firstDayOfWeek - firstOfMonth;
|
|
weeks = 0;
|
|
}
|
|
|
|
firstWeekDays %= 7;
|
|
|
|
return Math.ceil((this.daysInMonth(month, year) - firstWeekDays) / 7) + weeks;
|
|
},
|
|
|
|
// http://javascript.about.com/library/blstdweek.htm
|
|
weekOfYear: function(d)
|
|
{
|
|
var newYear = new Date(d.getFullYear(), 0, 1),
|
|
day = newYear.getDay();
|
|
if (this.firstDayOfWeek != 0) {
|
|
day = ((day + (7 - this.firstDayOfWeek)) % 7);
|
|
}
|
|
return Math.ceil((((d - newYear) / 86400000) + day + 1) / 7);
|
|
},
|
|
|
|
draw: function(timestamp, init)
|
|
{
|
|
this.date = new Date(timestamp);
|
|
this.month = this.date.getMonth();
|
|
this.year = this.date.getFullYear();
|
|
|
|
var cell, i, i_max, p, row, startOfView, vp,
|
|
count = 1,
|
|
div = $('hordeCalendar'),
|
|
tbody = div.down('TBODY'),
|
|
|
|
// Requires init above
|
|
daysInMonth = this.daysInMonth(this.month, this.year),
|
|
daysInView = this.weeksInMonth(this.month, this.year) * 7,
|
|
firstOfMonth = (new Date(this.year, this.month, 1)).getDay(),
|
|
|
|
// Cache today and open date.
|
|
today = new Date(),
|
|
today_year = today.getFullYear(),
|
|
today_month = today.getMonth(),
|
|
today_day = today.getDate(),
|
|
open = new Date(this.openDate),
|
|
open_year = open.getFullYear(),
|
|
open_month = open.getMonth(),
|
|
open_day = open.getDate();
|
|
|
|
if (this.firstDayOfWeek == 0) {
|
|
startOfView = 1 - firstOfMonth;
|
|
} else {
|
|
// @TODO Adjust this for days other than Monday.
|
|
startOfView = (firstOfMonth == 0)
|
|
? -5
|
|
: 2 - firstOfMonth;
|
|
}
|
|
|
|
div.down('.hordeCalendarYear').update(this.year);
|
|
div.down('.hordeCalendarMonth').update(this.months[this.month]);
|
|
tbody.update('');
|
|
|
|
for (i = startOfView, i_max = startOfView + daysInView; i < i_max; ++i) {
|
|
if (count == 1) {
|
|
row = new Element('TR');
|
|
if (this.click_week) {
|
|
row.insert(new Element('TD').insert(new Element('A', { className: 'hordeCalendarWeek' }).insert(this.weekOfYear(new Date(this.year, this.month, (i < 1) ? 1 : i)))));
|
|
}
|
|
}
|
|
|
|
cell = new Element('TD');
|
|
|
|
if (i < 1 || i > daysInMonth) {
|
|
cell.addClassName('hordeCalendarEmpty');
|
|
row.insert(cell);
|
|
} else {
|
|
if (today_year == this.year &&
|
|
today_month == this.month &&
|
|
today_day == i) {
|
|
cell.writeAttribute({ className: 'hordeCalendarToday' });
|
|
}
|
|
|
|
if (open_year == this.year &&
|
|
open_month == this.month &&
|
|
open_day == i) {
|
|
cell.addClassName('hordeCalendarCurrent');
|
|
}
|
|
|
|
row.insert(cell.insert(new Element('A', { className: 'hordeCalendarDay', href: '#' }).insert(i)));
|
|
}
|
|
|
|
if (count == 7) {
|
|
tbody.insert(row);
|
|
count = 0;
|
|
}
|
|
++count;
|
|
}
|
|
|
|
if (count > 1) {
|
|
tbody.insert(row);
|
|
}
|
|
|
|
div.show();
|
|
|
|
// Position the popup every time in case of a different input,
|
|
// window sizing changes, etc.
|
|
if (init) {
|
|
p = this.trigger.cumulativeOffset();
|
|
vp = document.viewport.getDimensions();
|
|
|
|
if (p.left + div.offsetWidth > vp.width) {
|
|
div.setStyle({ left: (vp.width - 10 - div.offsetWidth) + 'px' });
|
|
} else {
|
|
div.setStyle({ left: p.left + 'px' });
|
|
}
|
|
|
|
if (p.top + div.offsetHeight > vp.height) {
|
|
div.setStyle({ top: (vp.height - 10 - div.offsetHeight) + 'px' });
|
|
} else {
|
|
div.setStyle({ top: p.top + 'px' });
|
|
}
|
|
}
|
|
|
|
// IE 6 only.
|
|
if (Prototype.Browser.IE && !window.XMLHttpRequest) {
|
|
iframe = $('hordeCalendarIframe');
|
|
if (!iframe) {
|
|
iframe = new Element('IFRAME', { name: 'hordeCalendarIframe', id: 'hordeCalendarIframe', src: 'javascript:false;', scrolling: 'no', frameborder: 0 }).hide();
|
|
$(document.body).insert(iframe);
|
|
}
|
|
iframe.clonePosition(div).setStyle({
|
|
position: 'absolute',
|
|
display: 'block',
|
|
zIndex: 1
|
|
});
|
|
}
|
|
|
|
div.setStyle({ zIndex: 999 });
|
|
},
|
|
|
|
hideCal: function()
|
|
{
|
|
var iefix = $('hordeCalendarIframe');
|
|
|
|
$('hordeCalendar').hide();
|
|
|
|
if (iefix) {
|
|
iefix.hide();
|
|
}
|
|
},
|
|
|
|
changeYear: function(by)
|
|
{
|
|
this.draw((new Date(this.date.getFullYear() + by, this.date.getMonth(), 1)).getTime());
|
|
},
|
|
|
|
changeMonth: function(by)
|
|
{
|
|
var newMonth = this.date.getMonth() + by,
|
|
newYear = this.date.getFullYear();
|
|
|
|
if (newMonth == -1) {
|
|
newMonth = 11;
|
|
newYear -= 1;
|
|
}
|
|
|
|
this.draw((new Date(newYear, newMonth, 1)).getTime());
|
|
},
|
|
|
|
init: function()
|
|
{
|
|
var i, link, row,
|
|
offset = this.click_week ? 1 : 0,
|
|
thead = new Element('THEAD'),
|
|
table = new Element('TABLE', { className: 'hordeCalendarPopup', cellSpacing: 0 }).insert(thead).insert(new Element('TBODY'));
|
|
|
|
// Title bar.
|
|
link = new Element('A', { href: '#', className: 'hordeCalendarClose rightAlign' }).insert('x');
|
|
thead.insert(new Element('TR').insert(new Element('TD', { colspan: 6 + offset })).insert(new Element('TD').insert(link)));
|
|
|
|
// Year.
|
|
row = new Element('TR');
|
|
link = new Element('A', { className: 'hordeCalendarPrevYear', href: '#' }).insert('«');
|
|
row.insert(new Element('TD').insert(link));
|
|
|
|
tmp = new Element('TD', { align: 'center', colspan: 5 + offset });
|
|
if (this.click_year) {
|
|
tmp.insert(new Element('A', { className: 'hordeCalendarYear' }));
|
|
} else {
|
|
tmp.addClassName('hordeCalendarYear');
|
|
}
|
|
row.insert(tmp);
|
|
|
|
link = new Element('A', { className: 'hordeCalendarNextYear', href: '#' }).insert('»');
|
|
row.insert(new Element('TD', { className: 'rightAlign' }).insert(link));
|
|
|
|
thead.insert(row);
|
|
|
|
// Month name.
|
|
row = new Element('TR');
|
|
link = new Element('A', { className: 'hordeCalendarPrevMonth', href: '#' }).insert('«');
|
|
row.insert(new Element('TD').insert(link));
|
|
|
|
tmp = new Element('TD', { align: 'center', colspan: 5 + offset });
|
|
if (this.click_year) {
|
|
tmp.insert(new Element('A', { className: 'hordeCalendarMonth' }));
|
|
} else {
|
|
tmp.addClassName('hordeCalendarMonth');
|
|
}
|
|
row.insert(tmp);
|
|
|
|
link = new Element('A', { className: 'hordeCalendarNextMonth', href: '#' }).insert('»');
|
|
row.insert(new Element('TD', { className: 'rightAlign' }).insert(link));
|
|
|
|
thead.insert(row);
|
|
|
|
// Weekdays.
|
|
row = new Element('TR');
|
|
if (this.click_week) {
|
|
row.insert(new Element('TH'));
|
|
}
|
|
for (i = 0; i < 7; ++i) {
|
|
row.insert(new Element('TH').insert(this.weekdays[(i + this.firstDayOfWeek) % 7]));
|
|
}
|
|
thead.insert(row);
|
|
|
|
$(document.body).insert({ bottom: new Element('DIV', { id: 'hordeCalendar' }).setStyle({ position: 'absolute', 'z-index': 999 }).hide().insert(table) });
|
|
|
|
$('hordeCalendar').observe('click', this.clickHandler.bindAsEventListener(this));
|
|
},
|
|
|
|
clickHandler: function(e)
|
|
{
|
|
var elt = e.element(), day;
|
|
|
|
if (elt.hasClassName('hordeCalendarDay')) {
|
|
this.hideCal();
|
|
this.trigger.fire('Horde_Calendar:select', new Date(this.year, this.month, parseInt(elt.textContent || elt.innerText, 10)));
|
|
} else if (elt.hasClassName('hordeCalendarClose')) {
|
|
this.hideCal();
|
|
} else if (elt.hasClassName('hordeCalendarPrevYear')) {
|
|
this.changeYear(-1);
|
|
} else if (elt.hasClassName('hordeCalendarNextYear')) {
|
|
this.changeYear(1);
|
|
} else if (elt.hasClassName('hordeCalendarPrevMonth')) {
|
|
this.changeMonth(-1);
|
|
} else if (elt.hasClassName('hordeCalendarNextMonth')) {
|
|
this.changeMonth(1);
|
|
} else if (this.click_year && elt.hasClassName('hordeCalendarYear')) {
|
|
this.trigger.fire('Horde_Calendar:selectYear', new Date(this.year, this.month, 1));
|
|
this.hideCal();
|
|
} else if (this.click_month && elt.hasClassName('hordeCalendarMonth')) {
|
|
this.trigger.fire('Horde_Calendar:selectMonth', new Date(this.year, this.month, 1));
|
|
this.hideCal();
|
|
} else if (this.click_week && elt.hasClassName('hordeCalendarWeek')) {
|
|
day = elt.up('TR').down('A.hordeCalendarDay');
|
|
this.trigger.fire('Horde_Calendar:selectWeek', new Date(this.year, this.month, day.textContent || day.innerText));
|
|
this.hideCal();
|
|
}
|
|
|
|
e.stop();
|
|
}
|
|
|
|
};
|
|
|
|
document.observe('dom:loaded', Horde_Calendar.init.bind(Horde_Calendar));
|