2021-05-09 10:46:11 +08:00
|
|
|
import { hasOwn } from '@vue/shared'
|
2020-12-22 16:51:09 +08:00
|
|
|
import { PopperInstance, IPopperOptions } from '@element-plus/popper'
|
2020-10-20 10:31:47 +08:00
|
|
|
import { getValueByPath } from '@element-plus/utils/util'
|
2020-12-03 22:32:31 +08:00
|
|
|
import { off, on } from '@element-plus/utils/dom'
|
|
|
|
import { createPopper } from '@popperjs/core'
|
2020-12-22 16:51:09 +08:00
|
|
|
import PopupManager from '@element-plus/utils/popup-manager'
|
2021-05-13 17:55:04 +08:00
|
|
|
import { TableColumnCtx } from './table-column/defaults'
|
2020-10-20 10:31:47 +08:00
|
|
|
|
2021-08-04 18:28:08 +08:00
|
|
|
export type Nullable<T> = null | T
|
|
|
|
|
2020-12-03 22:32:31 +08:00
|
|
|
export const getCell = function(event: Event): HTMLElement {
|
2020-10-20 10:31:47 +08:00
|
|
|
let cell = event.target as HTMLElement
|
|
|
|
|
|
|
|
while (cell && cell.tagName.toUpperCase() !== 'HTML') {
|
|
|
|
if (cell.tagName.toUpperCase() === 'TD') {
|
|
|
|
return cell
|
|
|
|
}
|
|
|
|
cell = cell.parentNode as HTMLElement
|
|
|
|
}
|
|
|
|
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
const isObject = function(obj: unknown): boolean {
|
2020-10-20 10:31:47 +08:00
|
|
|
return obj !== null && typeof obj === 'object'
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export const orderBy = function<T>(
|
|
|
|
array: T[],
|
|
|
|
sortKey: string,
|
|
|
|
reverse: string | number,
|
|
|
|
sortMethod,
|
|
|
|
sortBy: string | (string | ((a: T, b: T, array?: T[]) => number))[],
|
|
|
|
) {
|
2020-10-20 10:31:47 +08:00
|
|
|
if (
|
|
|
|
!sortKey &&
|
|
|
|
!sortMethod &&
|
|
|
|
(!sortBy || (Array.isArray(sortBy) && !sortBy.length))
|
|
|
|
) {
|
|
|
|
return array
|
|
|
|
}
|
|
|
|
if (typeof reverse === 'string') {
|
|
|
|
reverse = reverse === 'descending' ? -1 : 1
|
|
|
|
} else {
|
|
|
|
reverse = reverse && reverse < 0 ? -1 : 1
|
|
|
|
}
|
|
|
|
const getKey = sortMethod
|
|
|
|
? null
|
2020-12-03 22:32:31 +08:00
|
|
|
: function(value, index) {
|
2020-10-20 10:31:47 +08:00
|
|
|
if (sortBy) {
|
|
|
|
if (!Array.isArray(sortBy)) {
|
|
|
|
sortBy = [sortBy]
|
|
|
|
}
|
2020-12-03 22:32:31 +08:00
|
|
|
return sortBy.map(function(by) {
|
2020-10-20 10:31:47 +08:00
|
|
|
if (typeof by === 'string') {
|
|
|
|
return getValueByPath(value, by)
|
|
|
|
} else {
|
|
|
|
return by(value, index, array)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
if (sortKey !== '$key') {
|
|
|
|
if (isObject(value) && '$value' in value) value = value.$value
|
|
|
|
}
|
|
|
|
return [isObject(value) ? getValueByPath(value, sortKey) : value]
|
|
|
|
}
|
2020-12-03 22:32:31 +08:00
|
|
|
const compare = function(a, b) {
|
2020-10-20 10:31:47 +08:00
|
|
|
if (sortMethod) {
|
|
|
|
return sortMethod(a.value, b.value)
|
|
|
|
}
|
|
|
|
for (let i = 0, len = a.key.length; i < len; i++) {
|
|
|
|
if (a.key[i] < b.key[i]) {
|
|
|
|
return -1
|
|
|
|
}
|
|
|
|
if (a.key[i] > b.key[i]) {
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
return array
|
2020-12-03 22:32:31 +08:00
|
|
|
.map(function(value, index) {
|
2020-10-20 10:31:47 +08:00
|
|
|
return {
|
|
|
|
value: value,
|
|
|
|
index: index,
|
|
|
|
key: getKey ? getKey(value, index) : null,
|
|
|
|
}
|
|
|
|
})
|
2020-12-03 22:32:31 +08:00
|
|
|
.sort(function(a, b) {
|
2020-10-20 10:31:47 +08:00
|
|
|
let order = compare(a, b)
|
|
|
|
if (!order) {
|
|
|
|
// make stable https://en.wikipedia.org/wiki/Sorting_algorithm#Stability
|
|
|
|
order = a.index - b.index
|
|
|
|
}
|
2021-05-13 17:55:04 +08:00
|
|
|
return order * +reverse
|
2020-10-20 10:31:47 +08:00
|
|
|
})
|
|
|
|
.map(item => item.value)
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export const getColumnById = function<T>(
|
2020-10-20 10:31:47 +08:00
|
|
|
table: {
|
2021-05-13 17:55:04 +08:00
|
|
|
columns: TableColumnCtx<T>[]
|
2020-10-20 10:31:47 +08:00
|
|
|
},
|
|
|
|
columnId: string,
|
2021-05-13 17:55:04 +08:00
|
|
|
): null | TableColumnCtx<T> {
|
2020-10-20 10:31:47 +08:00
|
|
|
let column = null
|
2020-12-03 22:32:31 +08:00
|
|
|
table.columns.forEach(function(item) {
|
2020-10-20 10:31:47 +08:00
|
|
|
if (item.id === columnId) {
|
|
|
|
column = item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
return column
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export const getColumnByKey = function<T>(
|
2020-10-20 10:31:47 +08:00
|
|
|
table: {
|
2021-05-13 17:55:04 +08:00
|
|
|
columns: TableColumnCtx<T>[]
|
2020-10-20 10:31:47 +08:00
|
|
|
},
|
|
|
|
columnKey: string,
|
2021-05-13 17:55:04 +08:00
|
|
|
): TableColumnCtx<T> {
|
2020-10-20 10:31:47 +08:00
|
|
|
let column = null
|
|
|
|
for (let i = 0; i < table.columns.length; i++) {
|
|
|
|
const item = table.columns[i]
|
|
|
|
if (item.columnKey === columnKey) {
|
|
|
|
column = item
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return column
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export const getColumnByCell = function<T>(
|
2020-10-20 10:31:47 +08:00
|
|
|
table: {
|
2021-05-13 17:55:04 +08:00
|
|
|
columns: TableColumnCtx<T>[]
|
2020-10-20 10:31:47 +08:00
|
|
|
},
|
|
|
|
cell: HTMLElement,
|
2021-05-13 17:55:04 +08:00
|
|
|
): null | TableColumnCtx<T> {
|
2020-10-20 10:31:47 +08:00
|
|
|
const matches = (cell.className || '').match(/el-table_[^\s]+/gm)
|
|
|
|
if (matches) {
|
|
|
|
return getColumnById(table, matches[0])
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export const getRowIdentity = <T>(
|
|
|
|
row: T,
|
|
|
|
rowKey: string | ((row: T) => any),
|
2020-10-20 10:31:47 +08:00
|
|
|
): string => {
|
|
|
|
if (!row) throw new Error('row is required when get row identity')
|
|
|
|
if (typeof rowKey === 'string') {
|
|
|
|
if (rowKey.indexOf('.') < 0) {
|
2021-05-13 17:55:04 +08:00
|
|
|
return row[rowKey] + ''
|
2020-10-20 10:31:47 +08:00
|
|
|
}
|
|
|
|
const key = rowKey.split('.')
|
|
|
|
let current = row
|
|
|
|
for (let i = 0; i < key.length; i++) {
|
|
|
|
current = current[key[i]]
|
|
|
|
}
|
2021-05-13 17:55:04 +08:00
|
|
|
return current + ''
|
2020-10-20 10:31:47 +08:00
|
|
|
} else if (typeof rowKey === 'function') {
|
|
|
|
return rowKey.call(null, row)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export const getKeysMap = function<T>(
|
|
|
|
array: T[],
|
2020-10-20 10:31:47 +08:00
|
|
|
rowKey: string,
|
2021-05-13 17:55:04 +08:00
|
|
|
): Record<string, { row: T; index: number; }> {
|
2020-12-03 22:32:31 +08:00
|
|
|
const arrayMap = {}
|
|
|
|
;(array || []).forEach((row, index) => {
|
2020-10-20 10:31:47 +08:00
|
|
|
arrayMap[getRowIdentity(row, rowKey)] = { row, index }
|
|
|
|
})
|
|
|
|
return arrayMap
|
|
|
|
}
|
|
|
|
|
|
|
|
export function mergeOptions<T, K>(defaults: T, config: K): T & K {
|
|
|
|
const options = {} as T & K
|
|
|
|
let key
|
|
|
|
for (key in defaults) {
|
|
|
|
options[key] = defaults[key]
|
|
|
|
}
|
|
|
|
for (key in config) {
|
2021-05-13 17:55:04 +08:00
|
|
|
if (hasOwn((config as unknown) as Indexable<any>, key)) {
|
2020-10-20 10:31:47 +08:00
|
|
|
const value = config[key]
|
|
|
|
if (typeof value !== 'undefined') {
|
|
|
|
options[key] = value
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return options
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export function parseWidth(width: number | string): number {
|
2020-10-20 10:31:47 +08:00
|
|
|
if (width !== undefined) {
|
|
|
|
width = parseInt(width as string, 10)
|
|
|
|
if (isNaN(width)) {
|
|
|
|
width = null
|
|
|
|
}
|
|
|
|
}
|
2021-05-13 17:55:04 +08:00
|
|
|
return +width
|
2020-10-20 10:31:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function parseMinWidth(minWidth): number {
|
|
|
|
if (typeof minWidth !== 'undefined') {
|
|
|
|
minWidth = parseWidth(minWidth)
|
|
|
|
if (isNaN(minWidth)) {
|
|
|
|
minWidth = 80
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return minWidth
|
|
|
|
}
|
|
|
|
|
|
|
|
export function parseHeight(height: number | string) {
|
|
|
|
if (typeof height === 'number') {
|
|
|
|
return height
|
|
|
|
}
|
|
|
|
if (typeof height === 'string') {
|
|
|
|
if (/^\d+(?:px)?$/.test(height)) {
|
|
|
|
return parseInt(height, 10)
|
|
|
|
} else {
|
|
|
|
return height
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null
|
|
|
|
}
|
|
|
|
|
|
|
|
// https://github.com/reduxjs/redux/blob/master/src/compose.js
|
|
|
|
export function compose(...funcs) {
|
|
|
|
if (funcs.length === 0) {
|
|
|
|
return arg => arg
|
|
|
|
}
|
|
|
|
if (funcs.length === 1) {
|
|
|
|
return funcs[0]
|
|
|
|
}
|
|
|
|
return funcs.reduce((a, b) => (...args) => a(b(...args)))
|
|
|
|
}
|
|
|
|
|
2021-05-13 17:55:04 +08:00
|
|
|
export function toggleRowStatus<T>(
|
|
|
|
statusArr: T[],
|
|
|
|
row: T,
|
2020-10-20 10:31:47 +08:00
|
|
|
newVal: boolean,
|
|
|
|
): boolean {
|
|
|
|
let changed = false
|
|
|
|
const index = statusArr.indexOf(row)
|
|
|
|
const included = index !== -1
|
|
|
|
|
|
|
|
const addRow = () => {
|
|
|
|
statusArr.push(row)
|
|
|
|
changed = true
|
|
|
|
}
|
|
|
|
const removeRow = () => {
|
|
|
|
statusArr.splice(index, 1)
|
|
|
|
changed = true
|
|
|
|
}
|
|
|
|
|
|
|
|
if (typeof newVal === 'boolean') {
|
|
|
|
if (newVal && !included) {
|
|
|
|
addRow()
|
|
|
|
} else if (!newVal && included) {
|
|
|
|
removeRow()
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (included) {
|
|
|
|
removeRow()
|
|
|
|
} else {
|
|
|
|
addRow()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return changed
|
|
|
|
}
|
|
|
|
|
|
|
|
export function walkTreeNode(
|
|
|
|
root,
|
|
|
|
cb,
|
|
|
|
childrenKey = 'children',
|
|
|
|
lazyKey = 'hasChildren',
|
|
|
|
) {
|
|
|
|
const isNil = array => !(Array.isArray(array) && array.length)
|
|
|
|
|
|
|
|
function _walker(parent, children, level) {
|
|
|
|
cb(parent, children, level)
|
|
|
|
children.forEach(item => {
|
|
|
|
if (item[lazyKey]) {
|
|
|
|
cb(item, null, level + 1)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const children = item[childrenKey]
|
|
|
|
if (!isNil(children)) {
|
|
|
|
_walker(item, children, level + 1)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
root.forEach(item => {
|
|
|
|
if (item[lazyKey]) {
|
|
|
|
cb(item, null, 0)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const children = item[childrenKey]
|
|
|
|
if (!isNil(children)) {
|
|
|
|
_walker(item, children, 0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2020-12-03 22:32:31 +08:00
|
|
|
|
2021-01-27 15:25:55 +08:00
|
|
|
export let removePopper
|
|
|
|
|
2020-12-03 22:32:31 +08:00
|
|
|
export function createTablePopper(
|
|
|
|
trigger: HTMLElement,
|
|
|
|
popperContent: string,
|
2020-12-07 10:36:37 +08:00
|
|
|
popperOptions: Partial<IPopperOptions>,
|
2021-02-26 20:35:29 +08:00
|
|
|
tooltipEffect: string,
|
2020-12-03 22:32:31 +08:00
|
|
|
) {
|
|
|
|
function renderContent(): HTMLDivElement {
|
2021-02-26 20:35:29 +08:00
|
|
|
const isLight = tooltipEffect === 'light'
|
2020-12-03 22:32:31 +08:00
|
|
|
const content = document.createElement('div')
|
2021-02-26 20:35:29 +08:00
|
|
|
content.className = `el-popper ${isLight ? 'is-light' : 'is-dark'}`
|
2020-12-03 22:32:31 +08:00
|
|
|
content.innerHTML = popperContent
|
2020-12-22 16:51:09 +08:00
|
|
|
content.style.zIndex = String(PopupManager.nextZIndex())
|
2020-12-03 22:32:31 +08:00
|
|
|
document.body.appendChild(content)
|
|
|
|
return content
|
|
|
|
}
|
|
|
|
function renderArrow(): HTMLDivElement {
|
|
|
|
const arrow = document.createElement('div')
|
|
|
|
arrow.className = 'el-popper__arrow'
|
|
|
|
arrow.style.bottom = '-4px'
|
|
|
|
return arrow
|
|
|
|
}
|
|
|
|
function showPopper() {
|
|
|
|
popperInstance && popperInstance.update()
|
|
|
|
}
|
2021-01-27 15:25:55 +08:00
|
|
|
removePopper = function removePopper() {
|
2020-12-03 22:32:31 +08:00
|
|
|
try {
|
|
|
|
popperInstance && popperInstance.destroy()
|
|
|
|
content && document.body.removeChild(content)
|
|
|
|
off(trigger, 'mouseenter', showPopper)
|
2021-03-09 20:22:07 +08:00
|
|
|
off(trigger, 'mouseleave', removePopper)
|
2020-12-03 22:32:31 +08:00
|
|
|
} catch {}
|
|
|
|
}
|
|
|
|
let popperInstance: Nullable<PopperInstance> = null
|
|
|
|
const content = renderContent()
|
|
|
|
const arrow = renderArrow()
|
|
|
|
content.appendChild(arrow)
|
|
|
|
|
|
|
|
popperInstance = createPopper(trigger, content, {
|
|
|
|
modifiers: [
|
|
|
|
{
|
|
|
|
name: 'offset',
|
|
|
|
options: {
|
|
|
|
offset: [0, 8],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: 'arrow',
|
|
|
|
options: {
|
|
|
|
element: arrow,
|
|
|
|
padding: 10,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
...popperOptions,
|
|
|
|
})
|
|
|
|
on(trigger, 'mouseenter', showPopper)
|
|
|
|
on(trigger, 'mouseleave', removePopper)
|
2021-03-09 20:22:07 +08:00
|
|
|
return popperInstance
|
2020-12-03 22:32:31 +08:00
|
|
|
}
|