{"version":3,"file":"phoenix.js","sources":["../../../src/js/utils.js","../../../src/js/theme/node.js","../../../src/js/theme/bulk-select.js","../../../src/js/theme/charts/echarts/echarts-utils.js","../../../src/js/theme/dropzone.js","../../../src/js/theme/googleMap.js","../../../src/js/theme/theme-control.js","../../../src/js/theme/mapbox.js","../../../src/js/theme/flight-map.js","../../../src/js/theme/mapbox-cluster.js","../../../src/js/phoenix.js"],"sourcesContent":["/* -------------------------------------------------------------------------- */\r\n/* Utils */\r\n/* -------------------------------------------------------------------------- */\r\nexport const docReady = fn => {\r\n // see if DOM is already available\r\n if (document.readyState === 'loading') {\r\n document.addEventListener('DOMContentLoaded', fn);\r\n } else {\r\n setTimeout(fn, 1);\r\n }\r\n};\r\n\r\nexport const toggleColor = (lightColor, darkColor) => {\r\n const currentMode = getItemFromStore('phoenixTheme');\r\n const mode = currentMode === 'auto' ? getSystemTheme() : currentMode;\r\n return mode === 'light' ? lightColor : darkColor;\r\n};\r\n\r\nexport const resize = fn => window.addEventListener('resize', fn);\r\n\r\nexport const isIterableArray = array => Array.isArray(array) && !!array.length;\r\n\r\nexport const camelize = str => {\r\n const text = str.replace(/[-_\\s.]+(.)?/g, (_, c) =>\r\n c ? c.toUpperCase() : ''\r\n );\r\n return `${text.substr(0, 1).toLowerCase()}${text.substr(1)}`;\r\n};\r\n\r\nexport const getData = (el, data) => {\r\n try {\r\n return JSON.parse(el.dataset[camelize(data)]);\r\n } catch (e) {\r\n return el.dataset[camelize(data)];\r\n }\r\n};\r\n\r\n/* ----------------------------- Colors function ---------------------------- */\r\n\r\nexport const hexToRgb = hexValue => {\r\n let hex;\r\n hexValue.indexOf('#') === 0\r\n ? (hex = hexValue.substring(1))\r\n : (hex = hexValue);\r\n // Expand shorthand form (e.g. \"03F\") to full form (e.g. \"0033FF\")\r\n const shorthandRegex = /^#?([a-f\\d])([a-f\\d])([a-f\\d])$/i;\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(\r\n hex.replace(shorthandRegex, (m, r, g, b) => r + r + g + g + b + b)\r\n );\r\n return result\r\n ? [\r\n parseInt(result[1], 16),\r\n parseInt(result[2], 16),\r\n parseInt(result[3], 16)\r\n ]\r\n : null;\r\n};\r\n\r\nexport const rgbaColor = (color = '#fff', alpha = 0.5) =>\r\n `rgba(${hexToRgb(color)}, ${alpha})`;\r\n\r\n/* --------------------------------- Colors --------------------------------- */\r\n\r\nexport const getColor = (name, dom = document.documentElement) => {\r\n return getComputedStyle(dom).getPropertyValue(`--phoenix-${name}`).trim();\r\n};\r\n\r\nexport const hasClass = (el, className) => {\r\n !el && false;\r\n return el.classList.value.includes(className);\r\n};\r\n\r\nexport const addClass = (el, className) => {\r\n el.classList.add(className);\r\n};\r\n\r\nexport const getOffset = el => {\r\n const rect = el.getBoundingClientRect();\r\n const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;\r\n const scrollTop = window.pageYOffset || document.documentElement.scrollTop;\r\n return { top: rect.top + scrollTop, left: rect.left + scrollLeft };\r\n};\r\n\r\nexport const isScrolledIntoView = el => {\r\n let top = el.offsetTop;\r\n let left = el.offsetLeft;\r\n const width = el.offsetWidth;\r\n const height = el.offsetHeight;\r\n\r\n while (el.offsetParent) {\r\n // eslint-disable-next-line no-param-reassign\r\n el = el.offsetParent;\r\n top += el.offsetTop;\r\n left += el.offsetLeft;\r\n }\r\n\r\n return {\r\n all:\r\n top >= window.pageYOffset &&\r\n left >= window.pageXOffset &&\r\n top + height <= window.pageYOffset + window.innerHeight &&\r\n left + width <= window.pageXOffset + window.innerWidth,\r\n partial:\r\n top < window.pageYOffset + window.innerHeight &&\r\n left < window.pageXOffset + window.innerWidth &&\r\n top + height > window.pageYOffset &&\r\n left + width > window.pageXOffset\r\n };\r\n};\r\n\r\nexport const breakpoints = {\r\n xs: 0,\r\n sm: 576,\r\n md: 768,\r\n lg: 992,\r\n xl: 1200,\r\n xxl: 1540\r\n};\r\n\r\nexport const getBreakpoint = el => {\r\n const classes = el && el.classList.value;\r\n let breakpoint;\r\n if (classes) {\r\n breakpoint =\r\n breakpoints[\r\n classes\r\n .split(' ')\r\n .filter(cls => cls.includes('navbar-expand-'))\r\n .pop()\r\n .split('-')\r\n .pop()\r\n ];\r\n }\r\n return breakpoint;\r\n};\r\n\r\n/* --------------------------------- Cookie --------------------------------- */\r\n\r\nexport const setCookie = (name, value, seconds) => {\r\n const expires = window.dayjs().add(seconds, 'second').toDate();\r\n document.cookie = `${name}=${value};expires=${expires}`;\r\n};\r\n\r\nexport const getCookie = name => {\r\n const keyValue = document.cookie.match(`(^|;) ?${name}=([^;]*)(;|$)`);\r\n return keyValue ? keyValue[2] : keyValue;\r\n};\r\n\r\nexport const settings = {\r\n tinymce: {\r\n theme: 'oxide'\r\n },\r\n chart: {\r\n borderColor: 'rgba(255, 255, 255, 0.8)'\r\n }\r\n};\r\n\r\n/* -------------------------- Chart Initialization -------------------------- */\r\n\r\nexport const newChart = (chart, config) => {\r\n const ctx = chart.getContext('2d');\r\n return new window.Chart(ctx, config);\r\n};\r\n\r\n/* ---------------------------------- Store --------------------------------- */\r\n\r\nexport const getItemFromStore = (key, defaultValue, store = localStorage) => {\r\n try {\r\n return JSON.parse(store.getItem(key)) || defaultValue;\r\n } catch {\r\n return store.getItem(key) || defaultValue;\r\n }\r\n};\r\n\r\nexport const setItemToStore = (key, payload, store = localStorage) =>\r\n store.setItem(key, payload);\r\nexport const getStoreSpace = (store = localStorage) =>\r\n parseFloat(\r\n (\r\n escape(encodeURIComponent(JSON.stringify(store))).length /\r\n (1024 * 1024)\r\n ).toFixed(2)\r\n );\r\n\r\n/* get Dates between */\r\n\r\nexport const getDates = (\r\n startDate,\r\n endDate,\r\n interval = 1000 * 60 * 60 * 24\r\n) => {\r\n const duration = endDate - startDate;\r\n const steps = duration / interval;\r\n return Array.from(\r\n { length: steps + 1 },\r\n (v, i) => new Date(startDate.valueOf() + interval * i)\r\n );\r\n};\r\n\r\nexport const getPastDates = duration => {\r\n let days;\r\n\r\n switch (duration) {\r\n case 'week':\r\n days = 7;\r\n break;\r\n case 'month':\r\n days = 30;\r\n break;\r\n case 'year':\r\n days = 365;\r\n break;\r\n\r\n default:\r\n days = duration;\r\n }\r\n\r\n const date = new Date();\r\n const endDate = date;\r\n const startDate = new Date(new Date().setDate(date.getDate() - (days - 1)));\r\n return getDates(startDate, endDate);\r\n};\r\n\r\n/* Get Random Number */\r\nexport const getRandomNumber = (min, max) => {\r\n return Math.floor(Math.random() * (max - min) + min);\r\n};\r\n\r\nexport const getSystemTheme = () =>\r\n window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\r\n\r\n// export const handleThemeDropdownIcon = value => {\r\n// document.querySelectorAll('[data-theme-dropdown-toggle-icon]').forEach(el => {\r\n// const theme = getData(el, 'theme-dropdown-toggle-icon');\r\n\r\n// if (value === theme) {\r\n// el.classList.remove('d-none');\r\n// } else {\r\n// el.classList.add('d-none');\r\n// }\r\n// });\r\n// };\r\n// handleThemeDropdownIcon(getItemFromStore('phoenixTheme'));\r\n\r\nexport default {\r\n docReady,\r\n toggleColor,\r\n resize,\r\n isIterableArray,\r\n camelize,\r\n getData,\r\n hasClass,\r\n addClass,\r\n hexToRgb,\r\n rgbaColor,\r\n getColor,\r\n breakpoints,\r\n // getGrays,\r\n getOffset,\r\n isScrolledIntoView,\r\n getBreakpoint,\r\n setCookie,\r\n getCookie,\r\n newChart,\r\n settings,\r\n getItemFromStore,\r\n setItemToStore,\r\n getStoreSpace,\r\n getDates,\r\n getPastDates,\r\n getRandomNumber,\r\n getSystemTheme\r\n // handleThemeDropdownIcon\r\n};\r\n","/* eslint-disable no-unused-expressions */\r\n/*-----------------------------------------------\r\n| DomNode\r\n-----------------------------------------------*/\r\nclass DomNode {\r\n constructor(node) {\r\n this.node = node;\r\n }\r\n\r\n addClass(className) {\r\n this.isValidNode() && this.node.classList.add(className);\r\n }\r\n\r\n removeClass(className) {\r\n this.isValidNode() && this.node.classList.remove(className);\r\n }\r\n\r\n toggleClass(className) {\r\n this.isValidNode() && this.node.classList.toggle(className);\r\n }\r\n\r\n hasClass(className) {\r\n this.isValidNode() && this.node.classList.contains(className);\r\n }\r\n\r\n data(key) {\r\n if (this.isValidNode()) {\r\n try {\r\n return JSON.parse(this.node.dataset[this.camelize(key)]);\r\n } catch (e) {\r\n return this.node.dataset[this.camelize(key)];\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n attr(name) {\r\n return this.isValidNode() && this.node[name];\r\n }\r\n\r\n setAttribute(name, value) {\r\n this.isValidNode() && this.node.setAttribute(name, value);\r\n }\r\n\r\n removeAttribute(name) {\r\n this.isValidNode() && this.node.removeAttribute(name);\r\n }\r\n\r\n setProp(name, value) {\r\n this.isValidNode() && (this.node[name] = value);\r\n }\r\n\r\n on(event, cb) {\r\n this.isValidNode() && this.node.addEventListener(event, cb);\r\n }\r\n\r\n isValidNode() {\r\n return !!this.node;\r\n }\r\n\r\n // eslint-disable-next-line class-methods-use-this\r\n camelize(str) {\r\n const text = str.replace(/[-_\\s.]+(.)?/g, (_, c) =>\r\n c ? c.toUpperCase() : ''\r\n );\r\n return `${text.substr(0, 1).toLowerCase()}${text.substr(1)}`;\r\n }\r\n}\r\n\r\nexport default DomNode;\r\n","import { getData } from '../utils';\r\nimport DomNode from './node';\r\n\r\n/*-----------------------------------------------\r\n| Bulk Select\r\n-----------------------------------------------*/\r\n\r\nconst elementMap = new Map();\r\n\r\nexport class BulkSelect {\r\n constructor(element, option) {\r\n this.element = element;\r\n this.option = {\r\n displayNoneClassName: 'd-none',\r\n ...option\r\n };\r\n elementMap.set(this.element, this);\r\n }\r\n\r\n // Static\r\n static getInstance(element) {\r\n if (elementMap.has(element)) {\r\n return elementMap.get(element);\r\n }\r\n return null;\r\n }\r\n\r\n init() {\r\n this.attachNodes();\r\n this.clickBulkCheckbox();\r\n this.clickRowCheckbox();\r\n }\r\n\r\n getSelectedRows() {\r\n return Array.from(this.bulkSelectRows)\r\n .filter(row => row.checked)\r\n .map(row => getData(row, 'bulk-select-row'));\r\n }\r\n\r\n attachNodes() {\r\n const { body, actions, replacedElement } = getData(\r\n this.element,\r\n 'bulk-select'\r\n );\r\n\r\n this.actions = new DomNode(document.getElementById(actions));\r\n this.replacedElement = new DomNode(\r\n document.getElementById(replacedElement)\r\n );\r\n this.bulkSelectRows = document\r\n .getElementById(body)\r\n .querySelectorAll('[data-bulk-select-row]');\r\n }\r\n\r\n attachRowNodes(elms) {\r\n this.bulkSelectRows = elms;\r\n }\r\n\r\n clickBulkCheckbox() {\r\n // Handle click event in bulk checkbox\r\n this.element.addEventListener('click', () => {\r\n if (this.element.indeterminate === 'indeterminate') {\r\n this.actions.addClass(this.option.displayNoneClassName);\r\n this.replacedElement.removeClass(this.option.displayNoneClassName);\r\n\r\n this.removeBulkCheck();\r\n\r\n this.bulkSelectRows.forEach(el => {\r\n const rowCheck = new DomNode(el);\r\n rowCheck.checked = false;\r\n rowCheck.setAttribute('checked', false);\r\n });\r\n return;\r\n }\r\n\r\n this.toggleDisplay();\r\n this.bulkSelectRows.forEach(el => {\r\n el.checked = this.element.checked;\r\n });\r\n });\r\n }\r\n\r\n clickRowCheckbox() {\r\n // Handle click event in checkbox of each row\r\n this.bulkSelectRows.forEach(el => {\r\n const rowCheck = new DomNode(el);\r\n rowCheck.on('click', () => {\r\n if (this.element.indeterminate !== 'indeterminate') {\r\n this.element.indeterminate = true;\r\n this.element.setAttribute('indeterminate', 'indeterminate');\r\n this.element.checked = true;\r\n this.element.setAttribute('checked', true);\r\n\r\n this.actions.removeClass(this.option.displayNoneClassName);\r\n this.replacedElement.addClass(this.option.displayNoneClassName);\r\n }\r\n\r\n if ([...this.bulkSelectRows].every(element => element.checked)) {\r\n this.element.indeterminate = false;\r\n this.element.setAttribute('indeterminate', false);\r\n }\r\n\r\n if ([...this.bulkSelectRows].every(element => !element.checked)) {\r\n this.removeBulkCheck();\r\n this.toggleDisplay();\r\n }\r\n });\r\n });\r\n }\r\n\r\n removeBulkCheck() {\r\n this.element.indeterminate = false;\r\n this.element.removeAttribute('indeterminate');\r\n this.element.checked = false;\r\n this.element.setAttribute('checked', false);\r\n }\r\n\r\n toggleDisplay() {\r\n this.actions.toggleClass(this.option.displayNoneClassName);\r\n this.replacedElement.toggleClass(this.option.displayNoneClassName);\r\n }\r\n}\r\n\r\nconst bulkSelectInit = () => {\r\n const bulkSelects = document.querySelectorAll('[data-bulk-select]');\r\n\r\n if (bulkSelects.length) {\r\n bulkSelects.forEach(el => {\r\n const bulkSelect = new BulkSelect(el);\r\n bulkSelect.init();\r\n });\r\n }\r\n};\r\n\r\nexport default bulkSelectInit;\r\n","// import * as echarts from 'echarts';\r\nconst { merge } = window._;\r\n\r\n// form config.js\r\nexport const echartSetOption = (\r\n chart,\r\n userOptions,\r\n getDefaultOptions,\r\n responsiveOptions\r\n) => {\r\n const { breakpoints, resize } = window.phoenix.utils;\r\n const handleResize = options => {\r\n Object.keys(options).forEach(item => {\r\n if (window.innerWidth > breakpoints[item]) {\r\n chart.setOption(options[item]);\r\n }\r\n });\r\n };\r\n\r\n const themeController = document.body;\r\n // Merge user options with lodash\r\n chart.setOption(merge(getDefaultOptions(), userOptions));\r\n\r\n const navbarVerticalToggle = document.querySelector(\r\n '.navbar-vertical-toggle'\r\n );\r\n if (navbarVerticalToggle) {\r\n navbarVerticalToggle.addEventListener('navbar.vertical.toggle', () => {\r\n chart.resize();\r\n if (responsiveOptions) {\r\n handleResize(responsiveOptions);\r\n }\r\n });\r\n }\r\n\r\n resize(() => {\r\n chart.resize();\r\n if (responsiveOptions) {\r\n handleResize(responsiveOptions);\r\n }\r\n });\r\n if (responsiveOptions) {\r\n handleResize(responsiveOptions);\r\n }\r\n\r\n themeController.addEventListener(\r\n 'clickControl',\r\n ({ detail: { control } }) => {\r\n if (control === 'phoenixTheme') {\r\n chart.setOption(window._.merge(getDefaultOptions(), userOptions));\r\n }\r\n if (responsiveOptions) {\r\n handleResize(responsiveOptions);\r\n }\r\n }\r\n );\r\n};\r\n// -------------------end config.js--------------------\r\n\r\nconst echartTabs = document.querySelectorAll('[data-tab-has-echarts]');\r\nif (echartTabs) {\r\n echartTabs.forEach(tab => {\r\n tab.addEventListener('shown.bs.tab', e => {\r\n const el = e.target;\r\n const { hash } = el;\r\n const id = hash || el.dataset.bsTarget;\r\n const content = document.getElementById(id.substring(1));\r\n const chart = content?.querySelector('[data-echart-tab]');\r\n if (chart) {\r\n window.echarts.init(chart).resize();\r\n }\r\n });\r\n });\r\n}\r\n\r\nexport const tooltipFormatter = (params, dateFormatter = 'MMM DD') => {\r\n let tooltipItem = ``;\r\n params.forEach(el => {\r\n tooltipItem += `
\r\n ${\r\n window.dayjs(params[0].axisValue).isValid()\r\n ? window.dayjs(params[0].axisValue).format(dateFormatter)\r\n : params[0].axisValue\r\n }\r\n
\r\n ${tooltipItem}\r\n