vue-smart-table
Version:
A table with dynamic components for vue.js
182 lines (173 loc) • 6.16 kB
JavaScript
/**
* Created by gurghet on 29/06/16.
*/
function getDataFromDotNotation (d, row) {
return d.split('.').reduce((o, i) => { if (o === undefined) { return undefined } else { return o[i] } }, row)
}
function derivedBody (body, cols) {
return body.map(row => {
cols.forEach(col => {
let realColValue = {}
if (/\+/.test(col)) {
// it's a composite column will return an object
col.split('+').forEach(d => {
realColValue[d] = getDataFromDotNotation(d, row)
})
} else {
realColValue = getDataFromDotNotation(col, row)
}
row[col] = realColValue
})
return row
})
}
var camelCase = require('camel-case')
function undashCamelize (columnKey) {
return camelCase(columnKey.replace(/\-/, ' '))
}
/**
* rawBody is an array in the form
* [ { 'col 1': 'value 1', 'col 2': 'value 2', ... [_id: 'some id'] },
* { 'col 1': 'value 3', 'col 2': 'value 4', ... [_id: 'some other id'] },
* ... ]
* Columns can be omitted and _ids can be omitted too.
*/
function bodyWithIds (body, idColKey) {
let counter = 0
let usedIds = []
body.forEach(row => {
let idValue = getDataFromDotNotation(idColKey, row)
if ((idValue === undefined || idValue === null) && (row[idColKey] === undefined || row[idColKey] === null)) {
idValue = '_smart_' + counter++
}
if (usedIds.indexOf(idValue) !== -1) {
idValue = String(idValue) + '-' + counter++
}
row._id = idValue
usedIds.push(idValue)
Object.keys(row).forEach(p => {
if (p.indexOf(' ') !== -1 || p.indexOf('-') !== -1) {
let camelized = undashCamelize(p)
let v = row[p]
delete row[p]
row[camelized] = v
}
})
})
return body
}
function assertShowReactive (row) {
if (row._show === undefined || ((Object.getOwnPropertyDescriptor(row, '_show').get === undefined) && row.____mut !== '')) {
console.error('[Smart Table Internal Error] Missing or non-reactive _show property, set the _show property before calling filteredBody and it has to be reactive')
}
}
function filteredBody (body, filter, colKeys, cumulative = false) {
if (colKeys === undefined) {
throw new Error('[Smart Table Internal Error] Filtering scope not defined')
}
if (colKeys.length === 0) {
// no scoping => no filtering
// this is to treat the most common case
// in which no filterable columns are
// defined, it also incidentally
// catches the case in which the scope is
// a malformed empty column
return
}
if (typeof filter === 'function') {
if (Array.isArray(colKeys) && colKeys.length !== 1) {
throw new Error('[Smart Table Internal Error] When using custom function the filtering scope must be on exatcly one column (namely the column of component that provides the function)')
}
let colKey = colKeys
return body.forEach(row => {
assertShowReactive(row)
let val = getDataFromDotNotation(colKey, row)
if (filter(val)) {
row._show = !cumulative || row._show
} else {
row._show = false
}
})
} else if (typeof filter === 'string') {
return body.forEach(row => {
assertShowReactive(row)
function someColumnContainsFilter () {
return colKeys.some(col => {
let val = getDataFromDotNotation(col, row)
let lowerCaseFilter = filter.toLowerCase()
let columnIsStringAndContainsFilter = typeof val === 'string' && val.toLowerCase().indexOf(lowerCaseFilter) !== -1
let columnIsNumberAndContainsFilterAsAString = typeof val === 'number' && String(val).indexOf(filter) !== -1
return columnIsStringAndContainsFilter || columnIsNumberAndContainsFilterAsAString
})
}
function columnContainsFilter () {
let colKey = colKeys
let val = getDataFromDotNotation(colKey, row)
// todo: remove this code duplication eventually
let lowerCaseFilter = String(filter).toLowerCase()
return val !== undefined && String(val).toLowerCase().indexOf(lowerCaseFilter) !== -1
}
if (
Array.isArray(colKeys) && someColumnContainsFilter() || // global search
typeof colKeys === 'string' && columnContainsFilter()
) {
row._show = !cumulative || row._show
} else {
row._show = false
}
})
}
}
function sortedBody (body, colKey, desc, compareFunction) {
function numericCompare (row1, row2) {
let valA = getDataFromDotNotation(colKey, row1)
var valB = getDataFromDotNotation(colKey, row2)
if (valA === undefined || valB === undefined) {
return 0
}
return (valA - valB) * (desc ? -1 : 1)
}
function lexicographicCompare (row1, row2) {
let valA = String(getDataFromDotNotation(colKey, row1))
var valB = String(getDataFromDotNotation(colKey, row2))
if (valA === undefined || valB === undefined) {
return 0
}
var r = (valA > valB) ? 1 : -1
return r * (desc ? -1 : 1)
}
function isNumeric (obj) {
return !Array.isArray(obj) && (obj - parseFloat(obj) + 1) >= 0
}
function scopedCompareFunction (row1, row2) {
let valA = getDataFromDotNotation(colKey, row1)
let valB = getDataFromDotNotation(colKey, row2)
return compareFunction(valA, valB)
}
if (compareFunction !== undefined && typeof compareFunction === 'string') {
if (compareFunction === 'lexicographic') {
body.sort(lexicographicCompare)
}
} else if (compareFunction !== undefined && typeof compareFunction === 'function') {
body.sort(scopedCompareFunction)
if (desc) {
body.reverse()
}
} else {
let everyRowIsNonNumeric = body.every(r => !isNumeric(getDataFromDotNotation(colKey, r)))
if (everyRowIsNonNumeric) {
body.sort(lexicographicCompare)
} else {
body.sort(numericCompare)
}
}
return body
}
function camelizeHeader (header) {
header.forEach(p => {
if (p.key.indexOf(' ') !== -1 || p.key.indexOf('-') !== -1) {
p.key = camelCase(p.key.replace(/\-/, ' '))
}
})
}
export default { derivedBody, bodyWithIds, filteredBody, sortedBody, camelizeHeader }