From 3f3525efd343557781ecb2c589ec321a64486105 Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Wed, 14 Mar 2018 18:59:57 +0300 Subject: [PATCH] Slightly more refactoring (allow options), add select styles to material css --- calendar-material.css | 241 +++++++++++--------- calendar.css | 2 +- calendar.js | 509 +++++++++++++++++++++--------------------- test.htm | 5 + 4 files changed, 394 insertions(+), 363 deletions(-) diff --git a/calendar-material.css b/calendar-material.css index ef0b7d7..2b8c64d 100644 --- a/calendar-material.css +++ b/calendar-material.css @@ -9,160 +9,181 @@ font-family: Roboto, sans-serif; box-shadow: 0 19px 60px rgba(0, 0, 0, .3), 0 15px 20px rgba(0, 0, 0, .22) } +.calendar-box select { + height: 36px; + line-height: 36px; + font-family: Roboto, sans-serif; + font-size: 15px; + text-transform: uppercase; + font-weight: 500; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-outline: 0; + -moz-outline: 0; + outline: 0; + padding: 0; + color: white; + background: transparent; + border: 0; + text-align: center; + cursor: pointer; + transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; +} +.calendar-box select:hover { + background: rgba(255, 255, 255, 0.3); +} +.calendar-box select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 white; +} .calendar-box select.calendar-month { - width: 90px; - margin-right: 3px; + width: 90px; + margin-right: 3px; } .calendar-box select.calendar-year { - width: 70px; + width: 70px; } .calendar-box .calendar-cancel { - font-family: Roboto, sans-serif; - font-size: 15px; - border: 0; - width: auto; - margin: 10px; - padding: 0 12px; - float: right; - text-decoration: none; - color: inherit; - text-transform: uppercase; - height: 36px; - background: transparent; - text-align: center; - line-height: 36px; - cursor: pointer; - transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; + font-family: Roboto, sans-serif; + font-size: 15px; + border: 0; + width: auto; + margin: 10px; + padding: 0 12px; + float: right; + text-decoration: none; + color: inherit; + text-transform: uppercase; + height: 36px; + background: transparent; + text-align: center; + line-height: 36px; + cursor: pointer; + transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; } .calendar-box .calendar-cancel:hover { - background: rgba(0, 0, 0, 0.14); + background: rgba(0, 0, 0, 0.14); } .calendar-box table { - border-collapse: collapse; - width: 100%; - font-weight: normal; - font-size: 13px; + border-collapse: collapse; + width: 100%; + font-weight: normal; + font-size: 13px; } .calendar-box td.months, .calendar-box td.years { - width: 25%; - text-align: center; - box-sizing: border-box; - padding: 0; - vertical-align: top; + width: 25%; + text-align: center; + box-sizing: border-box; + padding: 0; + vertical-align: top; } .calendar-box td.months a, .calendar-box td.years a { - text-decoration: none; - line-height: 42px; - height: 43px; - display: block; - padding-right: 1px; - box-sizing: border-box; - color: #777; - transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; + text-decoration: none; + line-height: 42px; + height: 43px; + display: block; + padding-right: 1px; + box-sizing: border-box; + color: #777; + transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; } .calendar-box td.days { - width: 43px; - height: 43px; - padding: 3px; - box-sizing: border-box; - text-align: center; + width: 43px; + height: 43px; + padding: 3px; + box-sizing: border-box; + text-align: center; } .calendar-box td.days a { - text-decoration: none; - line-height: 36px; - height: 37px; - width: 37px; - display: block; - padding-right: 1px; - border-radius: 50%; - box-sizing: border-box; - color: #777; - transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; + text-decoration: none; + line-height: 36px; + height: 37px; + width: 37px; + display: block; + padding-right: 1px; + border-radius: 50%; + box-sizing: border-box; + color: #777; + transition: all 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; } .calendar-box td a:hover { - background: rgba(3, 169, 244, 0.3); + background: rgba(3, 169, 244, 0.3); } .calendar-box td.selected a { - background: rgb(3, 169, 244); - color: white; + background: rgb(3, 169, 244); + color: white; } .calendar-box td.days.today a { - border: 1px solid rgb(3, 169, 244); + border: 1px solid rgb(3, 169, 244); } .calendar-box td.days.today a:hover { - border: 1px solid transparent; + border: 1px solid transparent; } .calendar-box tr.header td { - color: #aaa; - text-transform: uppercase; - width: 43px; - height: 43px; - box-sizing: border-box; - text-align: center; + color: #aaa; + text-transform: uppercase; + width: 43px; + height: 43px; + box-sizing: border-box; + text-align: center; } .calendar-box td { background: #f4f6f8; } .calendar-box td.future { color: #606060; } .calendar-box .calendar-title { - text-align: center; - white-space: nowrap; - padding: 10px 56px; - background: #03a9f4; - font-weight: 500; - font-size: 16px; - line-height: 36px; - color: white; - position: relative; + text-align: center; + white-space: nowrap; + padding: 10px 56px; + background: #03a9f4; + font-weight: 500; + font-size: 16px; + line-height: 36px; + color: white; + position: relative; } - .calendar-box .calendar-title a { - display: inline-block; - text-decoration: none; - color: inherit; - text-transform: uppercase; - height: 36px; - padding: 0 12px; - transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; + display: inline-block; + text-decoration: none; + color: inherit; + text-transform: uppercase; + height: 36px; + padding: 0 12px; + transition: background 0.35s cubic-bezier(0.4, 0, 0.2, 1) !important; } - .calendar-box .calendar-title a:hover { - background: rgba(255, 255, 255, 0.3); + background: rgba(255, 255, 255, 0.3); } - .calendar-box .calendar-title a.prev { - position: absolute; - left: 10px; - padding: 0; - width: 36px; + position: absolute; + left: 10px; + padding: 0; + width: 36px; } - .calendar-box .calendar-title a.next { - position: absolute; - right: 10px; - padding: 0; - width: 36px; + position: absolute; + right: 10px; + padding: 0; + width: 36px; } - .calendar-box .calendar-title a.prev:after { - content: "chevron_left"; + content: "chevron_left"; } - .calendar-box .calendar-title a.next:after { - content: "chevron_right"; + content: "chevron_right"; } - .calendar-box .calendar-title a.prev:after, .calendar-box .calendar-title a.next:after { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - display: inline-block; - text-transform: none; - letter-spacing: normal; - word-wrap: normal; - white-space: nowrap; - direction: ltr; - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; - -moz-osx-font-smoothing: grayscale; - font-feature-settings: 'liga'; + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + display: inline-block; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + -moz-osx-font-smoothing: grayscale; + font-feature-settings: 'liga'; } diff --git a/calendar.css b/calendar.css index 0b0bc9d..af13c99 100644 --- a/calendar.css +++ b/calendar.css @@ -1,4 +1,4 @@ -/* Default CSS for calendar.js, version: 2015-05-03 */ +/* Default CSS for calendar.js, version: 2018-03-14 */ .calendar-box { display: none; background: #fff; diff --git a/calendar.js b/calendar.js index b9285e8..5cd687d 100644 --- a/calendar.js +++ b/calendar.js @@ -3,9 +3,8 @@ * Creates a calendar widget which can be used to select the date more easily than using just a text box * * Original: http://www.openjs.com/scripts/ui/calendar/ - * Modified: http://svn.yourcmc.ru/viewvc.py/vitaphoto/js/{util.js,calendar.js,calendar.css} - * (uses addListener() and getOffset() from util.js) - * Version: 2017-05-03 + * Modified: http://yourcmc.ru/git/vitalif-js/calendar + * Version: 2018-03-14 * License: MIT-like, http://www.openjs.com/license.php * * Example: @@ -14,9 +13,12 @@ * Calendar.set("date"); * */ -if (!window.Calendar) { -window.Calendar = { - // Configuration: +function Calendar() +{ +} + +// Configuration +Calendar.defaultOptions = { month_names: ["Январь","Февраль","Март","Апрель","Май","Июнь","Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"], close_label: 'Закрыть', weekdays: ["Пн","Вт","Ср","Чт","Пт","Сб","Вс"], @@ -24,278 +26,281 @@ window.Calendar = { selectboxes: false, // true: use selectboxes for year and month, false: show months and years in table years: {min: -70, max: 10}, // range of displayed years if selectboxes==true format: 'd.m.Y', // either d.m.Y or Y-m-d, other formats are not supported - - // State variables: month_days: [31,28,31,30,31,30,31,31,30,31,30,31], // Today's date today: new Date(), - // Selected date - selected: new Date(), - opt: {}, - data: [], - addedListener: false, +}; - //Functions - /// Used to create HTML in a optimized way. - wrt:function(txt) { - this.data.push(txt); - }, - fin:function() { - this.wrt(""+this.close_label+""); - document.getElementById(this.opt['calendar']).innerHTML = this.data.join(""); - this.data = []; - }, +// State variables +Calendar.instance = null; +Calendar.box = null; +Calendar.addedListener = false; - /// Called when the user clicks on a date in the calendar. - selectDate:function(year,month,day) { - var i = this.opt["input"]; - var t = i.value.split(/\s+/, 2)[1]||''; - if (t) - t = ' '+t; - i.value = (this.format == 'Y-m-d' ? year + '-' + month + '-' + day : day + '.' + month + '.' + year) + t; - this.hideCalendar(); - }, +Calendar.prototype.setHTML = function(html) +{ + html += ""+this.close_label+""; + Calendar.box.innerHTML = html; +}; - showMonths:function(year, month) { - var cur_y = this.today.getFullYear(); - var cur_m = this.today.getMonth(); - var sel_m = this.selected.getFullYear() == year ? this.selected.getMonth() : -1; - this.wrt(""); - this.wrt(""); - this.wrt(""); +/// Called when the user clicks on a date in the calendar. +Calendar.prototype.selectDate = function(year, month, day) +{ + var i = this.input; + var t = i.value.split(/\s+/, 2)[1]||''; + if (t) + t = ' '+t; + i.value = (this.format == 'Y-m-d' ? year + '-' + month + '-' + day : day + '.' + month + '.' + year) + t; + Calendar.hideCalendar(); +}; + +Calendar.prototype.showMonths = function(year, month) +{ + var cur_y = this.today.getFullYear(); + var cur_m = this.today.getMonth(); + var sel_m = this.selected.getFullYear() == year ? this.selected.getMonth() : -1; + var html = ''; + html += "
"); - this.wrt(" "+year+""); - this.wrt("
"; + html += ""; + html += ""; + for (var i in this.month_names) { + if (i && !(i % 3)) + html += ""; + var class_name = (year < cur_y || year == cur_y && i < cur_m ? 'past' : + (year > cur_y || year == cur_y && i > cur_m ? 'future' : 'today')) + + (i == sel_m ? ' selected' : ''); + html += ""; + } + html += ""; + html += "
"; + html += " "+year+""; + html += "
"+this.month_names[i]+"
"; + this.setHTML(html); +}; + +Calendar.prototype.showYears = function(year) +{ + var beg = year & ~15; + var cur_y = this.today.getFullYear(); + var sel_y = this.selected.getFullYear(); + var html = ''; + html += ""; + html += ""; + html += ""; + for (var i = 0; i < 16; i++) { + if (i && !(i % 4)) + html += ""; + var class_name = (beg+i < cur_y ? 'past' : (beg+i > cur_y ? 'future' : 'today')) + + (beg+i == sel_y ? ' selected' : ''); + html += ""; + } + html += ""; + html += "
"; + html += " "; + html += " "+beg+" - "+(beg+15)+""; + html += " "; + html += "
"+(beg+i)+"
"; + this.setHTML(html); +}; + +/// Creates a calendar with the date given in the argument as the selected date. +Calendar.prototype.makeCalendar = function(year, month) +{ + // Display the table + var next_month = month+1; + var next_month_year = year; + if (next_month >= 12) { + next_month = 0; + next_month_year++; + } + + var previous_month = month-1; + var previous_month_year = year; + if (previous_month < 0) { + previous_month = 11; + previous_month_year--; + } + + var current_year = this.today.getFullYear(); + + var html = ''; + html += ""; + html += ""); - var class_name = (year < cur_y || year == cur_y && i < cur_m ? 'past' : - (year > cur_y || year == cur_y && i > cur_m ? 'future' : 'today')) - + (i == sel_m ? ' selected' : ''); - this.wrt(""); + html += ""); - this.wrt("
"; + if (!this.selectboxes) { + html += " "+this.month_names[month]+""; + html += " "+year+""; + } else { + html += "
"+this.month_names[i]+"
"); - this.fin(); - }, - - showYears:function(year) { - var beg = year & ~15; - var cur_y = this.today.getFullYear(); - var sel_y = this.selected.getFullYear(); - this.wrt(""); - this.wrt(""); - this.wrt(""); - for (var i = 0; i < 16; i++) { - if (i && !(i % 4)) - this.wrt(""); - var class_name = (beg+i < cur_y ? 'past' : (beg+i > cur_y ? 'future' : 'today')) - + (beg+i == sel_y ? ' selected' : ''); - this.wrt(""); + html += ""; + html += ""); - this.wrt("
"); - this.wrt(" "); - this.wrt(" "+beg+" - "+(beg+15)+""); - this.wrt(" "); - this.wrt("
"+(beg+i)+"
"); - this.fin(); - }, + html += ""; + } + html += " "; + html += ""; + for (var weekday = 0; weekday < 7; weekday++) + html += ""+this.weekdays[weekday]+""; + html += ""; - /// Creates a calendar with the date given in the argument as the selected date. - makeCalendar:function(year, month) { - // Display the table - var next_month = month+1; - var next_month_year = year; - if (next_month >= 12) { - next_month = 0; - next_month_year++; - } + // Get the first day of this month + var first_day = new Date(year,month,1); + var start_day = (first_day.getDay()+this.sunday)%7; - var previous_month = month-1; - var previous_month_year = year; - if (previous_month < 0) { - previous_month = 11; - previous_month_year--; - } + var d = 1; + var flag = 0; - var current_year = this.today.getFullYear(); + // Leap year support + if (!(year % 4) && ((year % 100) || !(year % 400))) + this.month_days[1] = 29; + else + this.month_days[1] = 28; - this.wrt(""); - this.wrt(""); - this.wrt(""); - for (var weekday = 0; weekday < 7; weekday++) - this.wrt(""); - this.wrt(""); + var days_in_this_month = this.month_days[month]; - // Get the first day of this month - var first_day = new Date(year,month,1); - var start_day = (first_day.getDay()+Calendar.sunday)%7; + // Create the calendar + var yea = this.today.getFullYear(); + var all_diff = (year - yea) || (month - this.today.getMonth()); + var sel_day = year == this.selected.getFullYear() && month == this.selected.getMonth() ? this.selected.getDate() : -1; + for (var i = 0; i <= 5; i++) { + if (w >= days_in_this_month) + break; + html += ""; + for (var j = 0; j < 7; j++) { + if (d > days_in_this_month) + flag = 0; // If the days has overshooted the number of days in this month, stop writing + else if (j >= start_day && !flag) + flag = 1; // If the first day of this month has come, start the date writing - var d = 1; - var flag = 0; + if (flag) { + var w = d, mon = month+1; + if (w < 10) + w = "0" + w; + if (mon < 10) + mon = "0" + mon; - // Leap year support - if (!(year % 4) && ((year % 100) || !(year % 400))) - this.month_days[1] = 29; - else - this.month_days[1] = 28; + // Is it today? + var class_name = ''; - var days_in_this_month = this.month_days[month]; - - // Create the calendar - var yea = this.today.getFullYear(); - var all_diff = (year - yea) || (month - this.today.getMonth()); - var sel_day = year == this.selected.getFullYear() && month == this.selected.getMonth() ? this.selected.getDate() : -1; - for (var i = 0; i <= 5; i++) { - if (w >= days_in_this_month) - break; - this.wrt(""); - for (var j = 0; j < 7; j++) { - if (d > days_in_this_month) - flag = 0; // If the days has overshooted the number of days in this month, stop writing - else if (j >= start_day && !flag) - flag = 1; // If the first day of this month has come, start the date writing - - if (flag) { - var w = d, mon = month+1; - if (w < 10) - w = "0" + w; - if (mon < 10) - mon = "0" + mon; - - // Is it today? - var class_name = ''; - - var diff = all_diff || (d - this.today.getDate()); - if (diff < 0) - class_name = ' past'; - else if (!diff) - class_name = ' today'; - else - class_name = ' future'; - - if (d == sel_day) - class_name += ' selected'; - - class_name += " " + this.weekdays[j].toLowerCase(); - - this.wrt(""); - d++; - } + var diff = all_diff || (d - this.today.getDate()); + if (diff < 0) + class_name = ' past'; + else if (!diff) + class_name = ' today'; else - this.wrt(""); + class_name = ' future'; + + if (d == sel_day) + class_name += ' selected'; + + class_name += " " + this.weekdays[j].toLowerCase(); + + html += ""; + d++; } - this.wrt(""); + else + html += ""; } - this.wrt("
"); - if (!this.selectboxes) { - this.wrt(" "+this.month_names[month]+""); - this.wrt(" "+year+""); - } else { - this.wrt(" "); - this.wrt(""); - } - this.wrt("
"+this.weekdays[weekday]+"
"+d+" "+d+"
 
"); - this.fin(); - }, + html += ""; + } + html += ""; + this.setHTML(html); +}; - /// Display the calendar - if a date exists in the input box, that will be selected in the calendar. - showCalendar: function() { - var input = this.opt['input']; +/// Display the calendar - if a date exists in the input box, that will be selected in the calendar. +Calendar.prototype.showCalendar = function() +{ + Calendar.instance = this; + var input = this.input; - //Position the div in the correct location... - var div = document.getElementById(this.opt['calendar']); - var xy = getOffset(input); - var width = input.clientWidth||input.offsetWidth; - var height = input.clientHeight||input.offsetHeight; - div.style.left = (xy.left-1)+"px"; - div.style.top = (xy.top+height-1)+"px"; + //Position the div in the correct location... + var div = Calendar.box; + var xy = getOffset(input); + var width = input.clientWidth||input.offsetWidth; + var height = input.clientHeight||input.offsetHeight; + div.style.left = (xy.left-1)+"px"; + div.style.top = (xy.top+height-1)+"px"; - // Show the calendar with the date in the input as the selected date - this.selected = new Date(); - var date_in_input = input.value.replace(/\s+.*$/, ''); //Remove time - if(date_in_input) { - // date format is HARDCODE - var selected_date = false; - var date_parts = date_in_input.split("-"); + // Show the calendar with the date in the input as the selected date + this.selected = new Date(); + var date_in_input = input.value.replace(/\s+.*$/, ''); //Remove time + if (date_in_input) { + // date format is HARDCODE + var selected_date = false; + var date_parts = date_in_input.split("-"); + if (date_parts.length == 3) { + // Y-m-d + date_parts[1]--; //Month starts with 0 + selected_date = new Date(date_parts[0], date_parts[1], date_parts[2]); + } else if (date_parts.length == 1) { + date_parts = date_in_input.split('.'); if (date_parts.length == 3) { - // Y-m-d + // d.m.Y date_parts[1]--; //Month starts with 0 - selected_date = new Date(date_parts[0], date_parts[1], date_parts[2]); - } else if (date_parts.length == 1) { - date_parts = date_in_input.split('.'); - if (date_parts.length == 3) { - // d.m.Y - date_parts[1]--; //Month starts with 0 - selected_date = new Date(date_parts[2], date_parts[1], date_parts[0]); - } - } - if (selected_date && !isNaN(selected_date.getFullYear())) { //Valid date. - this.selected = selected_date; + selected_date = new Date(date_parts[2], date_parts[1], date_parts[0]); } } - - this.makeCalendar(this.selected.getFullYear(), this.selected.getMonth()); - document.getElementById(this.opt['calendar']).style.display = "block"; - }, - - /// Hides the currently show calendar. - hideCalendar: function() { - document.getElementById(this.opt['calendar']).style.display = "none"; - }, - - /// Setup a text input box to be a calendar box. - set: function(input_or_id) { - if (typeof input_or_id == 'string') - input_or_id = document.getElementById(input_or_id); - if (!input_or_id) - return; // If the input field is not there, exit. - - if (!Calendar.opt['calendar'] || !document.getElementById(Calendar.opt['calendar'])) - Calendar.init(); - - addListener(input_or_id, 'focus', function(ev) { - Calendar.opt['input'] = this; - Calendar.showCalendar(); - }); - }, - - /// Will be called once when the first input is set. - init: function() { - if(!this.opt['calendar'] || !document.getElementById(this.opt['calendar'])) { - var div = document.createElement('div'); - if(!this.opt['calendar']) - this.opt['calendar'] = 'calender_div_'+ Math.round(Math.random() * 100); - - div.setAttribute('id',this.opt['calendar']); - div.className="calendar-box"; - addListener(div, "mousedown", function(ev) { - ev = ev || window.event; - if (ev.stopPropagation) - ev.stopPropagation(); - else - ev.cancelBubble = true; - return true; - }); - document.getElementsByTagName("body")[0].insertBefore(div,document.getElementsByTagName("body")[0].firstChild); - - if (!Calendar.addedListener) { - addListener(document, "mousedown", function() { Calendar.hideCalendar(); }); - Calendar.addedListener = true; - } + if (selected_date && !isNaN(selected_date.getFullYear())) { //Valid date. + this.selected = selected_date; } } -} -} + + this.makeCalendar(this.selected.getFullYear(), this.selected.getMonth()); + Calendar.box.style.display = "block"; +}; + +/// Hides the currently show calendar. +Calendar.hideCalendar = function() +{ + Calendar.box.style.display = "none"; +}; + +/// Setup a text input box to be a calendar box. +Calendar.set = function(input_or_id, options) +{ + if (typeof input_or_id == 'string') + input_or_id = document.getElementById(input_or_id); + if (!input_or_id) + return; // If the input field is not there, exit. + options = options||{}; + var instance = new Calendar(); + for (var i in Calendar.defaultOptions) + instance[i] = options[i] || Calendar.defaultOptions[i]; + instance.input = input_or_id; + Calendar.init(); + addListener(input_or_id, 'focus', function(ev) { + instance.showCalendar(); + }); + return instance; +}; + +/// Will be called once when the first input is set. +Calendar.init = function() +{ + if (!Calendar.box || !Calendar.box.parentNode) { + var div = document.createElement('div'); + if (!Calendar.box) + Calendar.box = div; + div.className = "calendar-box"; + addListener(div, "mousedown", function(ev) { + ev = ev || window.event; + if (ev.stopPropagation) + ev.stopPropagation(); + else + ev.cancelBubble = true; + return true; + }); + document.getElementsByTagName("body")[0].insertBefore(div,document.getElementsByTagName("body")[0].firstChild); + if (!Calendar.addedListener) { + addListener(document, "mousedown", function() { Calendar.hideCalendar(); }); + Calendar.addedListener = true; + } + } +}; diff --git a/test.htm b/test.htm index ad7e83e..3649be6 100644 --- a/test.htm +++ b/test.htm @@ -8,3 +8,8 @@ + + +