UNPKG

framework7-without-localstorage

Version:

Full featured mobile HTML framework for building iOS & Android apps

999 lines (932 loc) 42.3 kB
/*====================================================== ************ Calendar ************ ======================================================*/ var Calendar = function (params) { var p = this; var defaults = { monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August' , 'September' , 'October', 'November', 'December'], monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], firstDay: 1, // First day of the week, Monday weekendDays: [0, 6], // Sunday and Saturday multiple: false, rangePicker: false, dateFormat: 'yyyy-mm-dd', direction: 'horizontal', // or 'vertical' minDate: null, maxDate: null, disabled: null, // dates range of disabled days events: null, // dates range of days with events rangesClasses: null, //array with custom classes date ranges touchMove: true, animate: true, closeOnSelect: false, monthPicker: true, monthPickerTemplate: '<div class="picker-calendar-month-picker">' + '<a href="#" class="link icon-only picker-calendar-prev-month"><i class="icon icon-prev"></i></a>' + '<span class="current-month-value"></span>' + '<a href="#" class="link icon-only picker-calendar-next-month"><i class="icon icon-next"></i></a>' + '</div>', yearPicker: true, yearPickerTemplate: '<div class="picker-calendar-year-picker">' + '<a href="#" class="link icon-only picker-calendar-prev-year"><i class="icon icon-prev"></i></a>' + '<span class="current-year-value"></span>' + '<a href="#" class="link icon-only picker-calendar-next-year"><i class="icon icon-next"></i></a>' + '</div>', weekHeader: true, // Common settings closeByOutsideClick: true, scrollToInput: true, inputReadOnly: true, convertToPopover: true, onlyInPopover: false, toolbar: true, toolbarCloseText: 'Done', headerPlaceholder: 'Select date', header: app.params.material, footer: app.params.material, toolbarTemplate: '<div class="toolbar">' + '<div class="toolbar-inner">' + '{{monthPicker}}' + '{{yearPicker}}' + '</div>' + '</div>', headerTemplate: '<div class="picker-header">' + '<div class="picker-calendar-selected-date">{{placeholder}}</div>' + '</div>', footerTemplate: '<div class="picker-footer">' + '<a href="#" class="button close-picker">{{closeText}}</a>' + '</div>', /* Callbacks onMonthAdd onChange onOpen onClose onDayClick onMonthYearChangeStart onMonthYearChangeEnd */ }; params = params || {}; for (var def in defaults) { if (typeof params[def] === 'undefined') { params[def] = defaults[def]; } } p.params = params; p.initialized = false; // Inline flag p.inline = p.params.container ? true : false; // Is horizontal p.isH = p.params.direction === 'horizontal'; // RTL inverter var inverter = p.isH ? (app.rtl ? -1 : 1) : 1; // Animating flag p.animating = false; // Should be converted to popover function isPopover() { var toPopover = false; if (!p.params.convertToPopover && !p.params.onlyInPopover) return toPopover; if (!p.inline && p.params.input) { if (p.params.onlyInPopover) toPopover = true; else { if (app.device.ios) { toPopover = app.device.ipad ? true : false; } else { if (app.width >= 768) toPopover = true; } } } return toPopover; } function inPopover() { if (p.opened && p.container && p.container.length > 0 && p.container.parents('.popover').length > 0) return true; else return false; } // Format date function formatDate(date) { date = new Date(date); var year = date.getFullYear(); var month = date.getMonth(); var month1 = month + 1; var day = date.getDate(); var weekDay = date.getDay(); return p.params.dateFormat .replace(/yyyy/g, year) .replace(/yy/g, (year + '').substring(2)) .replace(/mm/g, month1 < 10 ? '0' + month1 : month1) .replace(/m(\W+)/g, month1 + '$1') .replace(/MM/g, p.params.monthNames[month]) .replace(/M(\W+)/g, p.params.monthNamesShort[month] + '$1') .replace(/dd/g, day < 10 ? '0' + day : day) .replace(/d(\W+)/g, day + '$1') .replace(/DD/g, p.params.dayNames[weekDay]) .replace(/D(\W+)/g, p.params.dayNamesShort[weekDay] + '$1'); } // Value p.addValue = function (value) { if (p.params.multiple) { if (!p.value) p.value = []; var inValuesIndex; for (var i = 0; i < p.value.length; i++) { if (new Date(value).getTime() === new Date(p.value[i]).getTime()) { inValuesIndex = i; } } if (typeof inValuesIndex === 'undefined') { p.value.push(value); } else { p.value.splice(inValuesIndex, 1); } p.updateValue(); } else if (p.params.rangePicker) { if (!p.value) p.value = []; if (p.value.length === 2 || p.value.length === 0) { p.value = []; } if (p.value[0] !== value) p.value.push(value); else p.value = []; p.value.sort(function (a,b) { return a - b; }); p.updateValue(); } else { p.value = [value]; p.updateValue(); } }; p.setValue = function (arrValues) { p.value = arrValues; p.updateValue(); }; p.updateValue = function (onlyHeader) { var i, inputValue; if (p.container && p.container.length > 0) { p.wrapper.find('.picker-calendar-day-selected').removeClass('picker-calendar-day-selected'); var valueDate; if (p.params.rangePicker && p.value.length === 2) { for (i = new Date(p.value[0]).getTime(); i <= new Date(p.value[1]).getTime(); i += 24*60*60*1000) { valueDate = new Date(i); p.wrapper.find('.picker-calendar-day[data-date="' + valueDate.getFullYear() + '-' + valueDate.getMonth() + '-' + valueDate.getDate() + '"]').addClass('picker-calendar-day-selected'); } } else { for (i = 0; i < p.value.length; i++) { valueDate = new Date(p.value[i]); p.wrapper.find('.picker-calendar-day[data-date="' + valueDate.getFullYear() + '-' + valueDate.getMonth() + '-' + valueDate.getDate() + '"]').addClass('picker-calendar-day-selected'); } } } if (p.params.onChange) { p.params.onChange(p, p.value); } if ((p.input && p.input.length > 0) || (app.params.material && p.params.header)) { if (p.params.formatValue) inputValue = p.params.formatValue(p, p.value); else { inputValue = []; for (i = 0; i < p.value.length; i++) { inputValue.push(formatDate(p.value[i])); } inputValue = inputValue.join(p.params.rangePicker ? ' - ' : ', '); } if (app.params.material && p.params.header && p.container && p.container.length > 0) { p.container.find('.picker-calendar-selected-date').text(inputValue); } if (p.input && p.input.length > 0 && !onlyHeader) { $(p.input).val(inputValue); $(p.input).trigger('change'); } } }; // Columns Handlers p.initCalendarEvents = function () { var col; var allowItemClick = true; var isTouched, isMoved, touchStartX, touchStartY, touchCurrentX, touchCurrentY, touchStartTime, touchEndTime, startTranslate, currentTranslate, wrapperWidth, wrapperHeight, percentage, touchesDiff, isScrolling; function handleTouchStart (e) { if (isMoved || isTouched) return; // e.preventDefault(); isTouched = true; touchStartX = touchCurrentY = e.type === 'touchstart' ? e.targetTouches[0].pageX : e.pageX; touchStartY = touchCurrentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY; touchStartTime = (new Date()).getTime(); percentage = 0; allowItemClick = true; isScrolling = undefined; startTranslate = currentTranslate = p.monthsTranslate; } function handleTouchMove (e) { if (!isTouched) return; touchCurrentX = e.type === 'touchmove' ? e.targetTouches[0].pageX : e.pageX; touchCurrentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY; if (typeof isScrolling === 'undefined') { isScrolling = !!(isScrolling || Math.abs(touchCurrentY - touchStartY) > Math.abs(touchCurrentX - touchStartX)); } if (p.isH && isScrolling) { isTouched = false; return; } e.preventDefault(); if (p.animating) { isTouched = false; return; } allowItemClick = false; if (!isMoved) { // First move isMoved = true; wrapperWidth = p.wrapper[0].offsetWidth; wrapperHeight = p.wrapper[0].offsetHeight; p.wrapper.transition(0); } touchesDiff = p.isH ? touchCurrentX - touchStartX : touchCurrentY - touchStartY; percentage = touchesDiff/(p.isH ? wrapperWidth : wrapperHeight); currentTranslate = (p.monthsTranslate * inverter + percentage) * 100; // Transform wrapper p.wrapper.transform('translate3d(' + (p.isH ? currentTranslate : 0) + '%, ' + (p.isH ? 0 : currentTranslate) + '%, 0)'); } function handleTouchEnd (e) { if (!isTouched || !isMoved) { isTouched = isMoved = false; return; } isTouched = isMoved = false; touchEndTime = new Date().getTime(); if (touchEndTime - touchStartTime < 300) { if (Math.abs(touchesDiff) < 10) { p.resetMonth(); } else if (touchesDiff >= 10) { if (app.rtl) p.nextMonth(); else p.prevMonth(); } else { if (app.rtl) p.prevMonth(); else p.nextMonth(); } } else { if (percentage <= -0.5) { if (app.rtl) p.prevMonth(); else p.nextMonth(); } else if (percentage >= 0.5) { if (app.rtl) p.nextMonth(); else p.prevMonth(); } else { p.resetMonth(); } } // Allow click setTimeout(function () { allowItemClick = true; }, 100); } function handleDayClick(e) { if (!allowItemClick) return; var day = $(e.target).parents('.picker-calendar-day'); if (day.length === 0 && $(e.target).hasClass('picker-calendar-day')) { day = $(e.target); } if (day.length === 0) return; if (day.hasClass('picker-calendar-day-disabled')) return; if (!p.params.rangePicker) { if (day.hasClass('picker-calendar-day-next')) p.nextMonth(); if (day.hasClass('picker-calendar-day-prev')) p.prevMonth(); } var dateYear = day.attr('data-year'); var dateMonth = day.attr('data-month'); var dateDay = day.attr('data-day'); if (p.params.onDayClick) { p.params.onDayClick(p, day[0], dateYear, dateMonth, dateDay); } if (!day.hasClass('picker-calendar-day-selected') || p.params.multiple || p.params.rangePicker) { p.addValue(new Date(dateYear, dateMonth, dateDay, 0, 0, 0)); } if (p.params.closeOnSelect) { if (p.params.rangePicker && p.value.length === 2 || !p.params.rangePicker) p.close(); } } p.container.find('.picker-calendar-prev-month').on('click', p.prevMonth); p.container.find('.picker-calendar-next-month').on('click', p.nextMonth); p.container.find('.picker-calendar-prev-year').on('click', p.prevYear); p.container.find('.picker-calendar-next-year').on('click', p.nextYear); p.wrapper.on('click', handleDayClick); var passiveListener = app.touchEvents.start === 'touchstart' && app.support.passiveListener ? {passive: true, capture: false} : false; var activeListener = app.support.passiveListener ? {passive: false, capture: false} : false; if (p.params.touchMove) { p.wrapper.on(app.touchEvents.start, handleTouchStart, passiveListener); p.wrapper.on(app.touchEvents.move, handleTouchMove, activeListener); p.wrapper.on(app.touchEvents.end, handleTouchEnd, passiveListener); } p.container[0].f7DestroyCalendarEvents = function () { p.container.find('.picker-calendar-prev-month').off('click', p.prevMonth); p.container.find('.picker-calendar-next-month').off('click', p.nextMonth); p.container.find('.picker-calendar-prev-year').off('click', p.prevYear); p.container.find('.picker-calendar-next-year').off('click', p.nextYear); p.wrapper.off('click', handleDayClick); if (p.params.touchMove) { p.wrapper.off(app.touchEvents.start, handleTouchStart, passiveListener); p.wrapper.off(app.touchEvents.move, handleTouchMove, activeListener); p.wrapper.off(app.touchEvents.end, handleTouchEnd, passiveListener); } }; }; p.destroyCalendarEvents = function (colContainer) { if ('f7DestroyCalendarEvents' in p.container[0]) p.container[0].f7DestroyCalendarEvents(); }; // Scan Dates Range p.dateInRange = function (dayDate, range) { var match = false; var i; if (!range) return false; if (Array.isArray(range)) { for (i = 0; i < range.length; i ++) { if (range[i].from || range[i].to) { if (range[i].from && range[i].to) { if ((dayDate <= new Date(range[i].to).getTime()) && (dayDate >= new Date(range[i].from).getTime())) { match = true; } } else if (range[i].from) { if (dayDate >= new Date(range[i].from).getTime()) { match = true; } } else if (range[i].to) { if (dayDate <= new Date(range[i].to).getTime()) { match = true; } } } else if (dayDate === new Date(range[i]).getTime()) { match = true; } } } else if (range.from || range.to) { if (range.from && range.to) { if ((dayDate <= new Date(range.to).getTime()) && (dayDate >= new Date(range.from).getTime())) { match = true; } } else if (range.from) { if (dayDate >= new Date(range.from).getTime()) { match = true; } } else if (range.to) { if (dayDate <= new Date(range.to).getTime()) { match = true; } } } else if (typeof range === 'function') { match = range(new Date(dayDate)); } return match; }; // Calendar Methods p.daysInMonth = function (date) { var d = new Date(date); return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate(); }; p.monthHTML = function (date, offset) { date = new Date(date); var year = date.getFullYear(), month = date.getMonth(), day = date.getDate(); if (offset === 'next') { if (month === 11) date = new Date(year + 1, 0); else date = new Date(year, month + 1, 1); } if (offset === 'prev') { if (month === 0) date = new Date(year - 1, 11); else date = new Date(year, month - 1, 1); } if (offset === 'next' || offset === 'prev') { month = date.getMonth(); year = date.getFullYear(); } var daysInPrevMonth = p.daysInMonth(new Date(date.getFullYear(), date.getMonth()).getTime() - 10 * 24 * 60 * 60 * 1000), daysInMonth = p.daysInMonth(date), firstDayOfMonthIndex = new Date(date.getFullYear(), date.getMonth()).getDay(); if (firstDayOfMonthIndex === 0) firstDayOfMonthIndex = 7; var dayDate, currentValues = [], i, j, k, rows = 6, cols = 7, monthHTML = '', dayIndex = 0 + (p.params.firstDay - 1), today = new Date().setHours(0,0,0,0), minDate = p.params.minDate ? new Date(p.params.minDate).getTime() : null, maxDate = p.params.maxDate ? new Date(p.params.maxDate).getTime() : null, disabled, hasEvent; if (p.value && p.value.length) { for (i = 0; i < p.value.length; i++) { currentValues.push(new Date(p.value[i]).setHours(0,0,0,0)); } } for (i = 1; i <= rows; i++) { var rowHTML = ''; var row = i; for (j = 1; j <= cols; j++) { var col = j; dayIndex ++; var dayNumber = dayIndex - firstDayOfMonthIndex; var weekDayIndex = (col - 1 + p.params.firstDay > 6) ? (col - 1 - 7 + p.params.firstDay) : (col - 1 + p.params.firstDay); var addClass = ''; if (dayNumber < 0) { dayNumber = daysInPrevMonth + dayNumber + 1; addClass += ' picker-calendar-day-prev'; dayDate = new Date(month - 1 < 0 ? year - 1 : year, month - 1 < 0 ? 11 : month - 1, dayNumber).getTime(); } else { dayNumber = dayNumber + 1; if (dayNumber > daysInMonth) { dayNumber = dayNumber - daysInMonth; addClass += ' picker-calendar-day-next'; dayDate = new Date(month + 1 > 11 ? year + 1 : year, month + 1 > 11 ? 0 : month + 1, dayNumber).getTime(); } else { dayDate = new Date(year, month, dayNumber).getTime(); } } // Today if (dayDate === today) addClass += ' picker-calendar-day-today'; // Selected if (p.params.rangePicker && currentValues.length === 2) { if (dayDate >= currentValues[0] && dayDate <= currentValues[1]) addClass += ' picker-calendar-day-selected'; } else { if (currentValues.indexOf(dayDate) >= 0) addClass += ' picker-calendar-day-selected'; } // Weekend if (p.params.weekendDays.indexOf(weekDayIndex) >= 0) { addClass += ' picker-calendar-day-weekend'; } // Has Events hasEvent = false; if (p.params.events) { if (p.dateInRange(dayDate, p.params.events)) { hasEvent = true; } } if (hasEvent) { addClass += ' picker-calendar-day-has-events'; } // Custom Ranges if (p.params.rangesClasses) { for (k = 0; k < p.params.rangesClasses.length; k++) { if (p.dateInRange(dayDate, p.params.rangesClasses[k].range)) { addClass += ' ' + p.params.rangesClasses[k].cssClass; } } } // Disabled disabled = false; if ((minDate && dayDate < minDate) || (maxDate && dayDate > maxDate)) { disabled = true; } if (p.params.disabled) { if (p.dateInRange(dayDate, p.params.disabled)) { disabled = true; } } if (disabled) { addClass += ' picker-calendar-day-disabled'; } dayDate = new Date(dayDate); var dayYear = dayDate.getFullYear(); var dayMonth = dayDate.getMonth(); rowHTML += '<div data-year="' + dayYear + '" data-month="' + dayMonth + '" data-day="' + dayNumber + '" class="picker-calendar-day' + (addClass) + '" data-date="' + (dayYear + '-' + dayMonth + '-' + dayNumber) + '"><span>'+dayNumber+'</span></div>'; } monthHTML += '<div class="picker-calendar-row">' + rowHTML + '</div>'; } monthHTML = '<div class="picker-calendar-month" data-year="' + year + '" data-month="' + month + '">' + monthHTML + '</div>'; return monthHTML; }; p.animating = false; p.updateCurrentMonthYear = function (dir) { if (typeof dir === 'undefined') { p.currentMonth = parseInt(p.months.eq(1).attr('data-month'), 10); p.currentYear = parseInt(p.months.eq(1).attr('data-year'), 10); } else { p.currentMonth = parseInt(p.months.eq(dir === 'next' ? (p.months.length - 1) : 0).attr('data-month'), 10); p.currentYear = parseInt(p.months.eq(dir === 'next' ? (p.months.length - 1) : 0).attr('data-year'), 10); } p.container.find('.current-month-value').text(p.params.monthNames[p.currentMonth]); p.container.find('.current-year-value').text(p.currentYear); }; p.onMonthChangeStart = function (dir) { p.updateCurrentMonthYear(dir); p.months.removeClass('picker-calendar-month-current picker-calendar-month-prev picker-calendar-month-next'); var currentIndex = dir === 'next' ? p.months.length - 1 : 0; p.months.eq(currentIndex).addClass('picker-calendar-month-current'); p.months.eq(dir === 'next' ? currentIndex - 1 : currentIndex + 1).addClass(dir === 'next' ? 'picker-calendar-month-prev' : 'picker-calendar-month-next'); if (p.params.onMonthYearChangeStart) { p.params.onMonthYearChangeStart(p, p.currentYear, p.currentMonth); } }; p.onMonthChangeEnd = function (dir, rebuildBoth) { p.animating = false; var nextMonthHTML, prevMonthHTML, newMonthHTML; p.wrapper.find('.picker-calendar-month:not(.picker-calendar-month-prev):not(.picker-calendar-month-current):not(.picker-calendar-month-next)').remove(); if (typeof dir === 'undefined') { dir = 'next'; rebuildBoth = true; } if (!rebuildBoth) { newMonthHTML = p.monthHTML(new Date(p.currentYear, p.currentMonth), dir); } else { p.wrapper.find('.picker-calendar-month-next, .picker-calendar-month-prev').remove(); prevMonthHTML = p.monthHTML(new Date(p.currentYear, p.currentMonth), 'prev'); nextMonthHTML = p.monthHTML(new Date(p.currentYear, p.currentMonth), 'next'); } if (dir === 'next' || rebuildBoth) { p.wrapper.append(newMonthHTML || nextMonthHTML); } if (dir === 'prev' || rebuildBoth) { p.wrapper.prepend(newMonthHTML || prevMonthHTML); } p.months = p.wrapper.find('.picker-calendar-month'); p.setMonthsTranslate(p.monthsTranslate); if (p.params.onMonthAdd) { p.params.onMonthAdd(p, dir === 'next' ? p.months.eq(p.months.length - 1)[0] : p.months.eq(0)[0]); } if (p.params.onMonthYearChangeEnd) { p.params.onMonthYearChangeEnd(p, p.currentYear, p.currentMonth); } }; p.setMonthsTranslate = function (translate) { translate = translate || p.monthsTranslate || 0; if (typeof p.monthsTranslate === 'undefined') p.monthsTranslate = translate; p.months.removeClass('picker-calendar-month-current picker-calendar-month-prev picker-calendar-month-next'); var prevMonthTranslate = -(translate + 1) * 100 * inverter; var currentMonthTranslate = -translate * 100 * inverter; var nextMonthTranslate = -(translate - 1) * 100 * inverter; p.months.eq(0).transform('translate3d(' + (p.isH ? prevMonthTranslate : 0) + '%, ' + (p.isH ? 0 : prevMonthTranslate) + '%, 0)').addClass('picker-calendar-month-prev'); p.months.eq(1).transform('translate3d(' + (p.isH ? currentMonthTranslate : 0) + '%, ' + (p.isH ? 0 : currentMonthTranslate) + '%, 0)').addClass('picker-calendar-month-current'); p.months.eq(2).transform('translate3d(' + (p.isH ? nextMonthTranslate : 0) + '%, ' + (p.isH ? 0 : nextMonthTranslate) + '%, 0)').addClass('picker-calendar-month-next'); }; p.nextMonth = function (transition) { if (typeof transition === 'undefined' || typeof transition === 'object') { transition = ''; if (!p.params.animate) transition = 0; } var nextMonth = parseInt(p.months.eq(p.months.length - 1).attr('data-month'), 10); var nextYear = parseInt(p.months.eq(p.months.length - 1).attr('data-year'), 10); var nextDate = new Date(nextYear, nextMonth); var nextDateTime = nextDate.getTime(); var transitionEndCallback = p.animating ? false : true; if (p.params.maxDate) { if (nextDateTime > new Date(p.params.maxDate).getTime()) { return p.resetMonth(); } } p.monthsTranslate --; if (nextMonth === p.currentMonth) { var nextMonthTranslate = -(p.monthsTranslate) * 100 * inverter; var nextMonthHTML = $(p.monthHTML(nextDateTime, 'next')).transform('translate3d(' + (p.isH ? nextMonthTranslate : 0) + '%, ' + (p.isH ? 0 : nextMonthTranslate) + '%, 0)').addClass('picker-calendar-month-next'); p.wrapper.append(nextMonthHTML[0]); p.months = p.wrapper.find('.picker-calendar-month'); if (p.params.onMonthAdd) { p.params.onMonthAdd(p, p.months.eq(p.months.length - 1)[0]); } } p.animating = true; p.onMonthChangeStart('next'); var translate = (p.monthsTranslate * 100) * inverter; p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? translate : 0) + '%, ' + (p.isH ? 0 : translate) + '%, 0)'); if (transitionEndCallback) { p.wrapper.transitionEnd(function () { p.onMonthChangeEnd('next'); }); } if (!p.params.animate) { p.onMonthChangeEnd('next'); } }; p.prevMonth = function (transition) { if (typeof transition === 'undefined' || typeof transition === 'object') { transition = ''; if (!p.params.animate) transition = 0; } var prevMonth = parseInt(p.months.eq(0).attr('data-month'), 10); var prevYear = parseInt(p.months.eq(0).attr('data-year'), 10); var prevDate = new Date(prevYear, prevMonth + 1, -1); var prevDateTime = prevDate.getTime(); var transitionEndCallback = p.animating ? false : true; if (p.params.minDate) { if (prevDateTime < new Date(p.params.minDate).getTime()) { return p.resetMonth(); } } p.monthsTranslate ++; if (prevMonth === p.currentMonth) { var prevMonthTranslate = -(p.monthsTranslate) * 100 * inverter; var prevMonthHTML = $(p.monthHTML(prevDateTime, 'prev')).transform('translate3d(' + (p.isH ? prevMonthTranslate : 0) + '%, ' + (p.isH ? 0 : prevMonthTranslate) + '%, 0)').addClass('picker-calendar-month-prev'); p.wrapper.prepend(prevMonthHTML[0]); p.months = p.wrapper.find('.picker-calendar-month'); if (p.params.onMonthAdd) { p.params.onMonthAdd(p, p.months.eq(0)[0]); } } p.animating = true; p.onMonthChangeStart('prev'); var translate = (p.monthsTranslate * 100) * inverter; p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? translate : 0) + '%, ' + (p.isH ? 0 : translate) + '%, 0)'); if (transitionEndCallback) { p.wrapper.transitionEnd(function () { p.onMonthChangeEnd('prev'); }); } if (!p.params.animate) { p.onMonthChangeEnd('prev'); } }; p.resetMonth = function (transition) { if (typeof transition === 'undefined') transition = ''; var translate = (p.monthsTranslate * 100) * inverter; p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? translate : 0) + '%, ' + (p.isH ? 0 : translate) + '%, 0)'); }; p.setYearMonth = function (year, month, transition) { if (typeof year === 'undefined') year = p.currentYear; if (typeof month === 'undefined') month = p.currentMonth; if (typeof transition === 'undefined' || typeof transition === 'object') { transition = ''; if (!p.params.animate) transition = 0; } var targetDate; if (year < p.currentYear) { targetDate = new Date(year, month + 1, -1).getTime(); } else { targetDate = new Date(year, month).getTime(); } if (p.params.maxDate && targetDate > new Date(p.params.maxDate).getTime()) { return false; } if (p.params.minDate && targetDate < new Date(p.params.minDate).getTime()) { return false; } var currentDate = new Date(p.currentYear, p.currentMonth).getTime(); var dir = targetDate > currentDate ? 'next' : 'prev'; var newMonthHTML = p.monthHTML(new Date(year, month)); p.monthsTranslate = p.monthsTranslate || 0; var prevTranslate = p.monthsTranslate; var monthTranslate, wrapperTranslate; var transitionEndCallback = p.animating ? false : true; if (targetDate > currentDate) { // To next p.monthsTranslate --; if (!p.animating) p.months.eq(p.months.length - 1).remove(); p.wrapper.append(newMonthHTML); p.months = p.wrapper.find('.picker-calendar-month'); monthTranslate = -(prevTranslate - 1) * 100 * inverter; p.months.eq(p.months.length - 1).transform('translate3d(' + (p.isH ? monthTranslate : 0) + '%, ' + (p.isH ? 0 : monthTranslate) + '%, 0)').addClass('picker-calendar-month-next'); } else { // To prev p.monthsTranslate ++; if (!p.animating) p.months.eq(0).remove(); p.wrapper.prepend(newMonthHTML); p.months = p.wrapper.find('.picker-calendar-month'); monthTranslate = -(prevTranslate + 1) * 100 * inverter; p.months.eq(0).transform('translate3d(' + (p.isH ? monthTranslate : 0) + '%, ' + (p.isH ? 0 : monthTranslate) + '%, 0)').addClass('picker-calendar-month-prev'); } if (p.params.onMonthAdd) { p.params.onMonthAdd(p, dir === 'next' ? p.months.eq(p.months.length - 1)[0] : p.months.eq(0)[0]); } p.animating = true; p.onMonthChangeStart(dir); wrapperTranslate = (p.monthsTranslate * 100) * inverter; p.wrapper.transition(transition).transform('translate3d(' + (p.isH ? wrapperTranslate : 0) + '%, ' + (p.isH ? 0 : wrapperTranslate) + '%, 0)'); if (transitionEndCallback) { p.wrapper.transitionEnd(function () { p.onMonthChangeEnd(dir, true); }); } if (!p.params.animate) { p.onMonthChangeEnd(dir); } }; p.nextYear = function () { p.setYearMonth(p.currentYear + 1); }; p.prevYear = function () { p.setYearMonth(p.currentYear - 1); }; // HTML Layout p.layout = function () { var pickerHTML = ''; var pickerClass = ''; var i; var layoutDate = p.value && p.value.length ? p.value[0] : new Date().setHours(0,0,0,0); var prevMonthHTML = p.monthHTML(layoutDate, 'prev'); var currentMonthHTML = p.monthHTML(layoutDate); var nextMonthHTML = p.monthHTML(layoutDate, 'next'); var monthsHTML = '<div class="picker-calendar-months"><div class="picker-calendar-months-wrapper">' + (prevMonthHTML + currentMonthHTML + nextMonthHTML) + '</div></div>'; // Week days header var weekHeaderHTML = ''; if (p.params.weekHeader) { for (i = 0; i < 7; i++) { var weekDayIndex = (i + p.params.firstDay > 6) ? (i - 7 + p.params.firstDay) : (i + p.params.firstDay); var dayName = p.params.dayNamesShort[weekDayIndex]; weekHeaderHTML += '<div class="picker-calendar-week-day ' + ((p.params.weekendDays.indexOf(weekDayIndex) >= 0) ? 'picker-calendar-week-day-weekend' : '') + '"> ' + dayName + '</div>'; } weekHeaderHTML = '<div class="picker-calendar-week-days">' + weekHeaderHTML + '</div>'; } pickerClass = 'picker-modal picker-calendar' + (p.params.rangePicker ? ' picker-calendar-range' : '') + (p.params.cssClass ? ' ' + p.params.cssClass : ''); var toolbarHTML = p.params.toolbar ? p.params.toolbarTemplate.replace(/{{closeText}}/g, p.params.toolbarCloseText) : ''; if (p.params.toolbar) { toolbarHTML = p.params.toolbarTemplate .replace(/{{closeText}}/g, p.params.toolbarCloseText) .replace(/{{monthPicker}}/g, (p.params.monthPicker ? p.params.monthPickerTemplate : '')) .replace(/{{yearPicker}}/g, (p.params.yearPicker ? p.params.yearPickerTemplate : '')); } var headerHTML = p.params.header ? p.params.headerTemplate.replace(/{{closeText}}/g, p.params.toolbarCloseText).replace(/{{placeholder}}/g, p.params.headerPlaceholder) : ''; var footerHTML = p.params.footer ? p.params.footerTemplate.replace(/{{closeText}}/g, p.params.toolbarCloseText) : ''; pickerHTML = '<div class="' + (pickerClass) + '">' + headerHTML + footerHTML + toolbarHTML + '<div class="picker-modal-inner">' + weekHeaderHTML + monthsHTML + '</div>' + '</div>'; p.pickerHTML = pickerHTML; }; // Input Events function openOnInput(e) { e.preventDefault(); if (p.opened) return; p.open(); if (p.params.scrollToInput && !isPopover() && !app.params.material) { var pageContent = p.input.parents('.page-content'); if (pageContent.length === 0) return; var paddingTop = parseInt(pageContent.css('padding-top'), 10), paddingBottom = parseInt(pageContent.css('padding-bottom'), 10), pageHeight = pageContent[0].offsetHeight - paddingTop - p.container.height(), pageScrollHeight = pageContent[0].scrollHeight - paddingTop - p.container.height(), newPaddingBottom; var inputTop = p.input.offset().top - paddingTop + p.input[0].offsetHeight; if (inputTop > pageHeight) { var scrollTop = pageContent.scrollTop() + inputTop - pageHeight; if (scrollTop + pageHeight > pageScrollHeight) { newPaddingBottom = scrollTop + pageHeight - pageScrollHeight + paddingBottom; if (pageHeight === pageScrollHeight) { newPaddingBottom = p.container.height(); } pageContent.css({'padding-bottom': (newPaddingBottom) + 'px'}); } pageContent.scrollTop(scrollTop, 300); } } } function closeOnHTMLClick(e) { if (inPopover()) return; if (p.input && p.input.length > 0) { if (e.target !== p.input[0] && $(e.target).parents('.picker-modal').length === 0) p.close(); } else { if ($(e.target).parents('.picker-modal').length === 0) p.close(); } } if (p.params.input) { p.input = $(p.params.input); if (p.input.length > 0) { if (p.params.inputReadOnly) p.input.prop('readOnly', true); if (!p.inline) { p.input.on('click', openOnInput); } if (p.params.inputReadOnly) { p.input.on('focus mousedown', function (e) { e.preventDefault(); }); } } } if (!p.inline && p.params.closeByOutsideClick) $('html').on('click', closeOnHTMLClick); // Open function onPickerClose() { p.opened = false; if (p.input && p.input.length > 0) { p.input.parents('.page-content').css({'padding-bottom': ''}); if (app.params.material) p.input.trigger('blur'); } if (p.params.onClose) p.params.onClose(p); // Destroy events p.destroyCalendarEvents(); } p.opened = false; p.open = function () { var toPopover = isPopover(); var updateValue = false; if (!p.opened) { // Set date value if (!p.value) { if (p.params.value) { p.value = p.params.value; updateValue = true; } } // Layout p.layout(); // Append if (toPopover) { p.pickerHTML = '<div class="popover popover-picker-calendar"><div class="popover-inner">' + p.pickerHTML + '</div></div>'; p.popover = app.popover(p.pickerHTML, p.params.input, true); p.container = $(p.popover).find('.picker-modal'); $(p.popover).on('popover:close', function () { onPickerClose(); }); } else if (p.inline) { p.container = $(p.pickerHTML); p.container.addClass('picker-modal-inline'); $(p.params.container).append(p.container); } else { p.container = $(app.pickerModal(p.pickerHTML)); $(p.container) .on('picker:close', function () { onPickerClose(); }); } // Store calendar instance p.container[0].f7Calendar = p; p.wrapper = p.container.find('.picker-calendar-months-wrapper'); // Months p.months = p.wrapper.find('.picker-calendar-month'); // Update current month and year p.updateCurrentMonthYear(); // Set initial translate p.monthsTranslate = 0; p.setMonthsTranslate(); // Init events p.initCalendarEvents(); // Update input value if (updateValue) p.updateValue(); else if (app.params.material && p.value) p.updateValue(true); // Material Focus if (p.input && p.input.length > 0 && app.params.material) { p.input.trigger('focus'); } } // Set flag p.opened = true; p.initialized = true; if (p.params.onMonthAdd) { p.months.each(function () { p.params.onMonthAdd(p, this); }); } if (p.params.onOpen) p.params.onOpen(p); }; // Close p.close = function () { if (!p.opened || p.inline) return; if (inPopover()) { app.closeModal(p.popover); return; } else { app.closeModal(p.container); return; } }; // Destroy p.destroy = function () { p.close(); if (p.params.input && p.input.length > 0) { p.input.off('click focus', openOnInput); } $('html').off('click', closeOnHTMLClick); }; if (p.inline) { p.open(); } else { if (!p.initialized && p.params.value) p.setValue(p.params.value); } return p; }; app.calendar = function (params) { return new Calendar(params); };