bootstrap-table
Version:
An extended table to integration with some of the most widely used CSS frameworks. (Supports Bootstrap, Semantic UI, Bulma, Material Design, Foundation)
163 lines (144 loc) • 4.43 kB
JavaScript
import { isNumeric } from './helper.js'
/**
* Search and sorting utilities.
*
* This module provides utility functions for searching and sorting table data,
* including regex comparison, custom sorting logic, and search result highlighting.
*
* @module utils/search-sort
*/
/**
* Compares a value against a search pattern using regex.
* Supports both plain text search and regex patterns (e.g., /pattern/flags).
*
* @param {*} value - The value to search in.
* @param {string} search - The search pattern or regex.
* @returns {boolean} True if the value matches the search pattern, false otherwise.
*/
export function regexCompare (value, search) {
try {
const regexpParts = search.match(/^\/(.*?)\/([gim]*)$/)
if (value.toString().search(regexpParts ? new RegExp(regexpParts[1], regexpParts[2]) : new RegExp(search, 'gim')) !== -1) {
return true
}
} catch (e) {
console.error(e)
return false
}
return false
}
/**
* Sorts two values with support for numeric, string, and empty value handling.
*
* @param {*} a - The first value to compare.
* @param {*} b - The second value to compare.
* @param {number} order - The sort order (1 for ascending, -1 for descending).
* @param {Object.<string, *>} options - Sort options.
* @param {boolean} [options.sortStable=false] - If true, use position for equal values.
* @param {boolean} [options.sortEmptyLast=false] - If true, sort empty values last.
* @param {number} aPosition - The position of the first value.
* @param {number} bPosition - The position of the second value.
* @returns {number} Negative if a < b, positive if a > b, 0 if equal.
*/
export function sort (a, b, order, options, aPosition, bPosition) {
if (a === undefined || a === null) {
a = ''
}
if (b === undefined || b === null) {
b = ''
}
if (options.sortStable && a === b) {
a = aPosition
b = bPosition
}
// If both values are numeric, do a numeric comparison
if (isNumeric(a) && isNumeric(b)) {
// Convert numerical values from string to float.
a = parseFloat(a)
b = parseFloat(b)
if (a < b) {
return order * -1
}
if (a > b) {
return order
}
return 0
}
if (options.sortEmptyLast) {
if (a === '') {
return 1
}
if (b === '') {
return -1
}
}
if (a === b) {
return 0
}
// If value is not a string, convert to string
if (typeof a !== 'string') {
a = a.toString()
}
if (a.localeCompare(b) === -1) {
return order * -1
}
return order
}
/**
* Highlights search text matches in HTML by wrapping them in <mark> tags.
* Recursively processes all text nodes in the HTML.
*
* @param {string|Element} html - The HTML string or DOM element to process.
* @param {string} searchText - The text to search for and highlight.
* @returns {string|Element} The HTML with matches highlighted, or the processed element.
*/
export function replaceSearchMark (html, searchText) {
const isDom = html instanceof Element
const node = isDom ? html : document.createElement('div')
const regExp = new RegExp(searchText, 'gim')
const replaceTextWithDom = (text, regExp) => {
const result = []
let match
let lastIndex = 0
while ((match = regExp.exec(text)) !== null) {
if (lastIndex !== match.index) {
result.push(document.createTextNode(text.substring(lastIndex, match.index)))
}
const mark = document.createElement('mark')
mark.innerText = match[0]
result.push(mark)
lastIndex = match.index + match[0].length
}
if (!result.length) {
// no match
return
}
if (lastIndex !== text.length) {
result.push(document.createTextNode(text.substring(lastIndex)))
}
return result
}
const replaceMark = node => {
for (let i = 0; i < node.childNodes.length; i++) {
const child = node.childNodes[i]
if (child.nodeType === document.TEXT_NODE) {
const elements = replaceTextWithDom(child.data, regExp)
if (elements) {
for (const el of elements) {
node.insertBefore(el, child)
}
node.removeChild(child)
i += elements.length - 1
}
}
if (child.nodeType === document.ELEMENT_NODE) {
replaceMark(child)
}
}
}
if (!isDom) {
node.innerHTML = html
}
replaceMark(node)
return isDom ? node : node.innerHTML
}