live-demo.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "initialize|on[A-Z]*" }]*/
  2. var templates = {
  3. input: `<div class="field">
  4. <div class="control">
  5. <input type="text" class="input date">
  6. </div>
  7. </div>`,
  8. inline: `<div class="date"></div>`,
  9. range: `<div class="field has-addons date">
  10. <div class="control">
  11. <input type="text" name="range-start" class="input">
  12. </div>
  13. <div class="control">
  14. <a class="button is-static">to</a>
  15. </div>
  16. <div class="control">
  17. <input type="text" name="range-end" class="input">
  18. </div>
  19. </div>`,
  20. };
  21. var beforeShowFns = {
  22. beforeShowDay(date) {
  23. if (date.getMonth() == new Date().getMonth()) {
  24. switch (date.getDate()) {
  25. case 4:
  26. return {
  27. content: '<span class="tooltip" data-tooltip="Example tooltip">4</span>',
  28. classes: 'has-background-info'
  29. };
  30. case 8:
  31. return false;
  32. case 12:
  33. return "has-text-success";
  34. }
  35. }
  36. },
  37. beforeShowMonth(date) {
  38. switch (date.getMonth()) {
  39. case 6:
  40. if (date.getFullYear() === new Date().getFullYear()) {
  41. return {content: '🎉'};
  42. }
  43. break;
  44. case 8:
  45. return false;
  46. }
  47. },
  48. beforeShowYear(date) {
  49. switch (date.getFullYear()) {
  50. case 2017:
  51. return false;
  52. case 2020:
  53. return {content: '<span class="tooltip is-tooltip-bottom" data-tooltip="Tooltip text">2020</span>'};
  54. }
  55. },
  56. beforeShowDecade(date) {
  57. switch (date.getFullYear()) {
  58. case 2000:
  59. return false;
  60. case 2100:
  61. return {
  62. content: '💯',
  63. classes: 'is-background-success',
  64. };
  65. }
  66. },
  67. };
  68. var buttonClass;
  69. const today = new Date().setHours(0, 0, 0, 0);
  70. const defaultOptions = {
  71. allowOneSidedRange: false,
  72. autohide: false,
  73. beforeShowDay: null,
  74. beforeShowDecade: null,
  75. beforeShowMonth: null,
  76. beforeShowYear: null,
  77. calendarWeeks: false,
  78. clearBtn: false,
  79. dateDelimiter: ',',
  80. datesDisabled: [],
  81. daysOfWeekDisabled: [],
  82. daysOfWeekHighlighted: [],
  83. defaultViewDate: today,
  84. disableTouchKeyboard: false,
  85. format: 'mm/dd/yyyy',
  86. language: 'en',
  87. maxDate: null,
  88. maxNumberOfDates: 1,
  89. maxView: 3,
  90. minDate: null,
  91. nextArrow: '»',
  92. orientation: 'auto',
  93. pickLevel: 0,
  94. prevArrow: '«',
  95. showDaysOfWeek: true,
  96. showOnClick: true,
  97. showOnFocus: true,
  98. startView: 0,
  99. title: '',
  100. todayBtn: false,
  101. todayHighlight: false,
  102. updateOnBlur: true,
  103. weekStart: 0,
  104. };
  105. const languages = {
  106. 'ar-tn': 'Arabic-Tunisia',
  107. ar: 'Arabic',
  108. az: 'Azerbaijani',
  109. bg: 'Bulgarian',
  110. bm: 'Bamanankan',
  111. bn: 'Bengali (Bangla)',
  112. br: 'Breton',
  113. bs: 'Bosnian',
  114. ca: 'Catalan',
  115. cs: 'Czech',
  116. cy: 'Welsh',
  117. da: 'Danish',
  118. de: 'German',
  119. el: 'Greek',
  120. 'en-AU': 'Australian English',
  121. 'en-CA': 'Canadian English',
  122. 'en-GB': 'British English',
  123. 'en-IE': 'Irish English',
  124. 'en-NZ': 'New Zealand English',
  125. 'en-ZA': 'South African English',
  126. eo: 'Esperanto',
  127. es: 'Spanish',
  128. et: 'Estonian',
  129. eu: 'Basque',
  130. fa: 'Persian',
  131. fi: 'Finnish',
  132. fo: 'Faroese',
  133. 'fr-CH': 'French (Switzerland)',
  134. fr: 'French',
  135. gl: 'Galician',
  136. he: 'Hebrew',
  137. hi: 'Hindi',
  138. hr: 'Croatian',
  139. hu: 'Hungarian',
  140. hy: 'Armenian',
  141. id: 'Bahasa',
  142. is: 'Icelandic',
  143. 'it-CH': 'Italian (Switzerland)',
  144. it: 'Italian',
  145. ja: 'Japanese',
  146. ka: 'Georgian',
  147. kk: 'Kazakh',
  148. km: 'Khmer',
  149. ko: 'Korean',
  150. lt: 'Lithuanian',
  151. lv: 'Latvian',
  152. me: 'Montenegrin',
  153. mk: 'Macedonian',
  154. mn: 'Mongolian',
  155. mr: 'Marathi',
  156. ms: 'Malay',
  157. 'nl-BE': 'Belgium-Dutch',
  158. nl: 'Dutch',
  159. no: 'Norwegian',
  160. oc: 'Occitan',
  161. pl: 'Polish',
  162. 'pt-BR': 'Brazilian',
  163. pt: 'Portuguese',
  164. ro: 'Romanian',
  165. ru: 'Russian',
  166. si: 'Sinhala',
  167. sk: 'Slovak',
  168. sl: 'Slovene',
  169. sq: 'Albanian',
  170. 'sr-latn': 'Serbian latin',
  171. sr: 'Serbian cyrillic',
  172. sv: 'Swedish',
  173. sw: 'Swahili',
  174. ta: 'Tamil',
  175. tg: 'Tajik',
  176. th: 'Thai',
  177. tk: 'Turkmen',
  178. tr: 'Turkish',
  179. uk: 'Ukrainian',
  180. 'uz-cyrl': 'Uzbek cyrillic',
  181. 'uz-latn': 'Uzbek latin',
  182. vi: 'Vietnamese',
  183. 'zh-CN': 'Simplified Chinese',
  184. 'zh-TW': 'Traditional Chinese',
  185. };
  186. const range = document.createRange();
  187. const sandbox = document.getElementById('sandbox');
  188. const options = document.getElementById('options');
  189. const jsonFields = ['datesDisabled'];
  190. function parseHTML(html) {
  191. return range.createContextualFragment(html);
  192. }
  193. function getBeforeShowFnSrc(name) {
  194. return beforeShowFns[name].toString();
  195. }
  196. function switchPicker(type) {
  197. const options = buttonClass ? {buttonClass} : {};
  198. if (window.demoPicker) {
  199. const currentOpts = window.demoPicker instanceof DateRangePicker
  200. ? window.demoPicker.datepickers[0]._options
  201. : window.demoPicker._options;
  202. Object.keys(defaultOptions).reduce((opts, key) => {
  203. if (key in currentOpts && String(currentOpts[key] !== String(defaultOptions[key]))) {
  204. opts[key] = currentOpts[key];
  205. }
  206. return opts;
  207. }, options);
  208. window.demoPicker.destroy();
  209. sandbox.removeChild(sandbox.firstChild);
  210. }
  211. sandbox.appendChild(parseHTML(templates[type]));
  212. const el = sandbox.querySelector('.date');
  213. window.demoPicker = type === 'range'
  214. ? new DateRangePicker(el, options)
  215. : new Datepicker(el, options);
  216. }
  217. const setOptions = function setOptions(name, value) {
  218. window.demoPicker.setOptions({[name]: value});
  219. refreshOptionForm();
  220. };
  221. const refreshOptionForm = function refreshOptionForm() {
  222. const demoPicker = window.demoPicker;
  223. const rangePicker = demoPicker instanceof DateRangePicker;
  224. const datepicker = rangePicker ? demoPicker.datepickers[0] : demoPicker;
  225. const optsForm = document.getElementById('options');
  226. const {config, _options} = datepicker;
  227. const configDefaults = {
  228. minDate: new Date(today).setFullYear(0, 0, 1),
  229. maxDate: undefined,
  230. };
  231. const formElemByName = name => optsForm.querySelector(`[name="${name}"]`);
  232. const formatDate = val => Datepicker.formatDate(val, config.format, config.lang);
  233. if (!rangePicker) {
  234. const allowOneSided = formElemByName('allowOneSidedRange');
  235. if (allowOneSided.checked) {
  236. allowOneSided.checked = false;
  237. }
  238. }
  239. Object.entries(datepicker.config).forEach(entry => {
  240. const [key, val] = entry;
  241. let el;
  242. switch (key) {
  243. case 'format':
  244. case 'weekStart':
  245. el = formElemByName(key);
  246. if (el.value || val !== defaultOptions[key]) {
  247. el.value = val;
  248. }
  249. break;
  250. case 'minDate':
  251. case 'maxDate':
  252. el = formElemByName(key);
  253. if (val === configDefaults[key]) {
  254. if (!el.value || el.value === 'null') {
  255. break;
  256. }
  257. if (_options[key] === null) {
  258. el.value = '';
  259. break;
  260. }
  261. }
  262. el.value = formatDate(val);
  263. break;
  264. case 'datesDisabled':
  265. el = formElemByName(key);
  266. if (val.length === 0) {
  267. if (!el.value || el.value === '[]') {
  268. break;
  269. }
  270. if (String(_options.datesDisabled) === '[]') {
  271. el.value = '';
  272. break;
  273. }
  274. }
  275. el.value = JSON.stringify(val.map(item => formatDate(item)));
  276. break;
  277. case 'daysOfWeekDisabled':
  278. case 'daysOfWeekHighlighted':
  279. optsForm.querySelectorAll(`[name=${key}`).forEach(chkbox => {
  280. chkbox.checked = val.includes(Number.parseInt(chkbox.value, 10));
  281. });
  282. break;
  283. case 'defaultViewDate':
  284. el = formElemByName(key);
  285. if (val === defaultOptions[key]) {
  286. if (!el.value || el.value === 'today') {
  287. break;
  288. }
  289. if (_options[key] === 'today') {
  290. el.value = '';
  291. break;
  292. }
  293. }
  294. el.value = formatDate(val);
  295. break;
  296. case 'maxView':
  297. case 'pickLevel':
  298. case 'startView':
  299. formElemByName(key).value = val;
  300. break;
  301. case 'maxNumberOfDates':
  302. el = formElemByName(key);
  303. if (rangePicker) {
  304. if (el.value) {
  305. el.value = '';
  306. }
  307. break;
  308. }
  309. if (el.value || val !== defaultOptions[key]) {
  310. el.value = val;
  311. }
  312. break;
  313. }
  314. });
  315. };
  316. const handleArrayOption = function handleArrayOption(name) {
  317. const checkedInputs = options.querySelectorAll(`input[name=${name}]:checked`);
  318. setOptions(name, Array.from(checkedInputs).map(el => Number(el.value)));
  319. };
  320. function updateOption(name, value) {
  321. switch (name) {
  322. case 'beforeShowDay':
  323. case 'beforeShowMonth':
  324. case 'beforeShowYear':
  325. case 'beforeShowDecade':
  326. setOptions(name, value ? beforeShowFns[name] : null);
  327. return;
  328. case 'daysOfWeekDisabled':
  329. case 'daysOfWeekHighlighted':
  330. handleArrayOption(name, value);
  331. return;
  332. }
  333. let newValue;
  334. if (typeof value === 'string') {
  335. switch (value) {
  336. case '':
  337. newValue = defaultOptions[name];
  338. break;
  339. case 'null':
  340. newValue = null;
  341. break;
  342. case 'false':
  343. newValue = false;
  344. break;
  345. case 'true':
  346. newValue = true;
  347. break;
  348. default:
  349. newValue = Number(value);
  350. if (isNaN(newValue)) {
  351. newValue = value;
  352. }
  353. }
  354. } else {
  355. newValue = value;
  356. }
  357. setOptions(name, newValue);
  358. }
  359. function addError(el, message) {
  360. const field = el.parentElement.parentElement;
  361. field.appendChild(parseHTML(`<p class="help is-danger">${message}</p>`));
  362. el.classList.add('is-danger');
  363. }
  364. function removeErrors(el) {
  365. const field = el.parentElement.parentElement;
  366. field.querySelectorAll('.help.is-danger').forEach((errMsg) => {
  367. field.removeChild(errMsg);
  368. });
  369. el.classList.remove('is-danger');
  370. }
  371. function onChangeType(ev) {
  372. switchPicker(ev.target.value);
  373. refreshOptionForm();
  374. }
  375. function onChnageDirection(ev) {
  376. const defaultDir = window.getComputedStyle(document.body).direction;
  377. const dir = ev.target.value;
  378. const mainElem = document.querySelector('main');
  379. if (dir !== defaultDir) {
  380. mainElem.dir = dir;
  381. } else {
  382. mainElem.removeAttribute('dir');
  383. }
  384. }
  385. function onChangeInputOption(ev) {
  386. updateOption(ev.target.name, ev.target.value);
  387. }
  388. function onChangeTextareaOption(ev) {
  389. let {value, name} = ev.target;
  390. if (jsonFields.includes(name)) {
  391. removeErrors(ev.target);
  392. if (value.length > 0) {
  393. try {
  394. value = JSON.parse(value);
  395. } catch (err) {
  396. addError(ev.target, 'Invalid JSON string');
  397. return;
  398. }
  399. }
  400. }
  401. if (name === 'datesDisabled') {
  402. if (value && !Array.isArray(value)) {
  403. addError(ev.target, 'This option must be an array');
  404. return;
  405. }
  406. }
  407. updateOption(name, value);
  408. }
  409. function onClickCheckboxOptions(ev) {
  410. ev.stopPropagation();
  411. let checkbox;
  412. let checked;
  413. if (ev.target.tagName === 'INPUT') {
  414. checkbox = ev.target;
  415. checked = checkbox.checked;
  416. } else {
  417. ev.preventDefault();
  418. checkbox = ev.currentTarget.querySelector('input');
  419. checked = checkbox.checked = !checkbox.checked;
  420. }
  421. const value = checkbox.value === 'true' ? checked : checkbox.value;
  422. updateOption(checkbox.name, value);
  423. }
  424. function initialize() {
  425. // load languages
  426. const selectElem = options.querySelector('select[name=language]');
  427. Object.keys(languages).forEach((lang) => {
  428. document.body.appendChild(parseHTML(`<script src="../dist/js/locales/${lang}.js"></script>`));
  429. selectElem.appendChild(parseHTML(`<option value="${lang}">${lang} – ${languages[lang]}</option>`));
  430. });
  431. document.querySelector('.toggle-btn').addEventListener('click', () => {
  432. document.body.classList.toggle('open');
  433. });
  434. document.querySelectorAll('.code-wrap pre').forEach((el) => {
  435. el.textContent = getBeforeShowFnSrc(el.id.replace('code-', ''));
  436. });
  437. // collapsibles
  438. document.querySelectorAll('.collapse-button').forEach((el) => {
  439. el.addEventListener('click', () => {
  440. const target = document.getElementById(el.dataset.target);
  441. el.classList.toggle('is-active');
  442. target.classList.toggle('is-active');
  443. });
  444. });
  445. }