{"version":3,"sources":["jsdelivr-header.js","/npm/sv-filtable@2.3.0/src/sv-filtable.js"],"names":[],"mappings":"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","file":"/npm/sv-filtable@2.3.0/src/sv-filtable.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/sv-filtable@2.3.0/src/sv-filtable.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","// load namespace\nSV = window.SV || {};\n\nSV.Filtable = (function() {\n\n\t// constructor\n\treturn function(tableElem, controlPanel, userConfig) {\n\n\t\t// private members\n\n\t\t// control types with events\n\t\tconst controlTypes = {\n\t\t\ttext: {\n\t\t\t\tselector: 'input[type=\"text\"], input[type=\"search\"]',\n\t\t\t\tevent: 'input',\n\t\t\t},\n\t\t\tselect: {\n\t\t\t\tselector: 'select',\n\t\t\t\tevent: 'change',\n\t\t\t},\n\t\t\tcheckbox: {\n\t\t\t\tselector: 'input[type=\"checkbox\"]',\n\t\t\t\tevent: 'click',\n\t\t\t},\n\t\t};\n\n\t\tlet allControlFields = [];\n\n\t\tconst defaultOptions = {\n\t\t\tzebraStriping: false,\n\t\t\tlocale: 'en',\n\t\t};\n\t\tlet config = {};\n\n\t\t// classes for zebra striping\n\t\tconst zebraStripes = ['odd', 'even'];\n\n\t\t// public api\n\t\tlet methods = {};\n\n\t\t// private methods\n\n\t\t/**\n\t\t * Set up.\n\t\t */\n\t\tconst init = function() {\n\t\t\tif (!tableElem) {\n\t\t\t\tthrow 'Error: invalid table element supplied';\n\t\t\t}\n\n\t\t\t// merge config\n\t\t\tconfig = Object.assign({}, defaultOptions, userConfig);\n\n\t\t\tsetUpInputEvents();\n\n\t\t\t// filter on hashchange\n\t\t\twindow.addEventListener('hashchange', function() {\n\t\t\t\tapplyHashFilters();\n\t\t\t\tmethods.applyFilters(methods.buildFilters());\n\t\t\t});\n\n\t\t\t// filter on page load\n\t\t\tapplyHashFilters();\n\t\t\t// trigger redraw so browser can autocomplete fields\n\t\t\tsetTimeout(function() {\n\t\t\t\tmethods.applyFilters(methods.buildFilters());\n\t\t\t}, 10);\n\t\t};\n\n\t\t/**\n\t\t * Helper function for case-insensitive search.\n\t\t */\n\t\tconst strContains = function(haystack, needle) {\n\t\t\treturn haystack.toLocaleLowerCase(config.locale).indexOf(needle.toLocaleLowerCase(config.locale)) != -1;\n\t\t};\n\n\t\t/**\n\t\t * Get a form control's value (different handling for checkboxes).\n\t\t */\n\t\tconst getFieldValue = function(fieldElem) {\n\t\t\tconst isCheckbox = fieldElem.matches(controlTypes.checkbox.selector);\n\t\t\tif (isCheckbox && !fieldElem.checked) {\n\t\t\t\treturn '';\n\t\t\t}\n\n\t\t\treturn fieldElem.value;\n\t\t};\n\n\t\t/**\n\t\t * Simple range function.\n\t\t */\n\t\tconst allColumnIds = function() {\n\t\t\tconst cells = tableElem.querySelectorAll(':scope > tbody > tr:first-child > td');\n\n\t\t\treturn Array.from(Array(cells.length).keys());\n\t\t};\n\n\t\t/**\n\t\t * Check specified ids are valid columns.\n\t\t */\n\t\tconst validateColumnIds = function(allIds, filterIds) {\n\t\t\tfor (let col of filterIds) {\n\t\t\t\tcol = parseInt(col);\n\t\t\t\tif (allIds.indexOf(col) == -1) {\n\t\t\t\t\tthrow 'Error: invalid column specified in data-filter-col attribute';\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Add event listeners to all input fields.\n\t\t */\n\t\tconst setUpInputEvents = function() {\n\t\t\tif (!controlPanel) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tfor (let i in controlTypes) {\n\t\t\t\tlet ctrlType = controlTypes[i];\n\t\t\t\tlet fieldElems = controlPanel.querySelectorAll(ctrlType.selector);\n\t\t\t\tfor (let field of fieldElems) {\n\t\t\t\t\tallControlFields.push(field);\n\t\t\t\t\tfield.addEventListener(ctrlType.event, function () {\n\t\t\t\t\t\tlet filters = methods.buildFilters();\n\t\t\t\t\t\tmethods.applyFilters(filters);\n\t\t\t\t\t\tupdateHashFilter(field);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Return whether this row should be shown or not.\n\t\t */\n\t\tconst filterRow = function(row, filters) {\n\t\t\tconst cells = row.querySelectorAll(':scope > td');\n\n\t\t\tfor (let filter of filters) {\n\t\t\t\t// skip if empty search value\n\t\t\t\tif (filter.value.length == 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tlet showThisRow = false;\n\t\t\t\t// check for match in any columns\n\t\t\t\tfor (let col of filter.columns) {\n\t\t\t\t\tlet cell = cells[col];\n\t\t\t\t\tlet filterVal = cell.getAttribute('data-filter-value');\n\t\t\t\t\tif (filterVal) {\n\t\t\t\t\t\t// use exact match for filter-value\n\t\t\t\t\t\tif (filter.value == filterVal) {\n\t\t\t\t\t\t\tshowThisRow = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// partial match\n\t\t\t\t\t\tlet cellVal = cell.textContent;\n\t\t\t\t\t\tif (strContains(cellVal, filter.value)) {\n\t\t\t\t\t\t\tshowThisRow = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if this filter doesn't match, ignore the rest\n\t\t\t\tif (!showThisRow) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// all filters matched\n\t\t\treturn true;\n\t\t};\n\n\t\t/**\n\t\t * Extract filter object from URL hash.\n\t\t */\n\t\tconst parseHashFilter = function() {\n\t\t\tlet hashStr = window.location.hash.replace('#', '');\n\t\t\tif (hashStr.length === 0) {\n\t\t\t\treturn {};\n\t\t\t}\n\n\t\t\tlet filters = {};\n\t\t\tlet params = hashStr.split('&');\n\t\t\tfor (let param of params) {\n\t\t\t\tlet filterData = param.split('=');\n\t\t\t\tif (filterData.length === 2) {\n\t\t\t\t\tfilters[filterData[0]] = filterData[1];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn filters;\n\t\t};\n\n\t\t/**\n\t\t * Get URL hash and apply to control panel fields, which in turn filters the table.\n\t\t */\n\t\tconst applyHashFilters = function() {\n\t\t\tif (!controlPanel) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tlet hashData = parseHashFilter();\n\t\t\tfor (let name in hashData) {\n\t\t\t\tfieldElem = controlPanel.querySelector('[data-filter-hash=\"' + name + '\"]');\n\t\t\t\tif (!fieldElem) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst isCheckbox = fieldElem.matches(controlTypes.checkbox.selector);\n\t\t\t\tif (isCheckbox && fieldElem.value === hashData[name]) {\n\t\t\t\t\tfieldElem.checked = true;\n\t\t\t\t} else {\n\t\t\t\t\tfieldElem.value = hashData[name];\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Update URL hash based on input value (doesn't trigger onhashchange).\n\t\t */\n\t\tconst updateHashFilter = function(fieldElem) {\n\t\t\tlet fieldName = fieldElem.getAttribute('data-filter-hash');\n\t\t\tif (!fieldName) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// extend current data\n\t\t\tlet hashData = parseHashFilter();\n\t\t\thashData[fieldName] = getFieldValue(fieldElem);\n\n\t\t\t// recompose hash\n\t\t\tlet hashStr = '#';\n\t\t\tfor (let name in hashData) {\n\t\t\t\tif (hashData[name].length === 0) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (hashStr !== '#') {\n\t\t\t\t\thashStr += '&';\n\t\t\t\t}\n\n\t\t\t\thashStr += name + '=' + hashData[name];\n\t\t\t}\n\n\t\t\t// remove hash if empty\n\t\t\tif (hashStr === '#') {\n\t\t\t\thashStr = window.location.pathname + window.location.search;\n\t\t\t}\n\n\t\t\t// set hash\n\t\t\twindow.history.replaceState(undefined, undefined, hashStr);\n\t\t};\n\n\t\t// public methods\n\n\t\t/**\n\t\t * Create a set of filter objects based on all fields' values and data-filter-* properties.\n\t\t */\n\t\tmethods.buildFilters = function() {\n\t\t\tconst allCols = allColumnIds();\n\t\t\t// skip if table is empty\n\t\t\tif (allCols.length === 0) {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\tlet filters = [];\n\t\t\tfor (let fieldElem of allControlFields) {\n\t\t\t\tlet columnIds = [];\n\t\t\t\tlet columnVal = fieldElem.getAttribute('data-filter-col');\n\n\t\t\t\tif (columnVal) {\n\t\t\t\t\tcolumnIds = columnVal.toString().split(',');\n\t\t\t\t\tvalidateColumnIds(allCols, columnIds);\n\t\t\t\t} else {\n\t\t\t\t\t// if data-filter-col is missing we search all table columns\n\t\t\t\t\tcolumnIds = allCols;\n\t\t\t\t}\n\n\t\t\t\tlet fieldVal = getFieldValue(fieldElem);\n\t\t\t\tfilters.push({columns: columnIds, value: fieldVal});\n\t\t\t}\n\n\t\t\treturn filters;\n\t\t};\n\n\t\t/**\n\t\t * Reset the odd and even classes on visible rows.\n\t\t */\n\t\tmethods.restripeTable = function() {\n\t\t\tlet tableRows = tableElem.querySelectorAll(':scope > tbody > tr');\n\t\t\tlet stripe = 0;\n\t\t\tfor (let row of tableRows) {\n\t\t\t\trow.classList.remove(...zebraStripes);\n\t\t\t\tif (!row.classList.contains('hidden')) {\n\t\t\t\t\trow.classList.add(zebraStripes[stripe]);\n\t\t\t\t\tstripe = 1 - stripe;\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t/**\n\t\t * Apply the array of filters to the table.\n\t\t * We no longer clone the tbody as it doesn't work with IntersectionObserver.\n\t\t */\n\t\tmethods.applyFilters = function(filters) {\n\t\t\tif (!Array.isArray(filters)) {\n\t\t\t\tthrow 'Error: invalid filters supplied';\n\t\t\t}\n\n\t\t\t// trigger before-filter event\n\t\t\ttableElem.dispatchEvent(new CustomEvent('sv.filtable.before'));\n\n\t\t\t// trigger a redraw to avoid locking up the browser and ensure sv.filtable.before takes effect\n\t\t\tsetTimeout(function() {\n\t\t\t\tlet tableRows = tableElem.querySelectorAll(':scope > tbody > tr');\n\t\t\t\tlet totalRows = tableRows.length;\n\t\t\t\tlet visibleRows = 0;\n\t\t\t\tfor (let row of tableRows) {\n\t\t\t\t\tlet showRow = filterRow(row, filters);\n\t\t\t\t\tif (showRow) {\n\t\t\t\t\t\trow.classList.remove('hidden');\n\t\t\t\t\t\tvisibleRows++;\n\t\t\t\t\t} else {\n\t\t\t\t\t\trow.classList.add('hidden');\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (config.zebraStriping) {\n\t\t\t\t\tmethods.restripeTable();\n\t\t\t\t}\n\n\t\t\t\t// trigger after-filter event\n\t\t\t\tconst evDetail = {\n\t\t\t\t\ttotalRows: totalRows,\n\t\t\t\t\tvisibleRows: visibleRows,\n\t\t\t\t};\n\t\t\t\ttableElem.dispatchEvent(new CustomEvent('sv.filtable.after', {detail: evDetail}));\n\t\t\t}, 10);\n\t\t};\n\n\t\tinit();\n\n\t\treturn methods;\n\t};\n\n})();\n"]}