123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- import {hasProperty, pushUnique} from '../lib/utils.js';
- import {dateValue} from '../lib/date.js';
- import {reFormatTokens, parseDate} from '../lib/date-format.js';
- import {parseHTML} from '../lib/dom.js';
- import defaultOptions from './defaultOptions.js';
- const {
- language: defaultLang,
- format: defaultFormat,
- weekStart: defaultWeekStart,
- } = defaultOptions;
- // Reducer function to filter out invalid day-of-week from the input
- function sanitizeDOW(dow, day) {
- return dow.length < 6 && day >= 0 && day < 7
- ? pushUnique(dow, day)
- : dow;
- }
- function calcEndOfWeek(startOfWeek) {
- return (startOfWeek + 6) % 7;
- }
- // validate input date. if invalid, fallback to the original value
- function validateDate(value, format, locale, origValue) {
- const date = parseDate(value, format, locale);
- return date !== undefined ? date : origValue;
- }
- // Validate viewId. if invalid, fallback to the original value
- function validateViewId(value, origValue, max = 3) {
- const viewId = parseInt(value, 10);
- return viewId >= 0 && viewId <= max ? viewId : origValue;
- }
- // Create Datepicker configuration to set
- export default function processOptions(options, datepicker) {
- const inOpts = Object.assign({}, options);
- const config = {};
- const locales = datepicker.constructor.locales;
- let {
- format,
- language,
- locale,
- maxDate,
- maxView,
- minDate,
- pickLevel,
- startView,
- weekStart,
- } = datepicker.config || {};
- if (inOpts.language) {
- let lang;
- if (inOpts.language !== language) {
- if (locales[inOpts.language]) {
- lang = inOpts.language;
- } else {
- // Check if langauge + region tag can fallback to the one without
- // region (e.g. fr-CA → fr)
- lang = inOpts.language.split('-')[0];
- if (locales[lang] === undefined) {
- lang = false;
- }
- }
- }
- delete inOpts.language;
- if (lang) {
- language = config.language = lang;
- // update locale as well when updating language
- const origLocale = locale || locales[defaultLang];
- // use default language's properties for the fallback
- locale = Object.assign({
- format: defaultFormat,
- weekStart: defaultWeekStart
- }, locales[defaultLang]);
- if (language !== defaultLang) {
- Object.assign(locale, locales[language]);
- }
- config.locale = locale;
- // if format and/or weekStart are the same as old locale's defaults,
- // update them to new locale's defaults
- if (format === origLocale.format) {
- format = config.format = locale.format;
- }
- if (weekStart === origLocale.weekStart) {
- weekStart = config.weekStart = locale.weekStart;
- config.weekEnd = calcEndOfWeek(locale.weekStart);
- }
- }
- }
- if (inOpts.format) {
- const hasToDisplay = typeof inOpts.format.toDisplay === 'function';
- const hasToValue = typeof inOpts.format.toValue === 'function';
- const validFormatString = reFormatTokens.test(inOpts.format);
- if ((hasToDisplay && hasToValue) || validFormatString) {
- format = config.format = inOpts.format;
- }
- delete inOpts.format;
- }
- //*** dates ***//
- // while min and maxDate for "no limit" in the options are better to be null
- // (especially when updating), the ones in the config have to be undefined
- // because null is treated as 0 (= unix epoch) when comparing with time value
- let minDt = minDate;
- let maxDt = maxDate;
- if (inOpts.minDate !== undefined) {
- minDt = inOpts.minDate === null
- ? dateValue(0, 0, 1) // set 0000-01-01 to prevent negative values for year
- : validateDate(inOpts.minDate, format, locale, minDt);
- delete inOpts.minDate;
- }
- if (inOpts.maxDate !== undefined) {
- maxDt = inOpts.maxDate === null
- ? undefined
- : validateDate(inOpts.maxDate, format, locale, maxDt);
- delete inOpts.maxDate;
- }
- if (maxDt < minDt) {
- minDate = config.minDate = maxDt;
- maxDate = config.maxDate = minDt;
- } else {
- if (minDate !== minDt) {
- minDate = config.minDate = minDt;
- }
- if (maxDate !== maxDt) {
- maxDate = config.maxDate = maxDt;
- }
- }
- if (inOpts.datesDisabled) {
- config.datesDisabled = inOpts.datesDisabled.reduce((dates, dt) => {
- const date = parseDate(dt, format, locale);
- return date !== undefined ? pushUnique(dates, date) : dates;
- }, []);
- delete inOpts.datesDisabled;
- }
- if (inOpts.defaultViewDate !== undefined) {
- const viewDate = parseDate(inOpts.defaultViewDate, format, locale);
- if (viewDate !== undefined) {
- config.defaultViewDate = viewDate;
- }
- delete inOpts.defaultViewDate;
- }
- //*** days of week ***//
- if (inOpts.weekStart !== undefined) {
- const wkStart = Number(inOpts.weekStart) % 7;
- if (!isNaN(wkStart)) {
- weekStart = config.weekStart = wkStart;
- config.weekEnd = calcEndOfWeek(wkStart);
- }
- delete inOpts.weekStart;
- }
- if (inOpts.daysOfWeekDisabled) {
- config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []);
- delete inOpts.daysOfWeekDisabled;
- }
- if (inOpts.daysOfWeekHighlighted) {
- config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []);
- delete inOpts.daysOfWeekHighlighted;
- }
- //*** multi date ***//
- if (inOpts.maxNumberOfDates !== undefined) {
- const maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10);
- if (maxNumberOfDates >= 0) {
- config.maxNumberOfDates = maxNumberOfDates;
- config.multidate = maxNumberOfDates !== 1;
- }
- delete inOpts.maxNumberOfDates;
- }
- if (inOpts.dateDelimiter) {
- config.dateDelimiter = String(inOpts.dateDelimiter);
- delete inOpts.dateDelimiter;
- }
- //*** pick level & view ***//
- let newPickLevel = pickLevel;
- if (inOpts.pickLevel !== undefined) {
- newPickLevel = validateViewId(inOpts.pickLevel, 2);
- delete inOpts.pickLevel;
- }
- if (newPickLevel !== pickLevel) {
- pickLevel = config.pickLevel = newPickLevel;
- }
- let newMaxView = maxView;
- if (inOpts.maxView !== undefined) {
- newMaxView = validateViewId(inOpts.maxView, maxView);
- delete inOpts.maxView;
- }
- // ensure max view >= pick level
- newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView;
- if (newMaxView !== maxView) {
- maxView = config.maxView = newMaxView;
- }
- let newStartView = startView;
- if (inOpts.startView !== undefined) {
- newStartView = validateViewId(inOpts.startView, newStartView);
- delete inOpts.startView;
- }
- // ensure pick level <= start view <= max view
- if (newStartView < pickLevel) {
- newStartView = pickLevel;
- } else if (newStartView > maxView) {
- newStartView = maxView;
- }
- if (newStartView !== startView) {
- config.startView = newStartView;
- }
- //*** template ***//
- if (inOpts.prevArrow) {
- const prevArrow = parseHTML(inOpts.prevArrow);
- if (prevArrow.childNodes.length > 0) {
- config.prevArrow = prevArrow.childNodes;
- }
- delete inOpts.prevArrow;
- }
- if (inOpts.nextArrow) {
- const nextArrow = parseHTML(inOpts.nextArrow);
- if (nextArrow.childNodes.length > 0) {
- config.nextArrow = nextArrow.childNodes;
- }
- delete inOpts.nextArrow;
- }
- //*** misc ***//
- if (inOpts.disableTouchKeyboard !== undefined) {
- config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard;
- delete inOpts.disableTouchKeyboard;
- }
- if (inOpts.orientation) {
- const orientation = inOpts.orientation.toLowerCase().split(/\s+/g);
- config.orientation = {
- x: orientation.find(x => (x === 'left' || x === 'right')) || 'auto',
- y: orientation.find(y => (y === 'top' || y === 'bottom')) || 'auto',
- };
- delete inOpts.orientation;
- }
- if (inOpts.todayBtnMode !== undefined) {
- switch(inOpts.todayBtnMode) {
- case 0:
- case 1:
- config.todayBtnMode = inOpts.todayBtnMode;
- }
- delete inOpts.todayBtnMode;
- }
- //*** copy the rest ***//
- Object.keys(inOpts).forEach((key) => {
- if (inOpts[key] !== undefined && hasProperty(defaultOptions, key)) {
- config[key] = inOpts[key];
- }
- });
- return config;
- }
|