UNPKG

jquery-grid

Version:

jQuery Grid by Gijgo.com is a plug-in for the jQuery Javascript library. It is a very fast and extandable datagrid, and will add advanced interaction controls to any HTML table. This plugin has build-in integration with Bootstrap and Material Design. Free

988 lines (855 loc) 41.8 kB
/* * Gijgo DatePicker v1.9.13 * http://gijgo.com/datepicker * * Copyright 2014, 2019 gijgo.com * Released under the MIT license */ /* global window alert jQuery gj */ /** */ gj.datepicker = { plugins: {} }; gj.datepicker.config = { base: { /** Whether to display dates in other months at the start or end of the current month. */ showOtherMonths: false, /** Whether days in other months shown before or after the current month are selectable. * This only applies if the showOtherMonths option is set to true. */ selectOtherMonths: true, /** The width of the datepicker. */ width: undefined, /** The minimum selectable date. When not set, there is no minimum. */ minDate: undefined, /** The maximum selectable date. When not set, there is no maximum */ maxDate: undefined, /** Specifies the format, which is used to format the value of the DatePicker displayed in the input. */ format: 'mm/dd/yyyy', /** The name of the UI library that is going to be in use. */ uiLibrary: 'materialdesign', /** The name of the icons library that is going to be in use. Currently we support Material Icons, Font Awesome and Glyphicons. */ iconsLibrary: 'materialicons', /** The initial datepicker value. */ value: undefined, /** Day of the week start. 0 (Sunday) to 6 (Saturday) */ weekStartDay: 0, /** An array or function that will be used to determine which dates to be disabled for selection by the widget. */ disableDates: undefined, /** An array that will be used to determine which days of week to be disabled for selection by the widget. * The array needs to contains only numbers where 0 is Sunday, 1 is Monday and etc. */ disableDaysOfWeek: undefined, /** Whether to display week number in year on the left side of the calendar. */ calendarWeeks: false, /** Whether to enable keyboard navigation. */ keyboardNavigation: true, /** The language that needs to be in use. */ locale: 'en-us', icons: { /** datepicker icon definition. */ rightIcon: '<i class="gj-icon">event</i>', previousMonth: '<i class="gj-icon chevron-left"></i>', nextMonth: '<i class="gj-icon chevron-right"></i>' }, fontSize: undefined, /** The size of the datepicker input. */ size: 'default', /** If set to true, the datepicker will have modal behavior. */ modal: false, /** If set to true, add header to the datepicker. */ header: false, /** If set to true, add footer with ok and cancel buttons to the datepicker. */ footer: false, /** If set to true, show datepicker on input focus. */ showOnFocus: true, /** If set to true, show datepicker icon on the right side of the input. */ showRightIcon: true, style: { modal: 'gj-modal', wrapper: 'gj-datepicker gj-datepicker-md gj-unselectable', input: 'gj-textbox-md', calendar: 'gj-picker gj-picker-md datepicker gj-unselectable', footer: '', button: 'gj-button-md' } }, bootstrap: { style: { wrapper: 'gj-datepicker gj-datepicker-bootstrap gj-unselectable input-group', input: 'form-control', calendar: 'gj-picker gj-picker-bootstrap datepicker gj-unselectable', footer: 'modal-footer', button: 'btn btn-default' }, iconsLibrary: 'glyphicons', showOtherMonths: true }, bootstrap4: { style: { wrapper: 'gj-datepicker gj-datepicker-bootstrap gj-unselectable input-group', input: 'form-control', calendar: 'gj-picker gj-picker-bootstrap datepicker gj-unselectable', footer: 'modal-footer', button: 'btn btn-default' }, showOtherMonths: true }, fontawesome: { icons: { rightIcon: '<i class="fa fa-calendar" aria-hidden="true"></i>', previousMonth: '<i class="fa fa-chevron-left" aria-hidden="true"></i>', nextMonth: '<i class="fa fa-chevron-right" aria-hidden="true"></i>' } }, glyphicons: { icons: { rightIcon: '<span class="glyphicon glyphicon-calendar"></span>', previousMonth: '<span class="glyphicon glyphicon-chevron-left"></span>', nextMonth: '<span class="glyphicon glyphicon-chevron-right"></span>' } } }; gj.datepicker.methods = { init: function (jsConfig) { gj.widget.prototype.init.call(this, jsConfig, 'datepicker'); this.attr('data-datepicker', 'true'); gj.datepicker.methods.initialize(this, this.data()); return this; }, initialize: function ($datepicker, data) { var $calendar, $rightIcon, $wrapper = $datepicker.parent('div[role="wrapper"]'); if ($wrapper.length === 0) { $wrapper = $('<div role="wrapper" />').addClass(data.style.wrapper); // The css class needs to be added before the wrapping, otherwise doesn't work. $datepicker.wrap($wrapper); } else { $wrapper.addClass(data.style.wrapper); } $wrapper = $datepicker.parent('div[role="wrapper"]'); data.width && $wrapper.css('width', data.width); $datepicker.val(data.value).addClass(data.style.input).attr('role', 'input'); data.fontSize && $datepicker.css('font-size', data.fontSize); if (data.uiLibrary === 'bootstrap' || data.uiLibrary === 'bootstrap4') { if (data.size === 'small') { $wrapper.addClass('input-group-sm'); $datepicker.addClass('form-control-sm'); } else if (data.size === 'large') { $wrapper.addClass('input-group-lg'); $datepicker.addClass('form-control-lg'); } } else { if (data.size === 'small') { $wrapper.addClass('small'); } else if (data.size === 'large') { $wrapper.addClass('large'); } } if (data.showRightIcon) { if (data.uiLibrary === 'bootstrap') { $rightIcon = $('<span class="input-group-addon">' + data.icons.rightIcon + '</span>'); } else if (data.uiLibrary === 'bootstrap4') { $rightIcon = $('<span class="input-group-append"><button class="btn btn-outline-secondary border-left-0" type="button">' + data.icons.rightIcon + '</button></span>'); } else { $rightIcon = $(data.icons.rightIcon); } $rightIcon.attr('role', 'right-icon'); $rightIcon.on('click', function (e) { var $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); if ($calendar.is(':visible')) { gj.datepicker.methods.close($datepicker); } else { gj.datepicker.methods.open($datepicker, data); } }); $wrapper.append($rightIcon); } if (data.showOnFocus) { $datepicker.on('focus', function () { gj.datepicker.methods.open($datepicker, data); }); } $calendar = gj.datepicker.methods.createCalendar($datepicker, data); if (data.footer !== true) { $datepicker.on('blur', function () { $datepicker.timeout = setTimeout(function () { gj.datepicker.methods.close($datepicker); }, 500); }); $calendar.mousedown(function () { clearTimeout($datepicker.timeout); document.activeElement !== $datepicker[0] && $datepicker.focus(); return false; }); $calendar.on('click', function () { clearTimeout($datepicker.timeout); document.activeElement !== $datepicker[0] && $datepicker.focus(); }); } if (data.keyboardNavigation) { $(document).on('keydown', gj.datepicker.methods.createKeyDownHandler($datepicker, $calendar, data)); } }, createCalendar: function ($datepicker, data) { var date, $body, $footer, $btnCancel, $btnOk, $calendar = $('<div role="calendar" type="month"/>').addClass(data.style.calendar).attr('guid', $datepicker.attr('data-guid')); data.fontSize && $calendar.css('font-size', data.fontSize); date = gj.core.parseDate(data.value, data.format, data.locale); if (!date || isNaN(date.getTime())) { date = new Date(); } else { $datepicker.attr('day', date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate()); } $calendar.attr('month', date.getMonth()); $calendar.attr('year', date.getFullYear()); gj.datepicker.methods.renderHeader($datepicker, $calendar, data, date); $body = $('<div role="body" />'); $calendar.append($body); if (data.footer) { $footer = $('<div role="footer" class="' + data.style.footer + '" />'); $btnCancel = $('<button class="' + data.style.button + '">' + gj.core.messages[data.locale].cancel + '</button>'); $btnCancel.on('click', function () { $datepicker.close(); }); $footer.append($btnCancel); $btnOk = $('<button class="' + data.style.button + '">' + gj.core.messages[data.locale].ok + '</button>'); $btnOk.on('click', function () { var date, dayArr, dayStr = $calendar.attr('selectedDay'); if (dayStr) { dayArr = dayStr.split('-'); date = new Date(dayArr[0], dayArr[1], dayArr[2], $calendar.attr('hour') || 0, $calendar.attr('minute') || 0); gj.datepicker.methods.change($datepicker, $calendar, data, date); } else { $datepicker.close(); } }); $footer.append($btnOk); $calendar.append($footer); } $calendar.hide(); $('body').append($calendar); if (data.modal) { $calendar.wrapAll('<div role="modal" class="' + data.style.modal + '"/>'); gj.core.center($calendar); } return $calendar; }, renderHeader: function ($datepicker, $calendar, data, date) { var $header, $date, $year; if (data.header) { $header = $('<div role="header" />'); $year = $('<div role="year" />').on('click', function () { gj.datepicker.methods.renderDecade($datepicker, $calendar, data); $year.addClass('selected'); $date.removeClass('selected'); }); $year.html(gj.core.formatDate(date, 'yyyy', data.locale)); $header.append($year); $date = $('<div role="date" class="selected" />').on('click', function () { gj.datepicker.methods.renderMonth($datepicker, $calendar, data); $date.addClass('selected'); $year.removeClass('selected'); }); $date.html(gj.core.formatDate(date, 'ddd, mmm dd', data.locale)); $header.append($date); $calendar.append($header); } }, updateHeader: function ($calendar, data, date) { $calendar.find('[role="header"] [role="year"]').removeClass('selected').html(gj.core.formatDate(date, 'yyyy', data.locale)); $calendar.find('[role="header"] [role="date"]').addClass('selected').html(gj.core.formatDate(date, 'ddd, mmm dd', data.locale)); $calendar.find('[role="header"] [role="hour"]').removeClass('selected').html(gj.core.formatDate(date, 'HH', data.locale)); $calendar.find('[role="header"] [role="minute"]').removeClass('selected').html(gj.core.formatDate(date, 'MM', data.locale)); }, createNavigation: function ($datepicker, $body, $table, data) { var $row, $navigator, $thead = $('<thead/>'); $navigator = $('<div role="navigator" />'); $navigator.append($('<div>' + data.icons.previousMonth + '</div>').on('click', gj.datepicker.methods.prev($datepicker, data))); $navigator.append($('<div role="period"></div>').on('click', gj.datepicker.methods.changePeriod($datepicker, data))); $navigator.append($('<div>' + data.icons.nextMonth + '</div>').on('click', gj.datepicker.methods.next($datepicker, data))); $body.append($navigator); $row = $('<tr role="week-days" />'); if (data.calendarWeeks) { $row.append('<th><div>&nbsp;</div></th>'); } for (i = data.weekStartDay; i < gj.core.messages[data.locale].weekDaysMin.length; i++) { $row.append('<th><div>' + gj.core.messages[data.locale].weekDaysMin[i] + '</div></th>'); } for (i = 0; i < data.weekStartDay; i++) { $row.append('<th><div>' + gj.core.messages[data.locale].weekDaysMin[i] + '</div></th>'); } $thead.append($row); $table.append($thead); }, renderMonth: function ($datepicker, $calendar, data) { var weekDay, selectedDay, day, month, year, daysInMonth, total, firstDayPosition, i, now, prevMonth, nextMonth, $cell, $day, date, $body = $calendar.children('[role="body"]'), $table = $('<table/>'), $tbody = $('<tbody/>'), period = gj.core.messages[data.locale].titleFormat; $body.off().empty(); gj.datepicker.methods.createNavigation($datepicker, $body, $table, data); month = parseInt($calendar.attr('month'), 10); year = parseInt($calendar.attr('year'), 10); $calendar.attr('type', 'month'); period = period.replace('mmmm', gj.core.messages[data.locale].monthNames[month]).replace('yyyy', year); $calendar.find('div[role="period"]').text(period); daysInMonth = new Array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); if (year % 4 == 0 && year != 1900) { daysInMonth[1] = 29; } total = daysInMonth[month]; firstDayPosition = (new Date(year, month, 1).getDay() + 7 - data.weekStartDay) % 7; weekDay = 0; $row = $('<tr />'); prevMonth = gj.datepicker.methods.getPrevMonth(month, year); for (i = 1; i <= firstDayPosition; i++) { day = (daysInMonth[prevMonth.month] - firstDayPosition + i); date = new Date(prevMonth.year, prevMonth.month, day); if (data.calendarWeeks && i === 1) { $row.append('<td class="calendar-week"><div>' + gj.datepicker.methods.getWeekNumber(date) + '</div></td>'); } $cell = $('<td class="other-month" />'); if (data.showOtherMonths) { $day = $('<div>' + day + '</div>'); $cell.append($day); if (data.selectOtherMonths && gj.datepicker.methods.isSelectable(data, date)) { $cell.addClass('gj-cursor-pointer').attr('day', day).attr('month', prevMonth.month).attr('year', prevMonth.year); $day.on('click', gj.datepicker.methods.dayClickHandler($datepicker, $calendar, data, date)); $day.on('mousedown', function (e) { e.stopPropagation() }); } else { $cell.addClass('disabled'); } } $row.append($cell); weekDay++; } if (i > 1) { $tbody.append($row); } now = new Date(); for (i = 1; i <= total; i++) { date = new Date(year, month, i); if (weekDay == 0) { $row = $('<tr>'); if (data.calendarWeeks) { $row.append('<td class="calendar-week"><div>' + gj.datepicker.methods.getWeekNumber(date) + '</div></td>'); } } $cell = $('<td day="' + i + '" month="' + month + '" year="' + year + '" />'); if (year === now.getFullYear() && month === now.getMonth() && i === now.getDate()) { $cell.addClass('today'); } else { $cell.addClass('current-month'); } $day = $('<div>' + i + '</div>'); if (gj.datepicker.methods.isSelectable(data, date)) { $cell.addClass('gj-cursor-pointer'); $day.on('click', gj.datepicker.methods.dayClickHandler($datepicker, $calendar, data, date)); $day.on('mousedown', function (e) { e.stopPropagation() }); } else { $cell.addClass('disabled'); } $cell.append($day); $row.append($cell); weekDay++; if (weekDay == 7) { $tbody.append($row); weekDay = 0; } } nextMonth = gj.datepicker.methods.getNextMonth(month, year); for (i = 1; weekDay != 0; i++) { date = new Date(nextMonth.year, nextMonth.month, i); $cell = $('<td class="other-month" />'); if (data.showOtherMonths) { $day = $('<div>' + i + '</div>'); if (data.selectOtherMonths && gj.datepicker.methods.isSelectable(data, date)) { $cell.addClass('gj-cursor-pointer').attr('day', i).attr('month', nextMonth.month).attr('year', nextMonth.year); $day.on('click', gj.datepicker.methods.dayClickHandler($datepicker, $calendar, data, date)); $day.on('mousedown', function (e) { e.stopPropagation() }); } else { $cell.addClass('disabled'); } $cell.append($day); } $row.append($cell); weekDay++; if (weekDay == 7) { $tbody.append($row); weekDay = 0; } } $table.append($tbody); $body.append($table); if ($calendar.attr('selectedDay')) { selectedDay = $calendar.attr('selectedDay').split('-'); date = new Date(selectedDay[0], selectedDay[1], selectedDay[2], $calendar.attr('hour') || 0, $calendar.attr('minute') || 0); $calendar.find('tbody td[day="' + selectedDay[2] + '"][month="' + selectedDay[1] + '"]').addClass('selected'); gj.datepicker.methods.updateHeader($calendar, data, date); } }, renderYear: function ($datepicker, $calendar, data) { var year, i, m, $month, $table = $calendar.find('>[role="body"]>table'), $tbody = $table.children('tbody'); $table.children('thead').hide(); year = parseInt($calendar.attr('year'), 10); $calendar.attr('type', 'year'); $calendar.find('div[role="period"]').text(year); $tbody.empty(); for (i = 0; i < 3; i++) { $row = $('<tr />'); for (m = (i * 4); m <= (i * 4) + 3; m++) { $month = $('<div>' + gj.core.messages[data.locale].monthShortNames[m] + '</div>'); $month.on('click', gj.datepicker.methods.selectMonth($datepicker, $calendar, data, m)); $cell = $('<td></td>').append($month); $row.append($cell); } $tbody.append($row); } }, renderDecade: function ($datepicker, $calendar, data) { var year, decade, i, y, $year, $table = $calendar.find('>[role="body"]>table'), $tbody = $table.children('tbody'); $table.children('thead').hide(); year = parseInt($calendar.attr('year'), 10); decade = year - (year % 10); $calendar.attr('type', 'decade'); $calendar.find('div[role="period"]').text(decade + ' - ' + (decade + 9)); $tbody.empty(); for (i = decade - 1; i <= decade + 10 ; i += 4) { $row = $('<tr />'); for (y = i; y <= i + 3; y++) { $year = $('<div>' + y + '</div>'); $year.on('click', gj.datepicker.methods.selectYear($datepicker, $calendar, data, y)); $cell = $('<td></td>').append($year); $row.append($cell); } $tbody.append($row); } }, renderCentury: function ($datepicker, $calendar, data) { var year, century, i, d, $decade, $table = $calendar.find('>[role="body"]>table'), $tbody = $table.children('tbody'); $table.children('thead').hide(); year = parseInt($calendar.attr('year'), 10); century = year - (year % 100); $calendar.attr('type', 'century'); $calendar.find('div[role="period"]').text(century + ' - ' + (century + 99)); $tbody.empty(); for (i = (century - 10); i < century + 100; i += 40) { $row = $('<tr />'); for (d = i; d <= i + 30; d += 10) { $decade = $('<div>' + d + '</div>'); $decade.on('click', gj.datepicker.methods.selectDecade($datepicker, $calendar, data, d)); $cell = $('<td></td>').append($decade); $row.append($cell); } $tbody.append($row); } }, getWeekNumber: function (date) { var d = new Date(date.valueOf()); d.setDate(d.getDate() + 6); d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate())); d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7)); var yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); var weekNo = Math.ceil((((d - yearStart) / 86400000) + 1) / 7); return weekNo; }, getMinDate: function (data) { var minDate; if (data.minDate) { if (typeof (data.minDate) === 'string') { minDate = gj.core.parseDate(data.minDate, data.format, data.locale); } else if (typeof (data.minDate) === 'function') { minDate = data.minDate(); if (typeof minDate === 'string') { minDate = gj.core.parseDate(minDate, data.format, data.locale); } } else if (typeof data.minDate.getMonth === 'function') { minDate = data.minDate; } } return minDate; }, getMaxDate: function (data) { var maxDate; if (data.maxDate) { if (typeof data.maxDate === 'string') { maxDate = gj.core.parseDate(data.maxDate, data.format, data.locale); } else if (typeof data.maxDate === 'function') { maxDate = data.maxDate(); if (typeof maxDate === 'string') { maxDate = gj.core.parseDate(maxDate, data.format, data.locale); } } else if (typeof data.maxDate.getMonth === 'function') { maxDate = data.maxDate; } } return maxDate; }, isSelectable: function (data, date) { var result = true, minDate = gj.datepicker.methods.getMinDate(data), maxDate = gj.datepicker.methods.getMaxDate(data), i; if (minDate && date < minDate) { result = false; } else if (maxDate && date > maxDate) { result = false; } if (result) { if (data.disableDates) { if ($.isArray(data.disableDates)) { for (i = 0; i < data.disableDates.length; i++) { if (data.disableDates[i] instanceof Date && data.disableDates[i].getTime() === date.getTime()) { result = false; } else if (typeof data.disableDates[i] === 'string' && gj.core.parseDate(data.disableDates[i], data.format, data.locale).getTime() === date.getTime()) { result = false; } } } else if (data.disableDates instanceof Function) { result = data.disableDates(date); } } if ($.isArray(data.disableDaysOfWeek) && data.disableDaysOfWeek.indexOf(date.getDay()) > -1) { result = false; } } return result; }, getPrevMonth: function (month, year) { date = new Date(year, month, 1); date.setMonth(date.getMonth() - 1); return { month: date.getMonth(), year: date.getFullYear() }; }, getNextMonth: function (month, year) { date = new Date(year, month, 1); date.setMonth(date.getMonth() + 1); return { month: date.getMonth(), year: date.getFullYear() }; }, prev: function ($datepicker, data) { return function () { var date, month, year, decade, century, $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); year = parseInt($calendar.attr('year'), 10); switch ($calendar.attr('type')) { case 'month': month = parseInt($calendar.attr('month'), 10); date = gj.datepicker.methods.getPrevMonth(month, year); $calendar.attr('month', date.month); $calendar.attr('year', date.year); gj.datepicker.methods.renderMonth($datepicker, $calendar, data); break; case 'year': $calendar.attr('year', year - 1); gj.datepicker.methods.renderYear($datepicker, $calendar, data); break; case 'decade': decade = year - (year % 10); $calendar.attr('year', decade - 10); gj.datepicker.methods.renderDecade($datepicker, $calendar, data); break; case 'century': century = year - (year % 100); $calendar.attr('year', century - 100); gj.datepicker.methods.renderCentury($datepicker, $calendar, data); break; } } }, next: function ($datepicker, data) { return function () { var date, month, year, decade, century, $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); year = parseInt($calendar.attr('year'), 10); switch ($calendar.attr('type')) { case 'month': month = parseInt($calendar.attr('month'), 10); date = gj.datepicker.methods.getNextMonth(month, year); $calendar.attr('month', date.month); $calendar.attr('year', date.year); gj.datepicker.methods.renderMonth($datepicker, $calendar, data); break; case 'year': $calendar.attr('year', year + 1); gj.datepicker.methods.renderYear($datepicker, $calendar, data); break; case 'decade': decade = year - (year % 10); $calendar.attr('year', decade + 10); gj.datepicker.methods.renderDecade($datepicker, $calendar, data); break; case 'century': century = year - (year % 100); $calendar.attr('year', century + 100); gj.datepicker.methods.renderCentury($datepicker, $calendar, data); break; } } }, changePeriod: function ($datepicker, data) { return function (e) { var $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); switch ($calendar.attr('type')) { case 'month': gj.datepicker.methods.renderYear($datepicker, $calendar, data); break; case 'year': gj.datepicker.methods.renderDecade($datepicker, $calendar, data); break; case 'decade': gj.datepicker.methods.renderCentury($datepicker, $calendar, data); break; } } }, dayClickHandler: function ($datepicker, $calendar, data, date) { return function (e) { e && e.stopPropagation(); gj.datepicker.methods.selectDay($datepicker, $calendar, data, date); if (data.footer !== true && data.autoClose !== false) { gj.datepicker.methods.change($datepicker, $calendar, data, date); } return $datepicker; }; }, change: function ($datepicker, $calendar, data, date) { var day = date.getDate(), month = date.getMonth(), year = date.getFullYear(), value = gj.core.formatDate(date, data.format, data.locale); $calendar.attr('month', month); $calendar.attr('year', year); $datepicker.val(value); gj.datepicker.events.change($datepicker); if (window.getComputedStyle($calendar[0]).display !== 'none') { gj.datepicker.methods.close($datepicker); } }, selectDay: function ($datepicker, $calendar, data, date) { var day = date.getDate(), month = date.getMonth(), year = date.getFullYear(); $calendar.attr('selectedDay', year + '-' + month + '-' + day); $calendar.find('tbody td').removeClass('selected'); $calendar.find('tbody td[day="' + day + '"][month="' + month + '"]').addClass('selected'); gj.datepicker.methods.updateHeader($calendar, data, date); gj.datepicker.events.select($datepicker, 'day'); }, selectMonth: function ($datepicker, $calendar, data, month) { return function (e) { $calendar.attr('month', month); gj.datepicker.methods.renderMonth($datepicker, $calendar, data); gj.datepicker.events.select($datepicker, 'month'); }; }, selectYear: function ($datepicker, $calendar, data, year) { return function (e) { $calendar.attr('year', year); gj.datepicker.methods.renderYear($datepicker, $calendar, data); gj.datepicker.events.select($datepicker, 'year'); }; }, selectDecade: function ($datepicker, $calendar, data, year) { return function (e) { $calendar.attr('year', year); gj.datepicker.methods.renderDecade($datepicker, $calendar, data); gj.datepicker.events.select($datepicker, 'decade'); }; }, open: function ($datepicker, data) { var date, $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); if ($datepicker.val()) { $datepicker.value($datepicker.val()); } else { date = new Date(); $calendar.attr("month", date.getMonth()); $calendar.attr("year", date.getFullYear()); } switch ($calendar.attr('type')) { case 'month': gj.datepicker.methods.renderMonth($datepicker, $calendar, data); break; case 'year': gj.datepicker.methods.renderYear($datepicker, $calendar, data); break; case 'decade': gj.datepicker.methods.renderDecade($datepicker, $calendar, data); break; case 'century': gj.datepicker.methods.renderCentury($datepicker, $calendar, data); break; } $calendar.show(); $calendar.closest('div[role="modal"]').show(); if (data.modal) { gj.core.center($calendar); } else { gj.core.setChildPosition($datepicker[0], $calendar[0]); document.activeElement !== $datepicker[0] && $datepicker.focus(); } clearTimeout($datepicker.timeout); gj.datepicker.events.open($datepicker); }, close: function ($datepicker) { var $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); $calendar.hide(); $calendar.closest('div[role="modal"]').hide(); gj.datepicker.events.close($datepicker); }, createKeyDownHandler: function ($datepicker, $calendar, data) { return function (e) { var month, year, day, index, $new, $active, e = e || window.event; if (window.getComputedStyle($calendar[0]).display !== 'none') { $active = gj.datepicker.methods.getActiveCell($calendar); if (e.keyCode == '38') { // up index = $active.index(); $new = $active.closest('tr').prev('tr').find('td:eq(' + index + ')'); if (!$new.is('[day]')) { gj.datepicker.methods.prev($datepicker, data)(); $new = $calendar.find('tbody tr').last().find('td:eq(' + index + ')'); if ($new.is(':empty')) { $new = $calendar.find('tbody tr').last().prev().find('td:eq(' + index + ')'); } } if ($new.is('[day]')) { $new.addClass('focused'); $active.removeClass('focused'); } } else if (e.keyCode == '40') { // down index = $active.index(); $new = $active.closest('tr').next('tr').find('td:eq(' + index + ')'); if (!$new.is('[day]')) { gj.datepicker.methods.next($datepicker, data)(); $new = $calendar.find('tbody tr').first().find('td:eq(' + index + ')'); if (!$new.is('[day]')) { $new = $calendar.find('tbody tr:eq(1)').find('td:eq(' + index + ')'); } } if ($new.is('[day]')) { $new.addClass('focused'); $active.removeClass('focused'); } } else if (e.keyCode == '37') { // left $new = $active.prev('td[day]:not(.disabled)'); if ($new.length === 0) { $new = $active.closest('tr').prev('tr').find('td[day]').last(); } if ($new.length === 0) { gj.datepicker.methods.prev($datepicker, data)(); $new = $calendar.find('tbody tr').last().find('td[day]').last(); } if ($new.length > 0) { $new.addClass('focused'); $active.removeClass('focused'); } } else if (e.keyCode == '39') { // right $new = $active.next('[day]:not(.disabled)'); if ($new.length === 0) { $new = $active.closest('tr').next('tr').find('td[day]').first(); } if ($new.length === 0) { gj.datepicker.methods.next($datepicker, data)(); $new = $calendar.find('tbody tr').first().find('td[day]').first(); } if ($new.length > 0) { $new.addClass('focused'); $active.removeClass('focused'); } } else if (e.keyCode == '13') { // enter day = parseInt($active.attr('day'), 10); month = parseInt($active.attr('month'), 10); year = parseInt($active.attr('year'), 10); gj.datepicker.methods.dayClickHandler($datepicker, $calendar, data, new Date(year, month, day))(); } else if (e.keyCode == '27') { // esc $datepicker.close(); } } } }, getActiveCell: function ($calendar) { var $cell = $calendar.find('td[day].focused'); if ($cell.length === 0) { $cell = $calendar.find('td[day].selected'); if ($cell.length === 0) { $cell = $calendar.find('td[day].today'); if ($cell.length === 0) { $cell = $calendar.find('td[day]:not(.disabled)').first(); } } } return $cell; }, value: function ($datepicker, value) { var $calendar, date, data = $datepicker.data(); if (typeof (value) === "undefined") { return $datepicker.val(); } else { date = gj.core.parseDate(value, data.format, data.locale); if (date && date.getTime()) { $calendar = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); gj.datepicker.methods.dayClickHandler($datepicker, $calendar, data, date)(); } else { $datepicker.val(''); } return $datepicker; } }, destroy: function ($datepicker) { var data = $datepicker.data(), $parent = $datepicker.parent(), $picker = $('body').find('[role="calendar"][guid="' + $datepicker.attr('data-guid') + '"]'); if (data) { $datepicker.off(); if ($picker.parent('[role="modal"]').length > 0) { $picker.unwrap(); } $picker.remove(); $datepicker.removeData(); $datepicker.removeAttr('data-type').removeAttr('data-guid').removeAttr('data-datepicker'); $datepicker.removeClass(); $parent.children('[role="right-icon"]').remove(); $datepicker.unwrap(); } return $datepicker; } }; gj.datepicker.events = { /** * Triggered when the datepicker value is changed. * */ change: function ($datepicker) { return $datepicker.triggerHandler('change'); }, /** * Triggered when new value is selected inside the picker. * */ select: function ($datepicker, type) { return $datepicker.triggerHandler('select', [type]); }, /** * Event fires when the calendar is opened. */ open: function ($datepicker) { return $datepicker.triggerHandler('open'); }, /** * Event fires when the calendar is closed. */ close: function ($datepicker) { return $datepicker.triggerHandler('close'); } }; gj.datepicker.widget = function ($element, jsConfig) { var self = this, methods = gj.datepicker.methods; /** Gets or sets the value of the datepicker. */ self.value = function (value) { return methods.value(this, value); }; /** Remove datepicker functionality from the element. */ self.destroy = function () { return methods.destroy(this); }; /** Open the calendar. */ self.open = function () { return methods.open(this, this.data()); }; /** Close the calendar. */ self.close = function () { return methods.close(this); }; $.extend($element, self); if ('true' !== $element.attr('data-datepicker')) { methods.init.call($element, jsConfig); } return $element; }; gj.datepicker.widget.prototype = new gj.widget(); gj.datepicker.widget.constructor = gj.datepicker.widget; (function ($) { $.fn.datepicker = function (method) { var $widget; if (this && this.length) { if (typeof method === 'object' || !method) { return new gj.datepicker.widget(this, method); } else { $widget = new gj.datepicker.widget(this, null); if ($widget[method]) { return $widget[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else { throw 'Method ' + method + ' does not exist.'; } } } }; })(jQuery);