📄 calendar.rc4.js
字号:
// Calendar: a Javascript class for Mootools that adds accessible and unobtrusive date pickers to your form elements <http://electricprism.com/aeron/calendar>// Calendar RC4, Copyright (c) 2007 Aeron Glemann <http://electricprism.com/aeron>, MIT Style License.var Calendar = new Class({ options: { blocked: [], // blocked dates classes: [], // ['calendar', 'prev', 'next', 'month', 'year', 'today', 'invalid', 'valid', 'inactive', 'active', 'hover', 'hilite'] days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // days of the week starting at sunday direction: 0, // -1 past, 0 past + future, 1 future draggable: true, months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], navigation: 1, // 0 = no nav; 1 = single nav for month; 2 = dual nav for month and year offset: 0, // first day of the week: 0 = sunday, 1 = monday, etc.. onHideStart: Class.empty, onHideComplete: Class.empty, onShowStart: Class.empty, onShowComplete: Class.empty, pad: 1, // padding between multiple calendars tweak: {x: 0, y: 0} // tweak calendar positioning }, // initialize: calendar constructor // @param obj (obj) a js object containing the form elements and format strings { id: 'format', id: 'format' etc } // @param props (obj) optional properties initialize: function(obj, options) { // basic error checking if (!obj) { return false; } this.setOptions(options); // create our classes array var keys = ['calendar', 'prev', 'next', 'month', 'year', 'today', 'invalid', 'valid', 'inactive', 'active', 'hover', 'hilite']; var values = keys.map(function(key, i) { if (this.options.classes[i]) { if (this.options.classes[i].length) { key = this.options.classes[i]; } } return key; }, this); this.classes = values.associate(keys); // create cal element with css styles required for proper cal functioning this.calendar = new Element('div', { 'styles': { left: '-1000px', opacity: 0, position: 'absolute', top: '-1000px', zIndex: 1000 } }).addClass(this.classes.calendar).injectInside(document.body); // iex 6 needs a transparent iframe underneath the calendar in order to not allow select elements to render through if (window.ie6) { this.iframe = new Element('iframe', { 'styles': { left: '-1000px', position: 'absolute', top: '-1000px', zIndex: 999 } }).injectInside(document.body); this.iframe.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)'; } // initialize fade method this.fx = this.calendar.effect('opacity', { onStart: function() { if (this.calendar.getStyle('opacity') == 0) { // show if (window.ie6) { this.iframe.setStyle('display', 'block'); } this.calendar.setStyle('display', 'block'); this.fireEvent('onShowStart', this.element); } else { // hide this.fireEvent('onHideStart', this.element); } }.bind(this), onComplete: function() { if (this.calendar.getStyle('opacity') == 0) { // hidden this.calendar.setStyle('display', 'none'); if (window.ie6) { this.iframe.setStyle('display', 'none'); } this.fireEvent('onHideComplete', this.element); } else { // shown this.fireEvent('onShowComplete', this.element); } }.bind(this) }); // initialize drag method if (window.Drag && this.options.draggable) { this.drag = new Drag.Move(this.calendar, { onDrag: function() { if (window.ie6) { this.iframe.setStyles({ left: this.calendar.style.left, top: this.calendar.style.top }); } }.bind(this) }); } // create calendars array this.calendars = []; var id = 0; var d = new Date(); // today d.setDate(d.getDate() + this.options.direction.toInt()); // correct today for directional offset for (var i in obj) { var cal = { button: new Element('button', { 'type': 'button' }), el: $(i), els: [], id: id++, month: d.getMonth(), visible: false, year: d.getFullYear() }; // fix for bad element (naughty, naughty element!) if (!this.element(i, obj[i], cal)) { continue; } cal.el.addClass(this.classes.calendar); // create cal button cal.button.addClass(this.classes.calendar).addEvent('click', function(cal) { this.toggle(cal); }.pass(cal, this)).injectAfter(cal.el); // read in default value cal.val = this.read(cal); $extend(cal, this.bounds(cal)); // abs bounds of calendar $extend(cal, this.values(cal)); // valid days, months, years this.rebuild(cal); this.calendars.push(cal); // add to cals array } }, // blocked: returns an array of blocked days for the month / year // @param cal (obj) // @returns blocked days (array) blocked: function(cal) { var blocked = []; var offset = new Date(cal.year, cal.month, 1).getDay(); // day of the week (offset) var last = new Date(cal.year, cal.month + 1, 0).getDate(); // last day of this month this.options.blocked.each(function(date){ var values = date.split(' '); // preparation for (var i = 0; i <= 3; i++){ if (!values[i]){ values[i] = (i == 3) ? '' : '*'; } // make sure blocked date contains values for at least d, m and y values[i] = values[i].contains(',') ? values[i].split(',') : new Array(values[i]); // split multiple values var count = values[i].length - 1; for (var j = count; j >= 0; j--){ if (values[i][j].contains('-')){ // a range var val = values[i][j].split('-'); for (var k = val[0]; k <= val[1]; k++){ if (!values[i].contains(k)){ values[i].push(k + ''); } } values[i].splice(j, 1); } } } // execution if (values[2].contains(cal.year + '') || values[2].contains('*')){ if (values[1].contains(cal.month + 1 + '') || values[1].contains('*')){ values[0].each(function(val){ // if blocked value indicates this month / year if (val > 0){ blocked.push(val.toInt()); } // add date to blocked array }); if (values[3]){ // optional value for day of week for (var i = 0; i < last; i++){ var day = (i + offset) % 7; if (values[3].contains(day + '')){ blocked.push(i + 1); // add every date that corresponds to the blocked day of the week to the blocked array } } } } } }, this); return blocked; }, // bounds: returns the start / end bounds of the calendar // @param cal (obj) // @returns obj bounds: function(cal) { // 1. first we assume the calendar has no bounds (or a thousand years in either direction) // by default the calendar will accept a millennium in either direction var start = new Date(1000, 0, 1); // jan 1, 1000 var end = new Date(2999, 11, 31); // dec 31, 2999 // 2. but if the cal is one directional we adjust accordingly var date = new Date().getDate() + this.options.direction.toInt(); if (this.options.direction > 0) { start = new Date(); start.setDate(date + this.options.pad * cal.id); } if (this.options.direction < 0) { end = new Date(); end.setDate(date - this.options.pad * (this.calendars.length - cal.id - 1)); } // 3. then we can further filter the limits by using the pre-existing values in the selects cal.els.each(function(el) { if (el.getTag() == 'select') { if (el.format.test('(y|Y)')) { // search for a year select var years = []; el.getChildren().each(function(option) { // get options var values = this.unformat(option.value, el.format); if (!years.contains(values[0])) { years.push(values[0]); } // add to years array }, this); years.sort(this.sort); if (years[0] > start.getFullYear()) { d = new Date(years[0], start.getMonth() + 1, 0); // last day of new month if (start.getDate() > d.getDate()) { start.setDate(d.getDate()); } start.setYear(years[0]); } if (years.getLast() < end.getFullYear()) { d = new Date(years.getLast(), end.getMonth() + 1, 0); // last day of new month if (end.getDate() > d.getDate()) { end.setDate(d.getDate()); } end.setYear(years.getLast()); } } if (el.format.test('(F|m|M|n)')) { // search for a month select var months_start = []; var months_end = []; el.getChildren().each(function(option) { // get options var values = this.unformat(option.value, el.format); if ($type(values[0]) != 'number' || values[0] == years[0]) { // if it's a year / month combo for curr year, or simply a month select if (!months_start.contains(values[1])) { months_start.push(values[1]); } // add to months array } if ($type(values[0]) != 'number' || values[0] == years.getLast()) { // if it's a year / month combo for curr year, or simply a month select if (!months_end.contains(values[1])) { months_end.push(values[1]); } // add to months array } }, this); months_start.sort(this.sort); months_end.sort(this.sort); if (months_start[0] > start.getMonth()) { d = new Date(start.getFullYear(), months_start[0] + 1, 0); // last day of new month if (start.getDate() > d.getDate()) { start.setDate(d.getDate()); } start.setMonth(months_start[0]); } if (months_end.getLast() < end.getMonth()) { d = new Date(start.getFullYear(), months_end.getLast() + 1, 0); // last day of new month if (end.getDate() > d.getDate()) { end.setDate(d.getDate()); } end.setMonth(months_end.getLast()); } } } }, this); return { 'start': start, 'end': end }; }, // caption: returns the caption element with header and navigation // @param cal (obj) // @returns caption (element) caption: function(cal) { // start by assuming navigation is allowed var navigation = { prev: { 'month': true, 'year': true }, next: { 'month': true, 'year': true } }; // if we're in an out of bounds year if (cal.year == cal.start.getFullYear()) { navigation.prev.year = false; if (cal.month == cal.start.getMonth() && this.options.navigation == 1) { navigation.prev.month = false; } } if (cal.year == cal.end.getFullYear()) { navigation.next.year = false; if (cal.month == cal.end.getMonth() && this.options.navigation == 1) { navigation.next.month = false; } } // special case of improved navigation but months array with only 1 month we can disable all month navigation if ($type(cal.months) == 'array') { if (cal.months.length == 1 && this.options.navigation == 2) { navigation.prev.month = navigation.next.month = false; } } var caption = new Element('caption'); var prev = new Element('a').addClass(this.classes.prev).appendText('\x3c'); // < var next = new Element('a').addClass(this.classes.next).appendText('\x3e'); // > if (this.options.navigation == 2) { var month = new Element('span').addClass(this.classes.month).injectInside(caption); if (navigation.prev.month) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', -1); }.pass(cal, this)).injectInside(month); } month.adopt(new Element('span').appendText(this.options.months[cal.month])); if (navigation.next.month) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', 1); }.pass(cal, this)).injectInside(month); } var year = new Element('span').addClass(this.classes.year).injectInside(caption); if (navigation.prev.year) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'y', -1); }.pass(cal, this)).injectInside(year); } year.adopt(new Element('span').appendText(cal.year)); if (navigation.next.year) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'y', 1); }.pass(cal, this)).injectInside(year); } } else { // 1 or 0 if (navigation.prev.month && this.options.navigation) { prev.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', -1); }.pass(cal, this)).injectInside(caption); } caption.adopt(new Element('span').addClass(this.classes.month).appendText(this.options.months[cal.month])); caption.adopt(new Element('span').addClass(this.classes.year).appendText(cal.year)); if (navigation.next.month && this.options.navigation) { next.clone().addEvent('click', function(cal) { this.navigate(cal, 'm', 1); }.pass(cal, this)).injectInside(caption); } } return caption; }, // changed: run when a select value is changed // @param cal (obj) changed: function(cal) { cal.val = this.read(cal); // update calendar val from inputs $extend(cal, this.values(cal)); // update bounds - based on curr month this.rebuild(cal); // rebuild days select if (!cal.val) { return; } // in case the same date was clicked the cal has no set date we should exit if (cal.val.getDate() < cal.days[0]) { cal.val.setDate(cal.days[0]); } if (cal.val.getDate() > cal.days.getLast()) { cal.val.setDate(cal.days.getLast()); } cal.els.each(function(el) { // then we can set the value to the field el.value = this.format(cal.val, el.format); }, this);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -