UNPKG

datatables.net-plugins

Version:

Various small plug-ins for DataTables including feature, ordering, search and internationalisation plug-ins.

324 lines (283 loc) 8.77 kB
/*! * Fuzzy Search for DataTables * SpryMedia Ltd - datatables.net/license MIT license * * Damerau-Levenshtein function courtesy of https://github.com/tad-lispy/node-damerau-levenshtein * BSD 2-Clause License * Copyright (c) 2018, Tadeusz Łazurski * All rights reserved. */ import DataTable from 'datatables.net'; import './types'; import fuzzySearch from './fuzzySearch'; DataTable.ext.search.push(function (settings, data, dataIndex) { var initial = settings.oInit.fuzzySearch; if (!initial) { return true; } if (settings.aoData[dataIndex]) { // If fuzzy searching has not been implemented then pass all rows for this function if (settings.aoData[dataIndex]._fuzzySearch !== undefined) { // Read score to set the cell content and sort data var score = settings.aoData[dataIndex]._fuzzySearch.score; if (initial.rankColumn !== undefined) { settings.aoData[dataIndex].anCells[initial.rankColumn].innerHTML = score; // Remove '%' from the end of the score so can sort on a number settings.aoData[dataIndex]._aSortData[initial.rankColumn] = +score.substring(0, score.length - 1); } // Return the value for the pass as decided by the fuzzySearch function return settings.aoData[dataIndex]._fuzzySearch.pass; } else if (initial.rankColumn !== undefined) { settings.aoData[dataIndex].anCells[initial.rankColumn].innerHTML = ''; settings.aoData[dataIndex]._aSortData[initial.rankColumn] = ''; } } return true; }); $(document).on('init.dt', function (e, settings) { var api = new DataTable.Api(settings); var initial = api.init(); var initialFuzzy = initial.fuzzySearch; // If this is not set then fuzzy searching is not enabled on the table so return. if (!initialFuzzy) { return; } if (typeof initialFuzzy === 'object' && initialFuzzy.columns) { initialFuzzy.columns = api.columns(initialFuzzy.columns).indexes().toArray(); } var fromPlugin = false; // Find the input element var input = $('div.dt-search input', api.table().container()); var fontBold = { 'font-weight': '600', 'background-color': 'rgba(255,255,255,0.1)', }; var fontNormal = { 'font-weight': '500', 'background-color': 'transparent', }; var toggleCSS = { border: 'none', background: 'none', 'font-size': '100%', width: '50%', display: 'inline-block', color: 'white', cursor: 'pointer', padding: '0.5em', }; // Only going to set the toggle if it is enabled var toggle, tooltip, exact, fuzzy, label; if (initialFuzzy === true || initialFuzzy.toggleSmart) { toggle = $('<button class="toggleSearch">Abc</button>') .insertAfter(input) .css({ border: 'none', background: 'none', position: 'relative', right: '33px', top: '0px', cursor: 'pointer', color: '#3b5e99', 'margin-top': '1px', }); exact = $('<button class="toggleSearch">Exact</button>') .insertAfter(input) .css(toggleCSS) .css(fontBold) .attr('highlighted', 'true'); fuzzy = $('<button class="toggleSearch">Fuzzy</button>') .insertAfter(input) .css(toggleCSS); input.css({ 'padding-right': '30px', }); $(input.parent()).css('right', '-33px').css('position', 'relative'); label = $('<div>Search Type<div>').css({ 'padding-bottom': '0.5em', 'font-size': '0.8em', }); tooltip = $('<div class="fuzzyToolTip"></div>') .css({ position: 'absolute', top: '2em', background: 'white', 'border-radius': '4px', 'text-align': 'center', padding: '0.5em', 'background-color': '#16232a', 'box-shadow': '4px 4px 4px rgba(0, 0, 0, 0.5)', color: 'white', transition: 'opacity 0.25s', 'z-index': '30001', width: input.outerWidth()! - 3, }) .append(label) .append(exact) .append(fuzzy); } function toggleFuzzy(event) { if (toggle.attr('blurred')) { toggle.css({ filter: 'blur(0px)' }).removeAttr('blurred'); fuzzy.removeAttr('highlighted').css(fontNormal); exact.attr('highlighted', true).css(fontBold); } else { toggle.css({ filter: 'blur(1px)' }).attr('blurred', true); exact.removeAttr('highlighted').css(fontNormal); fuzzy.attr('highlighted', true).css(fontBold); } // Whenever the search mode is changed we need to re-search triggerSearchFunction(event); } // Highlights one of the buttons in the tooltip and un-highlights the other function highlightButton(toHighlight, event) { if (!toHighlight.attr('highlighted')) { toggleFuzzy(event); } } // Removes the tooltip element function removeToolTip() { tooltip.remove(); } // Turn off the default datatables searching events $(settings.nTable).off('search.dt.DT'); var fuzzySearchVal = ''; var searchVal = ''; // The function that we want to run on search var triggerSearchFunction = function (event) { // If the search is only to be triggered on return wait for that if ( (event.type === 'input' && (initial.search === undefined || !(initial.search as any).return)) || event.key === 'Enter' || event.type === 'click' ) { // If the toggle is set and isn't checkd then perform a normal search if (toggle && !toggle.attr('blurred')) { api.rows().iterator( 'row', function (settings: any, rowIdx) { settings.aoData[rowIdx]._fuzzySearch = undefined; }, false ); searchVal = input.val() as string; fuzzySearchVal = searchVal; fromPlugin = true; api.search(searchVal); fromPlugin = false; searchVal = ''; } // Otherwise perform a fuzzy search else { // Get the value from the input element and convert to lower case fuzzySearchVal = input.val() as string; searchVal = ''; if (fuzzySearchVal !== undefined && fuzzySearchVal.length !== 0) { fuzzySearchVal = fuzzySearchVal.toLowerCase(); } // For each row call the fuzzy search function to get result api.rows().iterator( 'row', function (settings: any, rowIdx) { settings.aoData[rowIdx]._fuzzySearch = fuzzySearch( fuzzySearchVal, settings.aoData[rowIdx]._aFilterData, initialFuzzy ); }, false ); fromPlugin = true; // Empty the datatables search and replace it with our own api.search(''); input.val(fuzzySearchVal); fromPlugin = false; } fromPlugin = true; api.draw(); fromPlugin = false; } }; var apiRegister = DataTable.Api.register; apiRegister('search.fuzzy()', function (value) { if (value === undefined) { return fuzzySearchVal; } else { fuzzySearchVal = value.toLowerCase(); searchVal = api.search() as string; input.val(fuzzySearchVal); // For each row call the fuzzy search function to get result api.rows().iterator( 'row', function (settings: any, rowIdx) { settings.aoData[rowIdx]._fuzzySearch = fuzzySearch( fuzzySearchVal, settings.aoData[rowIdx]._aFilterData, initialFuzzy ); }, false ); // triggerSearchFunction({key: 'Enter'}); return this; } }); input.off(); // Set listeners to occur on toggle and typing if (toggle) { // Actions for the toggle button toggle .on('click', toggleFuzzy) .on('mouseenter', function () { tooltip.insertAfter(toggle).on('mouseleave', removeToolTip); tooltip.css('left', input.position().left + 3); exact.on('click', event => highlightButton(exact, event)); fuzzy.on('click', event => highlightButton(fuzzy, event)); }) .on('mouseleave', removeToolTip); // Actions for the input element input .on('mouseenter', function () { tooltip.insertAfter(toggle).on('mouseleave', removeToolTip); tooltip.css('left', input.position().left + 3); exact.on('click', event => highlightButton(exact, event)); fuzzy.on('click', event => highlightButton(fuzzy, event)); }) .on('mouseleave', function () { var inToolTip = false; tooltip.on('mouseenter', () => (inToolTip = true)); toggle.on('mouseenter', () => (inToolTip = true)); setTimeout(function () { if (!inToolTip) { removeToolTip(); } }, 250); }); var state = api.state.loaded(); api.on('stateSaveParams', function (e, settings, data) { data._fuzzySearch = { active: toggle.attr('blurred'), val: input.val(), }; }); if (state !== null && state._fuzzySearch !== undefined) { input.val(state._fuzzySearch.val); if (state._fuzzySearch.active === 'true') { toggle.click(); api.page(state.start / state.length).draw('page'); } } } api.on('search', function () { if (!fromPlugin) { input.val(api.search() !== searchVal ? api.search() as string : fuzzySearchVal); } }); // Always add this event no matter if toggling is enabled input.on('input keydown', triggerSearchFunction); });