UNPKG

@mezereon/bigcommerce-stencil

Version:

BigCommerce UI components for Mezereon Xperience

143 lines (120 loc) 3.45 kB
import { debounced, isArray } from '@/helpers' import Vue from 'vue' import { createBrowserHistory } from 'history' import queryString from 'qs' function isString(value) { return typeof value === 'string' || value instanceof String } const encoder = function (val, defaultEncoder, charset, type) { if (type === 'key') { return val } else if (type === 'value') { if (!isString(val)) return val return val.replace(/&/g, '%26') } } const stringifyOptions = { allowDots: true, addQueryPrefix: true, arrayFormat: 'comma', skipNulls: true, encoder } const parseOptions = { ignoreQueryPrefix: true, allowDots: true, comma: true } class QueryState { constructor() { this.history = createBrowserHistory() this.queryParam = 'q' } // Listen for changes to the current location. onChange(callback) { this.unlisten = this.history.listen((location, action) => { // console.log(action, location.pathname, location.search) // skip for PUSH action if (action === 'PUSH') return debounced(250, callback(this.parseUrl(location))) }) } parseUrl(location) { // if location is empty, then take from history location = location || this.history.location const intermediate = queryString.parse(location.search, parseOptions) // convert single value to array with one element intermediate.selections = [] if (intermediate.mz) { Object.keys(intermediate.mz).forEach((key) => { const value = intermediate.mz[key] if (value && !isArray(value)) { intermediate.mz[key] = [value] } // initialize selections that will be split and updated inside RUN_QUERY mutation intermediate.selections.push({ action: 'init', name: key, key, value, label: key }) }) } const keyword = intermediate[this.queryParam] || '' if (keyword) { // initialize selections that will be split and updated inside RUN_QUERY mutation intermediate.selections.push({ action: 'replace', name: 'Keyword', key: '_Keyword', value: keyword, label: Vue.prototype.$t('Keyword') || 'Keyword' }) } const final = { keyword, page: parseInt(intermediate.page) || 1, sort: intermediate.sort, pageSize: intermediate.size ? parseInt(intermediate.size) : undefined, filters: intermediate.mz, selections: intermediate.selections } return final } push(state) { const object = { page: state.page, sort: state.sort, size: state.pageSize, mz: state.filters } // do not push keyword field if empty if (state.keyword && state.keyword !== '') { object[this.queryParam] = state.keyword } this.history.push({ search: queryString.stringify(object, stringifyOptions) }) } // this function is called from ui-components-vue stringifyFilters(filters) { const object = { mz: filters } // copy options const options = { ...stringifyOptions } // overwrite addQueryPrefix setting options.addQueryPrefix = false return queryString.stringify(object, options) } setQueryParam(queryParam) { this.queryParam = queryParam } destroy() { this.unlisten() } } const instance = new QueryState() Vue.prototype.$queryState = instance export default instance