UNPKG

react-hook-core

Version:
455 lines (438 loc) 13.1 kB
import { resources, StringMap } from "./core" import { clone } from "./reflect" export interface PageChange { page: number // currentPage size: number // itemsPerPage } export interface Filter { q?: string page?: number limit: number firstLimit?: number fields?: string[] sort?: string } export interface SearchResult<T> { total?: number list: T[] next?: string last?: boolean } export interface SearchService<T, S extends Filter> { keys?(): string[] search(s: S, limit?: number, offset?: number | string, fields?: string[]): Promise<SearchResult<T>> } export interface Sortable { sortField?: string sortType?: string sortTarget?: HTMLElement } export interface Pagination { initLimit?: number limit: number page?: number total?: number pages?: number showPaging?: boolean append?: boolean appendMode?: boolean appendable?: boolean } interface Searchable extends Pagination, Sortable {} export function mergeFilter<S extends Filter>(obj: S, b?: S, pageSizes?: number[], arrs?: string[] | any) { let a: any = b if (!b) { a = {} } const keys = Object.keys(obj) for (const key of keys) { const p = a[key] const v = (obj as any)[key] if (v && v !== "") { a[key] = isArray(key, p, arrs) ? v.split(",") : v } } const spage: any = obj["page"] if (!isNaN(spage)) { const page = parseInt(spage, 10) a.page = page > 1 ? page : undefined } const slimit: any = obj["limit"] if (!isNaN(slimit)) { const limit = parseInt(slimit, 10) if (pageSizes && pageSizes.length > 0) { if (pageSizes.indexOf(limit) >= 0) { a.limit = limit return a } } else { a.limit = limit > 0 ? limit : 12 } } return a } export function isArray(key: string, p: any, arrs: string[] | any): boolean { if (p) { if (Array.isArray(p)) { return true } } if (arrs) { if (Array.isArray(arrs)) { if (arrs.indexOf(key) >= 0) { return true } } else { const v = arrs[key] if (v && Array.isArray(v)) { return true } } } return false } // m is search model or an object which is parsed from url export function initFilter<S extends Filter>(m: S, com: Searchable): S { if (!isNaN(m.page as any)) { const page = parseInt(m.page as any, 10) m.page = page if (page >= 1) { com.page = page } } if (!isNaN(m.limit as any)) { const pageSize = parseInt(m.limit as any, 10) m.limit = pageSize if (pageSize > 0) { com.limit = pageSize } } if (!m.limit && com.limit) { m.limit = com.limit } if (!isNaN(m.firstLimit as any)) { const initPageSize = parseInt(m.firstLimit as any, 10) if (initPageSize > 0) { m.firstLimit = initPageSize com.initLimit = initPageSize } else { com.initLimit = com.limit } } else { com.initLimit = com.limit } const st = m.sort if (st && st.length > 0) { const ch = st.charAt(0) if (ch === "+" || ch === "-") { com.sortField = st.substring(1) com.sortType = ch } else { com.sortField = st com.sortType = "" } } return m } export function getFields(form?: HTMLFormElement, arr?: string[]): string[] | undefined { if (arr && arr.length > 0) { return arr } if (!form) { return undefined } let nodes = form.nextSibling as HTMLElement if (!nodes.querySelector) { if (!form.nextSibling) { return [] } else { nodes = form.nextSibling.nextSibling as HTMLElement } } if (!nodes.querySelector) { return undefined } const table = nodes.querySelector("table") const fields: string[] = [] if (table) { const thead = table.querySelector("thead") if (thead) { const ths = thead.querySelectorAll("th") if (ths) { const l = ths.length for (let i = 0; i < l; i++) { const th = ths[i] const field = th.getAttribute("data-field") if (field) { fields.push(field) } } } } } return fields.length > 0 ? fields : undefined } export function getPageTotal(pageSize?: number, total?: number): number { if (!pageSize || pageSize <= 0) { return 1 } else { if (!total) { total = 0 } if (total % pageSize === 0) { return Math.floor(total / pageSize) } return Math.floor(total / pageSize + 1) } } export function formatText(...args: any[]): string { let formatted = args[0] if (!formatted || formatted === "") { return "" } if (args.length > 1 && Array.isArray(args[1])) { const params = args[1] for (let i = 0; i < params.length; i++) { const regexp = new RegExp("\\{" + i + "\\}", "gi") formatted = formatted.replace(regexp, params[i]) } } else { for (let i = 1; i < args.length; i++) { const regexp = new RegExp("\\{" + (i - 1) + "\\}", "gi") formatted = formatted.replace(regexp, args[i]) } } return formatted } export function buildMessage<T>(resource: StringMap, results: T[], limit: number, page: number | undefined, total?: number): string { if (!results || results.length === 0) { return resource.msg_no_data_found } else { if (!page) { page = 1 } const fromIndex = (page - 1) * limit + 1 const toIndex = fromIndex + results.length - 1 const pageTotal = getPageTotal(limit, total) if (pageTotal > 1) { const msg2 = formatText(resource.msg_search_result_page_sequence, fromIndex, toIndex, total, page, pageTotal) return msg2 } else { const msg3 = formatText(resource.msg_search_result_sequence, fromIndex, toIndex) return msg3 } } } function removeFormatUrl(url: string): string { const startParams = url.indexOf("?") return startParams !== -1 ? url.substring(0, startParams) : url } function getPrefix(url: string): string { return url.indexOf("?") >= 0 ? "&" : "?" } export function addParametersIntoUrl<S extends Filter>(ft: S, isFirstLoad?: boolean, page?: number, fields?: string, limit?: string): void { if (!isFirstLoad) { if (!fields || fields.length === 0) { fields = resources.fields } if (!limit || limit.length === 0) { limit = resources.limit } if (page) { ;(ft as any)[resources.page] = page } const pageIndex = (ft as any)[resources.page] if (pageIndex && !isNaN(pageIndex) && pageIndex <= 1) { delete ft.page } const keys = Object.keys(ft) const currentUrl = window.location.host + window.location.pathname let url = removeFormatUrl(currentUrl) for (const key of keys) { const objValue = (ft as any)[key] if (objValue) { if (key !== fields) { if (typeof objValue === "string" || typeof objValue === "number") { if (key === limit) { if (objValue !== resources.defaultLimit) { url += getPrefix(url) + `${key}=${objValue}` } } else { if (typeof objValue === "string") { url += getPrefix(url) + `${key}=${encodeURIComponent(objValue)}` } else { url += getPrefix(url) + `${key}=${objValue}` } } } else if (typeof objValue === "object") { if (objValue instanceof Date) { url += getPrefix(url) + `${key}=${objValue.toISOString()}` } else { if (Array.isArray(objValue)) { if (objValue.length > 0) { const strs: string[] = [] for (const subValue of objValue) { if (typeof subValue === "string") { strs.push(encodeURIComponent(subValue)) } else if (typeof subValue === "number") { strs.push(subValue.toString()) } } url += getPrefix(url) + `${key}=${strs.join(",")}` } } else { const keysLvl2 = Object.keys(objValue) for (const key2 of keysLvl2) { const objValueLvl2 = objValue[key2] if (objValueLvl2) { if (objValueLvl2 instanceof Date) { url += getPrefix(url) + `${key}.${key2}=${objValueLvl2.toISOString()}` } else { if (typeof objValueLvl2 === "string") { url += getPrefix(url) + `${key}.${key2}=${encodeURIComponent(objValueLvl2)}` } else { url += getPrefix(url) + `${key}.${key2}=${objValueLvl2}` } } } } } } } } } } let p = "http://" const loc = window.location.href if (loc.length >= 8) { const ss = loc.substring(0, 8) if (ss === "https://") { p = "https://" } } window.history.replaceState({ path: currentUrl }, "", p + url) } } export interface Sort { field?: string type?: string } export function buildSort(sort?: string | null): Sort { const sortObj: Sort = {} if (sort && sort.length > 0) { const ch = sort.charAt(0) if (ch === "+" || ch === "-") { sortObj.field = sort.substring(1) sortObj.type = ch } else { sortObj.field = sort sortObj.type = "" } } return sortObj } export function setSort(sortable: Sortable, sort: string | undefined | null) { const st = buildSort(sort) sortable.sortField = st.field sortable.sortType = st.type } export function buildSortFilter<S extends Filter>(obj: S, sortable: Sortable): S { const filter: any = clone(obj) if (sortable.sortField && sortable.sortField.length > 0) { filter.sort = sortable.sortType === "-" ? "-" + sortable.sortField : sortable.sortField } else { delete filter.sort } delete filter.fields return filter } export function handleToggle(target?: HTMLElement, on?: boolean): boolean { const off = !on if (target) { if (on) { if (!target.classList.contains("on")) { target.classList.add("on") } } else { target.classList.remove("on") } } return off } export function getSortElement(target: HTMLElement): HTMLElement { return target.nodeName === "I" ? (target.parentElement as HTMLElement) : target } export function handleSort(target: HTMLElement, previousTarget?: HTMLElement, sortField?: string, sortType?: string): Sort { const type = target.getAttribute("sort-type") const field = toggleSortStyle(target) const s = sort(sortField, sortType, field, type == null ? undefined : type) if (sortField !== field) { removeSortStatus(previousTarget) } return s } export function sort(preField?: string, preSortType?: string, field?: string, sortType?: string): Sort { if (!preField || preField === "") { const s: Sort = { field, type: "+", } return s } else if (preField !== field) { const s: Sort = { field, type: !sortType ? "+" : sortType, } return s } else if (preField === field) { const type = preSortType === "+" ? "-" : "+" const s: Sort = { field, type } return s } else { return { field, type: sortType } } } export function removeSortStatus(target?: HTMLElement): void { if (target && target.children.length > 0) { target.removeChild(target.children[0]) } } export function toggleSortStyle(target: HTMLElement): string { let field = target.getAttribute("data-field") if (!field) { const p = target.parentNode as HTMLElement if (p) { field = p.getAttribute("data-field") } } if (!field || field.length === 0) { return "" } if (target.nodeName === "I") { target = target.parentNode as HTMLElement } let i = null if (target.children.length === 0) { target.innerHTML = target.innerHTML + '<i class="sort-up"></i>' } else { i = target.children[0] if (i.classList.contains("sort-up")) { i.classList.remove("sort-up") i.classList.add("sort-down") } else if (i.classList.contains("sort-down")) { i.classList.remove("sort-down") i.classList.add("sort-up") } } return field } export function getOffset(limit: number, page?: number, firstLimit?: number): number { const p = page && page > 0 ? page : 1 if (firstLimit && firstLimit > 0) { const offset = limit * (p - 2) + firstLimit return offset < 0 ? 0 : offset } else { const offset = limit * (p - 1) return offset < 0 ? 0 : offset } }