<script lang="ts"> import _ from 'lodash' import LocationQueryMixin from './LocationQuery.vue' function isDate(key: string, value: string): boolean { return ( ( key.toLowerCase().endsWith('date') || key.toLowerCase().endsWith('time') || key.toLowerCase().endsWith('timestamp') ) && new Date(value).toString() !== 'Invalid Date' ) } function parseValue(key: string, value: string | null): string | number | boolean | Date | undefined { value = decodeURI(value?.trim() || '') if (!value.length) { return undefined } else if (value.toLowerCase() === 'true') { return true } else if (value.toLowerCase() === 'false') { return false } else if (isDate(key, value)) { return new Date(value) } else if (!isNaN(Number(value))) { return Number(value) } else { return value } } function encodeValue(value: string | number | boolean | Date): string { if (value instanceof Date) { return value.getTime().toString() } else { return encodeURI(value.toString()) } } export default { mixins: [LocationQueryMixin], data() { return { query: this.parseQuery(window.location.href), } }, methods: { parseQuery(query: string): Record<string, string> { return query .replace(/^[^#]*#?(.*)/, (_, hash) => hash) .split('&') .reduce((acc: Record<string, any>, pair: string) => { const [key, value] = pair.split('=', 2).map((part: string) => part.trim()) if (key.length) { const v = parseValue(key, value) if (v != null) { acc[key] = v } } return acc }, {}) }, toQueryString(values: Record<string, any>) { return Object.entries(values) .filter(([_, value]) => value != null && value.toString() !== '[object Object]') .map(([key, value]) => `${key}=${encodeValue(value)}`) .join('&') }, setQuery(values: Record<string, any>) { const newQuery = this.toQueryString(values) window.location.hash = newQuery }, }, watch: { $route(newRoute: { fullPath: string }, oldRoute: { fullPath: string }) { const oldQuery = this.parseQuery(oldRoute.fullPath) const newQuery = this.parseQuery(newRoute.fullPath) // @ts-ignore if (this.isQueryChanged({oldValue: oldQuery, newValue: newQuery})) { this.query = newQuery } }, }, } </script>