diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/.prettierrc.json b/.prettierrc.json index 5562411..b9805bb 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,5 +1,7 @@ { - "arrowParens": "always", + "arrowParens": "avoid", + "breakBeforeElse": true, + "indentChains": true, "printWidth": 80, "proseWrap": "preserve", "quoteProps": "as-needed", diff --git a/api/row().show().js b/api/row().show().js index 902eb2d..65db77f 100644 --- a/api/row().show().js +++ b/api/row().show().js @@ -59,9 +59,12 @@ DataTable.Api.register('row().show()', function () { // Get row index var new_row_index = this.index(); // Row position - var row_position = this.table().rows({ search: 'applied' })[0].indexOf(new_row_index); + var row_position = this.table() + .rows({ search: 'applied' })[0] + .indexOf(new_row_index); // Already on right page ? - if ((row_position >= page_info.start && row_position < page_info.end) || row_position < 0) { + if ((row_position >= page_info.start && row_position < page_info.end) || + row_position < 0) { // Return row object return this; } diff --git a/api/row().show().mjs b/api/row().show().mjs index d23e8fa..ba67ef2 100644 --- a/api/row().show().mjs +++ b/api/row().show().mjs @@ -30,9 +30,12 @@ DataTable.Api.register('row().show()', function () { // Get row index var new_row_index = this.index(); // Row position - var row_position = this.table().rows({ search: 'applied' })[0].indexOf(new_row_index); + var row_position = this.table() + .rows({ search: 'applied' })[0] + .indexOf(new_row_index); // Already on right page ? - if ((row_position >= page_info.start && row_position < page_info.end) || row_position < 0) { + if ((row_position >= page_info.start && row_position < page_info.end) || + row_position < 0) { // Return row object return this; } diff --git a/api/src/row().show().ts b/api/src/row().show().ts index cc35e18..8227cd4 100644 --- a/api/src/row().show().ts +++ b/api/src/row().show().ts @@ -37,10 +37,15 @@ DataTable.Api.register('row().show()', function () { // Get row index var new_row_index = this.index(); // Row position - var row_position = this.table().rows({ search: 'applied' })[0].indexOf(new_row_index); + var row_position = this.table() + .rows({ search: 'applied' })[0] + .indexOf(new_row_index); // Already on right page ? - if ((row_position >= page_info.start && row_position < page_info.end) || row_position < 0) { + if ( + (row_position >= page_info.start && row_position < page_info.end) || + row_position < 0 + ) { // Return row object return this; } diff --git a/api/src/sum().ts b/api/src/sum().ts index c6e8642..7e490a3 100644 --- a/api/src/sum().ts +++ b/api/src/sum().ts @@ -50,10 +50,10 @@ declare module 'datatables.net' { DataTable.Api.register('sum()', function () { return this.flatten().reduce(function (a, b) { if (typeof a === 'string') { - a = a.replace(/[^\d.-]/g, '') as any * 1; + a = (a.replace(/[^\d.-]/g, '') as any) * 1; } if (typeof b === 'string') { - b = b.replace(/[^\d.-]/g, '') as any * 1; + b = (b.replace(/[^\d.-]/g, '') as any) * 1; } return a + b; diff --git a/buttons/button.download.js b/buttons/button.download.js index 9e891fc..9eb6711 100644 --- a/buttons/button.download.js +++ b/buttons/button.download.js @@ -106,7 +106,7 @@ DataTable.ext.buttons.download = { .css({ border: 'none', height: 0, - width: 0 + width: 0, }) .appendTo(document.body); var contentDoc = iframe[0].contentWindow.document; @@ -128,7 +128,7 @@ DataTable.ext.buttons.download = { }, url: '', type: 'POST', - data: {} + data: {}, }; diff --git a/buttons/button.download.mjs b/buttons/button.download.mjs index 7a8f51c..b893c33 100644 --- a/buttons/button.download.mjs +++ b/buttons/button.download.mjs @@ -77,7 +77,7 @@ DataTable.ext.buttons.download = { .css({ border: 'none', height: 0, - width: 0 + width: 0, }) .appendTo(document.body); var contentDoc = iframe[0].contentWindow.document; @@ -99,7 +99,7 @@ DataTable.ext.buttons.download = { }, url: '', type: 'POST', - data: {} + data: {}, }; diff --git a/buttons/src/button.download.ts b/buttons/src/button.download.ts index 9e1ed27..ba7be32 100644 --- a/buttons/src/button.download.ts +++ b/buttons/src/button.download.ts @@ -54,11 +54,13 @@ function flattenJson(data, name?, flattened?) { $.each(data, function (idx, val) { if (name === '') { flattenJson(val, idx, flattened); - } else { + } + else { flattenJson(val, name + '[' + idx.toString() + ']', flattened); } }); - } else { + } + else { flattened[name] = data; } @@ -77,7 +79,8 @@ DataTable.ext.buttons.download = { if (typeof config.data === 'function') { config.data(data); - } else if (typeof config.data === 'object') { + } + else if (typeof config.data === 'object') { $.extend(data, config.data); } diff --git a/dataRender/multi.js b/dataRender/multi.js index e68f10a..453bfc7 100644 --- a/dataRender/multi.js +++ b/dataRender/multi.js @@ -61,13 +61,13 @@ var DataTable = $.fn.dataTable; DataTable.render.multi = function (renderArray) { return function (d, type, row, meta) { for (var r = 0; r < renderArray.length; r++) { - if (typeof renderArray[r] === "function") { + if (typeof renderArray[r] === 'function') { d = renderArray[r](d, type, row, meta); } - else if (typeof renderArray[r][type] === "function") { + else if (typeof renderArray[r][type] === 'function') { d = renderArray[r][type](d, type, row, meta); } - else if (typeof renderArray[r]._ === "function") { + else if (typeof renderArray[r]._ === 'function') { d = renderArray[r]._(d, type, row, meta); } } diff --git a/dataRender/multi.mjs b/dataRender/multi.mjs index fae10e9..db5d912 100644 --- a/dataRender/multi.mjs +++ b/dataRender/multi.mjs @@ -32,13 +32,13 @@ import DataTable from 'datatables.net'; DataTable.render.multi = function (renderArray) { return function (d, type, row, meta) { for (var r = 0; r < renderArray.length; r++) { - if (typeof renderArray[r] === "function") { + if (typeof renderArray[r] === 'function') { d = renderArray[r](d, type, row, meta); } - else if (typeof renderArray[r][type] === "function") { + else if (typeof renderArray[r][type] === 'function') { d = renderArray[r][type](d, type, row, meta); } - else if (typeof renderArray[r]._ === "function") { + else if (typeof renderArray[r]._ === 'function') { d = renderArray[r]._(d, type, row, meta); } } diff --git a/dataRender/numberTo.d.ts b/dataRender/numberTo.d.ts new file mode 100644 index 0000000..9c4aa4b --- /dev/null +++ b/dataRender/numberTo.d.ts @@ -0,0 +1,8 @@ +/*! © SpryMedia Ltd, Alireza Mohammadi Doost - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStaticRender { + /** Convert numbers to Farsi, English or Arabic. */ + numberTo(string: 'fa' | 'en' | 'ar'): any; + } +} +export {}; diff --git a/dataRender/numberTo.js b/dataRender/numberTo.js new file mode 100644 index 0000000..d1a520a --- /dev/null +++ b/dataRender/numberTo.js @@ -0,0 +1,83 @@ +/*! © SpryMedia Ltd, Alireza Mohammadi Doost - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +/** + * Convert numbers to farsi, english, arabic. + * تبدیل عداد به فارسی, انگلیسی, عربی + * + * @name convertTo + * @summary convert numbers to farsi, english, arabic. + * @author Alireza Mohammadi Doost + * + * @example + * $('#example').DataTable( { + * columnDefs: [ { + * targets: 2, + * render: DataTable.render.numberTo('fa') + * } ] + * } ); + */ +DataTable.render.numberTo = function (to = 'fa') { + let result = null; + const faNumbers = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; + const enNumbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + const arNumbers = ['۰', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + return function (d, type, row) { + if (type !== 'display') { + return d; + } + if (!d && to === 'fa') { + return 'مقدار ورودی صحیح نمی‌باشد.'; + } + else if (!d) { + return 'numbers is empty.'; + } + switch (to) { + case 'fa': + result = d.toString().replace(/\d/g, x => faNumbers[x]); + break; + case 'en': + result = d.toString().replace(/\d/g, x => enNumbers[x]); + break; + case 'ar': + result = d.toString().replace(/\d/g, x => arNumbers[x]); + break; + } + return result; + }; +}; + + +return DataTable; +})); diff --git a/dataRender/numberTo.min.js b/dataRender/numberTo.min.js new file mode 100644 index 0000000..87e4195 --- /dev/null +++ b/dataRender/numberTo.min.js @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd, Alireza Mohammadi Doost - datatables.net/license */ +!function(t){"function"==typeof define&&define.amd?define(["datatables.net"],function(e){return t(e,window,document)}):"object"==typeof exports?module.exports=function(e,n){return e=e||window,n.fn.dataTable||require("datatables.net")(e,n),t(n,0,e.document)}:t(jQuery,window,document)}(function(e,n,t,r){"use strict";e=e.fn.dataTable;return e.render.numberTo=function(r="fa"){let a=null;const u=["۰","۱","۲","۳","۴","۵","۶","۷","۸","۹"],i=["0","1","2","3","4","5","6","7","8","9"],o=["۰","١","٢","٣","٤","٥","٦","٧","٨","٩"];return function(e,n,t){if("display"!==n)return e;if(!e&&"fa"===r)return"مقدار ورودی صحیح نمی‌باشد.";if(!e)return"numbers is empty.";switch(r){case"fa":a=e.toString().replace(/\d/g,e=>u[e]);break;case"en":a=e.toString().replace(/\d/g,e=>i[e]);break;case"ar":a=e.toString().replace(/\d/g,e=>o[e])}return a}},e}); \ No newline at end of file diff --git a/dataRender/numberTo.min.mjs b/dataRender/numberTo.min.mjs new file mode 100644 index 0000000..1608ea1 --- /dev/null +++ b/dataRender/numberTo.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd, Alireza Mohammadi Doost - datatables.net/license */ +import DataTable from"datatables.net";DataTable.render.numberTo=function(t="fa"){let n=null;const i=["۰","۱","۲","۳","۴","۵","۶","۷","۸","۹"],l=["0","1","2","3","4","5","6","7","8","9"],u=["۰","١","٢","٣","٤","٥","٦","٧","٨","٩"];return function(e,a,r){if("display"!==a)return e;if(!e&&"fa"===t)return"مقدار ورودی صحیح نمی‌باشد.";if(!e)return"numbers is empty.";switch(t){case"fa":n=e.toString().replace(/\d/g,e=>i[e]);break;case"en":n=e.toString().replace(/\d/g,e=>l[e]);break;case"ar":n=e.toString().replace(/\d/g,e=>u[e])}return n}};export default DataTable; \ No newline at end of file diff --git a/dataRender/numberTo.mjs b/dataRender/numberTo.mjs new file mode 100644 index 0000000..fc2cf0d --- /dev/null +++ b/dataRender/numberTo.mjs @@ -0,0 +1,53 @@ +/*! © SpryMedia Ltd, Alireza Mohammadi Doost - datatables.net/license */ + +import DataTable from 'datatables.net'; + + +/** + * Convert numbers to farsi, english, arabic. + * تبدیل عداد به فارسی, انگلیسی, عربی + * + * @name convertTo + * @summary convert numbers to farsi, english, arabic. + * @author Alireza Mohammadi Doost + * + * @example + * $('#example').DataTable( { + * columnDefs: [ { + * targets: 2, + * render: DataTable.render.numberTo('fa') + * } ] + * } ); + */ +DataTable.render.numberTo = function (to = 'fa') { + let result = null; + const faNumbers = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; + const enNumbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + const arNumbers = ['۰', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + return function (d, type, row) { + if (type !== 'display') { + return d; + } + if (!d && to === 'fa') { + return 'مقدار ورودی صحیح نمی‌باشد.'; + } + else if (!d) { + return 'numbers is empty.'; + } + switch (to) { + case 'fa': + result = d.toString().replace(/\d/g, x => faNumbers[x]); + break; + case 'en': + result = d.toString().replace(/\d/g, x => enNumbers[x]); + break; + case 'ar': + result = d.toString().replace(/\d/g, x => arNumbers[x]); + break; + } + return result; + }; +}; + + +export default DataTable; diff --git a/dataRender/src/intl.ts b/dataRender/src/intl.ts index 6e09543..35747cf 100644 --- a/dataRender/src/intl.ts +++ b/dataRender/src/intl.ts @@ -82,7 +82,8 @@ DataTable.render.intlDateTime = function (locale, options) { if (typeof data === 'string') { date = Date.parse(data); - } else if (data instanceof Date) { + } + else if (data instanceof Date) { date = data; } @@ -92,7 +93,8 @@ DataTable.render.intlDateTime = function (locale, options) { return formatter.format(date); }; - } else { + } + else { return function (d) { return d; }; @@ -106,12 +108,14 @@ DataTable.render.intlNumber = function (locale, options) { return function (d, type) { if (type === 'display') { return formatter.format(d); - } else if (type === 'filter') { + } + else if (type === 'filter') { return d + ' ' + formatter.format(d); } return d; }; - } else { + } + else { return function (d) { return d; }; diff --git a/dataRender/src/multi.ts b/dataRender/src/multi.ts index 1f1c458..71c8997 100644 --- a/dataRender/src/multi.ts +++ b/dataRender/src/multi.ts @@ -3,7 +3,7 @@ /** * This renderer doesn't format the output itself, but rather allows multiple * renderers to be easily called, which will render the content in sequence. - * + * * Pass the renderers you wish to chain together as elements in an array to * this function. Important - you should pass the renderer as if you were * going to give it to the `render` property directly (i.e. if it is just a @@ -39,11 +39,13 @@ declare module 'datatables.net' { DataTable.render.multi = function (renderArray: any[]) { return function (d, type, row, meta) { for (var r = 0; r < renderArray.length; r++) { - if (typeof renderArray[r] === "function") { + if (typeof renderArray[r] === 'function') { d = renderArray[r](d, type, row, meta); - } else if (typeof renderArray[r][type] === "function") { + } + else if (typeof renderArray[r][type] === 'function') { d = renderArray[r][type](d, type, row, meta); - } else if (typeof renderArray[r]._ === "function") { + } + else if (typeof renderArray[r]._ === 'function') { d = renderArray[r]._(d, type, row, meta); } } diff --git a/dataRender/src/numberTo.ts b/dataRender/src/numberTo.ts new file mode 100644 index 0000000..6c134de --- /dev/null +++ b/dataRender/src/numberTo.ts @@ -0,0 +1,62 @@ +/*! © SpryMedia Ltd, Alireza Mohammadi Doost - datatables.net/license */ + +/** + * Convert numbers to farsi, english, arabic. + * تبدیل عداد به فارسی, انگلیسی, عربی + * + * @name convertTo + * @summary convert numbers to farsi, english, arabic. + * @author Alireza Mohammadi Doost + * + * @example + * $('#example').DataTable( { + * columnDefs: [ { + * targets: 2, + * render: DataTable.render.numberTo('fa') + * } ] + * } ); + */ + +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface DataTablesStaticRender { + /** Convert numbers to Farsi, English or Arabic. */ + numberTo(string: 'fa' | 'en' | 'ar'); + } +} + +DataTable.render.numberTo = function (to = 'fa') { + let result = null; + const faNumbers = ['۰', '۱', '۲', '۳', '۴', '۵', '۶', '۷', '۸', '۹']; + const enNumbers = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; + const arNumbers = ['۰', '١', '٢', '٣', '٤', '٥', '٦', '٧', '٨', '٩']; + + return function (d, type, row) { + if (type !== 'display') { + return d; + } + + if (!d && to === 'fa') { + return 'مقدار ورودی صحیح نمی‌باشد.'; + } + else if (!d) { + return 'numbers is empty.'; + } + + switch (to) { + case 'fa': + result = d.toString().replace(/\d/g, x => faNumbers[x]); + break; + + case 'en': + result = d.toString().replace(/\d/g, x => enNumbers[x]); + break; + + case 'ar': + result = d.toString().replace(/\d/g, x => arNumbers[x]); + break; + } + return result; + }; +}; diff --git a/features/alphabetSearch/dataTables.alphabetSearch.d.ts b/features/alphabetSearch/dataTables.alphabetSearch.d.ts new file mode 100644 index 0000000..dac6eaa --- /dev/null +++ b/features/alphabetSearch/dataTables.alphabetSearch.d.ts @@ -0,0 +1,25 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStatic { + /** Show an set of alphabet buttons alongside a table providing search input options */ + AlphabetSearch(settings: any): void; + } + interface Config { + alphabet?: { + column: number; + caseSensitive: boolean; + numbers: boolean; + }; + } + interface Api { + alphabetSearch: ApiAlphabet; + } + interface ApiAlphabet { + (searchTerm: string): ApiAlphabetMethods; + } + interface ApiAlphabetMethods extends Api { + node(): JQuery | null; + recalc(): Api; + } +} +export {}; diff --git a/features/alphabetSearch/dataTables.alphabetSearch.js b/features/alphabetSearch/dataTables.alphabetSearch.js index a24a113..d4a4ae9 100644 --- a/features/alphabetSearch/dataTables.alphabetSearch.js +++ b/features/alphabetSearch/dataTables.alphabetSearch.js @@ -1,213 +1,212 @@ -/*! AlphabetSearch for DataTables v1.0.0 - * 2014 SpryMedia Ltd - datatables.net/license - */ +/*! © SpryMedia Ltd - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + /** * @summary AlphabetSearch * @description Show an set of alphabet buttons alongside a table providing * search input options - * @version 1.0.0 + * @version 1.1.0 * @file dataTables.alphabetSearch.js * @author SpryMedia Ltd (www.sprymedia.co.uk) * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2014 SpryMedia Ltd. + * @copyright Copyright SpryMedia Ltd. * * License MIT - http://datatables.net/license/mit * * For more detailed information please see: * http://datatables.net/blog/2014-09-22 */ -(function(){ - - // Search function -$.fn.dataTable.Api.register( 'alphabetSearch()', function ( searchTerm ) { - this.iterator( 'table', function ( context ) { - context.alphabetSearch = searchTerm; - } ); - - return this; -} ); - +DataTable.Api.register('alphabetSearch()', function (searchTerm) { + this.iterator('table', function (context) { + context.alphabetSearch = searchTerm; + }); + return this; +}); // Recalculate the alphabet display for updated data -$.fn.dataTable.Api.register( 'alphabetSearch.recalc()', function ( searchTerm ) { - this.iterator( 'table', function ( context ) { - draw( - new $.fn.dataTable.Api( context ), - $('div.alphabet', this.table().container()) - ); - } ); - - return this; -} ); - - +DataTable.Api.register('alphabetSearch.recalc()', function () { + this.iterator('table', function (context) { + draw(new DataTable.Api(context), context._alphabet, context._alphabetOptions); + }); + return this; +}); +DataTable.Api.register('alphabetSearch.node()', function () { + return this._context.length + ? this._context._alphabet + : null; + ; +}); // Search plug-in -$.fn.dataTable.ext.search.push( function ( context, searchData ) { - // Ensure that there is a search applied to this table before running it - if ( ! context.alphabetSearch ) { - return true; - } - - if (context.oInit.alphabet !== undefined) { - var columnId = (context.oInit.alphabet.column !== undefined) ? context.oInit.alphabet.column : 0 - var caseSensitive = (context.oInit.alphabet.caseSensitive !== undefined) ? context.oInit.alphabet.caseSensitive : false - } else { - var columnId = 0 - var caseSensitive = false - } - - if (caseSensitive) { - if ( searchData[columnId].charAt(0) === context.alphabetSearch ) { - return true; - } - } else { - if ( searchData[columnId].charAt(0).toUpperCase() === context.alphabetSearch ) { - return true; - } - } - - return false; -} ); - - +DataTable.ext.search.push(function (context, searchData) { + // Ensure that there is a search applied to this table before running it + if (!context.alphabetSearch) { + return true; + } + var columnId = 0; + var caseSensitive = false; + if (context.oInit.alphabet !== undefined) { + columnId = + context.oInit.alphabet.column !== undefined + ? context.oInit.alphabet.column + : 0; + caseSensitive = + context.oInit.alphabet.caseSensitive !== undefined + ? context.oInit.alphabet.caseSensitive + : false; + } + if (caseSensitive) { + if (searchData[columnId].charAt(0) === context.alphabetSearch) { + return true; + } + } + else { + if (searchData[columnId].charAt(0).toUpperCase() === context.alphabetSearch) { + return true; + } + } + return false; +}); // Private support methods -function bin ( data, options ) { - var letter, bins = {}; - - for ( var i=0, ien=data.length ; i/g, '') - .charAt(0); - } else { - letter = data[i] - .toString() - .replace(/<.*?>/g, '') - .charAt(0).toUpperCase(); - } - if ( bins[letter] ) { - bins[letter]++; - } - else { - bins[letter] = 1; - } - } - - return bins; +function bin(data, options) { + var letter, bins = {}; + for (var i = 0, ien = data.length; i < ien; i++) { + if (options.caseSensitive) { + letter = data[i].toString().replace(/<.*?>/g, '').charAt(0); + } + else { + letter = data[i].toString().replace(/<.*?>/g, '').charAt(0).toUpperCase(); + } + if (bins[letter]) { + bins[letter]++; + } + else { + bins[letter] = 1; + } + } + return bins; } - -function draw ( table, alphabet, options ) -{ - alphabet.empty(); - alphabet.append( 'Search: ' ); - - var columnData = table.column(options.column).data(); - var bins = bin( columnData, options ); - - $('') - .data( 'letter', '' ) - .data( 'match-count', columnData.length ) - .html( 'None' ) - .appendTo( alphabet ); - - if (options.numbers) { - for (var i = 0; i < 10; i++) { - var letter = String.fromCharCode(48 + i); - - $('') - .data('letter', letter) - .data('match-count', bins[letter] || 0) - .addClass(!bins[letter] ? 'empty' : '') - .html(letter) - .appendTo(alphabet); - } - } - for ( var i=0 ; i<26 ; i++ ) { - var letter = String.fromCharCode( 65 + i ); - - $('') - .data( 'letter', letter ) - .data( 'match-count', bins[letter] || 0 ) - .addClass( ! bins[letter] ? 'empty' : '' ) - .html( letter ) - .appendTo( alphabet ); - } - if (options.caseSensitive) { - for (var i = 0; i < 26; i++) { - var letter = String.fromCharCode(97 + i); - - $('') - .data('letter', letter) - .data('match-count', bins[letter] || 0) - .addClass(!bins[letter] ? 'empty' : '') - .html(letter) - .appendTo(alphabet); - } - } - - $('
') - .appendTo( alphabet ); +function draw(table, alphabet, options) { + alphabet.empty(); + alphabet.append('Search: '); + var columnData = table.column(options.column).data(); + var bins = bin(columnData, options); + $('') + .data('letter', '') + .data('match-count', columnData.length) + .html('None') + .appendTo(alphabet); + if (options.numbers) { + for (var i = 0; i < 10; i++) { + var letter = String.fromCharCode(48 + i); + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + } + for (var i = 0; i < 26; i++) { + var letter = String.fromCharCode(65 + i); + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + if (options.caseSensitive) { + for (var i = 0; i < 26; i++) { + var letter = String.fromCharCode(97 + i); + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + } + $('
').appendTo(alphabet); } - - -$.fn.dataTable.AlphabetSearch = function ( context ) { - var table = new $.fn.dataTable.Api( context ); - var alphabet = $('
'); - var options = $.extend({ - column: 0, - caseSensitive: false, - numbers: false - }, table.init().alphabet); - - draw( table, alphabet, options ); - - // Trigger a search - alphabet.on( 'click', 'span', function () { - alphabet.find( '.active' ).removeClass( 'active' ); - $(this).addClass( 'active' ); - - table - .alphabetSearch( $(this).data('letter') ) - .draw(); - } ); - - // Mouse events to show helper information - alphabet - .on( 'mouseenter', 'span', function () { - alphabet - .find('div.alphabetInfo') - .css( { - opacity: 1, - left: $(this).position().left, - width: $(this).width() - } ) - .html( $(this).data('match-count') ); - } ) - .on( 'mouseleave', 'span', function () { - alphabet - .find('div.alphabetInfo') - .css('opacity', 0); - } ); - - // API method to get the alphabet container node - this.node = function () { - return alphabet; - }; +DataTable.AlphabetSearch = function (context) { + var table = new DataTable.Api(context); + var alphabet = $('
'); + var options = $.extend({ + column: 0, + caseSensitive: false, + numbers: false, + }, table.init().alphabet); + draw(table, alphabet, options); + context._alphabet = alphabet; + context._alphabetOptions = options; + // Trigger a search + alphabet.on('click', 'span', function () { + alphabet.find('.active').removeClass('active'); + $(this).addClass('active'); + table.alphabetSearch($(this).data('letter')).draw(); + }); + // Mouse events to show helper information + alphabet + .on('mouseenter', 'span', function () { + alphabet + .find('div.alphabetInfo') + .css({ + opacity: 1, + left: $(this).position().left, + width: $(this).width(), + }) // unsure why it needs any + .html($(this).data('match-count')); + }) + .on('mouseleave', 'span', function () { + alphabet.find('div.alphabetInfo').css('opacity', 0); + }); }; - -$.fn.DataTable.AlphabetSearch = $.fn.dataTable.AlphabetSearch; - // Register a search plug-in -$.fn.dataTable.ext.feature.push( { - fnInit: function ( settings ) { - var search = new $.fn.dataTable.AlphabetSearch( settings ); - return search.node(); - }, - cFeature: 'A' -} ); - +DataTable.ext.feature.push({ + fnInit: function (settings) { + var search = new DataTable.AlphabetSearch(settings); + return search.node(); + }, + cFeature: 'A', +}); -}()); +return DataTable; +})); diff --git a/features/alphabetSearch/dataTables.alphabetSearch.min.js b/features/alphabetSearch/dataTables.alphabetSearch.min.js index 798fab1..7b80644 100644 --- a/features/alphabetSearch/dataTables.alphabetSearch.min.js +++ b/features/alphabetSearch/dataTables.alphabetSearch.min.js @@ -1,4 +1,2 @@ -/*! AlphabetSearch for DataTables v1.0.0 - * 2014 SpryMedia Ltd - datatables.net/license - */ -!function(){function n(a,t,e){t.empty(),t.append("Search: ");var a=a.column(e.column).data(),n=function(a,t){for(var e,n={},i=0,r=a.length;i/g,"").charAt(0):a[i].toString().replace(/<.*?>/g,"").charAt(0).toUpperCase()]?n[e]++:n[e]=1;return n}(a,e);if($('').data("letter","").data("match-count",a.length).html("None").appendTo(t),e.numbers)for(var i=0;i<10;i++){var r=String.fromCharCode(48+i);$("").data("letter",r).data("match-count",n[r]||0).addClass(n[r]?"":"empty").html(r).appendTo(t)}for(i=0;i<26;i++){r=String.fromCharCode(65+i);$("").data("letter",r).data("match-count",n[r]||0).addClass(n[r]?"":"empty").html(r).appendTo(t)}if(e.caseSensitive)for(i=0;i<26;i++){r=String.fromCharCode(97+i);$("").data("letter",r).data("match-count",n[r]||0).addClass(n[r]?"":"empty").html(r).appendTo(t)}$('
').appendTo(t)}$.fn.dataTable.Api.register("alphabetSearch()",function(t){return this.iterator("table",function(a){a.alphabetSearch=t}),this}),$.fn.dataTable.Api.register("alphabetSearch.recalc()",function(a){return this.iterator("table",function(a){n(new $.fn.dataTable.Api(a),$("div.alphabet",this.table().container()))}),this}),$.fn.dataTable.ext.search.push(function(a,t){if(!a.alphabetSearch)return!0;var e;if(void 0!==a.oInit.alphabet?(e=void 0!==a.oInit.alphabet.column?a.oInit.alphabet.column:0,void 0!==a.oInit.alphabet.caseSensitive&&a.oInit.alphabet.caseSensitive):(e=0,!1)){if(t[e].charAt(0)===a.alphabetSearch)return!0}else if(t[e].charAt(0).toUpperCase()===a.alphabetSearch)return!0;return!1}),$.fn.dataTable.AlphabetSearch=function(a){var t=new $.fn.dataTable.Api(a),e=$('
'),a=$.extend({column:0,caseSensitive:!1,numbers:!1},t.init().alphabet);n(t,e,a),e.on("click","span",function(){e.find(".active").removeClass("active"),$(this).addClass("active"),t.alphabetSearch($(this).data("letter")).draw()}),e.on("mouseenter","span",function(){e.find("div.alphabetInfo").css({opacity:1,left:$(this).position().left,width:$(this).width()}).html($(this).data("match-count"))}).on("mouseleave","span",function(){e.find("div.alphabetInfo").css("opacity",0)}),this.node=function(){return e}},$.fn.DataTable.AlphabetSearch=$.fn.dataTable.AlphabetSearch,$.fn.dataTable.ext.feature.push({fnInit:function(a){return new $.fn.dataTable.AlphabetSearch(a).node()},cFeature:"A"})}(); \ No newline at end of file +/*! © SpryMedia Ltd - datatables.net/license */ +!function(a){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(t){return a(t,window,document)}):"object"==typeof exports?module.exports=function(t,e){return t=t||window,(e=e||("undefined"!=typeof window?require("jquery"):require("jquery")(t))).fn.dataTable||require("datatables.net")(t,e),a(e,0,t.document)}:a(jQuery,window,document)}(function(o,t,e,r){"use strict";var i=o.fn.dataTable;function c(t,e,a){e.empty(),e.append("Search: ");var t=t.column(a.column).data(),n=function(t,e){for(var a,n={},r=0,i=t.length;r/g,"").charAt(0):t[r].toString().replace(/<.*?>/g,"").charAt(0).toUpperCase()]?n[a]++:n[a]=1;return n}(t,a);if(o('').data("letter","").data("match-count",t.length).html("None").appendTo(e),a.numbers)for(var r=0;r<10;r++){var i=String.fromCharCode(48+r);o("").data("letter",i).data("match-count",n[i]||0).addClass(n[i]?"":"empty").html(i).appendTo(e)}for(r=0;r<26;r++){i=String.fromCharCode(65+r);o("").data("letter",i).data("match-count",n[i]||0).addClass(n[i]?"":"empty").html(i).appendTo(e)}if(a.caseSensitive)for(r=0;r<26;r++){i=String.fromCharCode(97+r);o("").data("letter",i).data("match-count",n[i]||0).addClass(n[i]?"":"empty").html(i).appendTo(e)}o('
').appendTo(e)}return i.Api.register("alphabetSearch()",function(e){return this.iterator("table",function(t){t.alphabetSearch=e}),this}),i.Api.register("alphabetSearch.recalc()",function(){return this.iterator("table",function(t){c(new i.Api(t),t._alphabet,t._alphabetOptions)}),this}),i.Api.register("alphabetSearch.node()",function(){return this._context.length?this._context._alphabet:null}),i.ext.search.push(function(t,e){if(!t.alphabetSearch)return!0;var a=0,n=!1;if(t.oInit.alphabet!==r&&(a=t.oInit.alphabet.column!==r?t.oInit.alphabet.column:0,n=t.oInit.alphabet.caseSensitive!==r&&t.oInit.alphabet.caseSensitive),n){if(e[a].charAt(0)===t.alphabetSearch)return!0}else if(e[a].charAt(0).toUpperCase()===t.alphabetSearch)return!0;return!1}),i.AlphabetSearch=function(t){var e=new i.Api(t),a=o('
'),n=o.extend({column:0,caseSensitive:!1,numbers:!1},e.init().alphabet);c(e,a,n),t._alphabet=a,t._alphabetOptions=n,a.on("click","span",function(){a.find(".active").removeClass("active"),o(this).addClass("active"),e.alphabetSearch(o(this).data("letter")).draw()}),a.on("mouseenter","span",function(){a.find("div.alphabetInfo").css({opacity:1,left:o(this).position().left,width:o(this).width()}).html(o(this).data("match-count"))}).on("mouseleave","span",function(){a.find("div.alphabetInfo").css("opacity",0)})},i.ext.feature.push({fnInit:function(t){return new i.AlphabetSearch(t).node()},cFeature:"A"}),i}); \ No newline at end of file diff --git a/features/alphabetSearch/dataTables.alphabetSearch.min.mjs b/features/alphabetSearch/dataTables.alphabetSearch.min.mjs new file mode 100644 index 0000000..a224cec --- /dev/null +++ b/features/alphabetSearch/dataTables.alphabetSearch.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";function bin(a,t){for(var e,n={},r=0,i=a.length;r/g,"").charAt(0):a[r].toString().replace(/<.*?>/g,"").charAt(0).toUpperCase()]?n[e]++:n[e]=1;return n}function draw(a,t,e){t.empty(),t.append("Search: ");var a=a.column(e.column).data(),n=bin(a,e);if($('').data("letter","").data("match-count",a.length).html("None").appendTo(t),e.numbers)for(var r=0;r<10;r++){var i=String.fromCharCode(48+r);$("").data("letter",i).data("match-count",n[i]||0).addClass(n[i]?"":"empty").html(i).appendTo(t)}for(r=0;r<26;r++){i=String.fromCharCode(65+r);$("").data("letter",i).data("match-count",n[i]||0).addClass(n[i]?"":"empty").html(i).appendTo(t)}if(e.caseSensitive)for(r=0;r<26;r++){i=String.fromCharCode(97+r);$("").data("letter",i).data("match-count",n[i]||0).addClass(n[i]?"":"empty").html(i).appendTo(t)}$('
').appendTo(t)}DataTable.Api.register("alphabetSearch()",function(t){return this.iterator("table",function(a){a.alphabetSearch=t}),this}),DataTable.Api.register("alphabetSearch.recalc()",function(){return this.iterator("table",function(a){draw(new DataTable.Api(a),a._alphabet,a._alphabetOptions)}),this}),DataTable.Api.register("alphabetSearch.node()",function(){return this._context.length?this._context._alphabet:null}),DataTable.ext.search.push(function(a,t){if(!a.alphabetSearch)return!0;var e=0,n=!1;if(void 0!==a.oInit.alphabet&&(e=void 0!==a.oInit.alphabet.column?a.oInit.alphabet.column:0,n=void 0!==a.oInit.alphabet.caseSensitive&&a.oInit.alphabet.caseSensitive),n){if(t[e].charAt(0)===a.alphabetSearch)return!0}else if(t[e].charAt(0).toUpperCase()===a.alphabetSearch)return!0;return!1}),DataTable.AlphabetSearch=function(a){var t=new DataTable.Api(a),e=$('
'),n=$.extend({column:0,caseSensitive:!1,numbers:!1},t.init().alphabet);draw(t,e,n),a._alphabet=e,a._alphabetOptions=n,e.on("click","span",function(){e.find(".active").removeClass("active"),$(this).addClass("active"),t.alphabetSearch($(this).data("letter")).draw()}),e.on("mouseenter","span",function(){e.find("div.alphabetInfo").css({opacity:1,left:$(this).position().left,width:$(this).width()}).html($(this).data("match-count"))}).on("mouseleave","span",function(){e.find("div.alphabetInfo").css("opacity",0)})},DataTable.ext.feature.push({fnInit:function(a){return new DataTable.AlphabetSearch(a).node()},cFeature:"A"});export default DataTable; \ No newline at end of file diff --git a/features/alphabetSearch/dataTables.alphabetSearch.mjs b/features/alphabetSearch/dataTables.alphabetSearch.mjs new file mode 100644 index 0000000..e76eaa3 --- /dev/null +++ b/features/alphabetSearch/dataTables.alphabetSearch.mjs @@ -0,0 +1,177 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary AlphabetSearch + * @description Show an set of alphabet buttons alongside a table providing + * search input options + * @version 1.1.0 + * @file dataTables.alphabetSearch.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright SpryMedia Ltd. + * + * License MIT - http://datatables.net/license/mit + * + * For more detailed information please see: + * http://datatables.net/blog/2014-09-22 + */ +// Search function +DataTable.Api.register('alphabetSearch()', function (searchTerm) { + this.iterator('table', function (context) { + context.alphabetSearch = searchTerm; + }); + return this; +}); +// Recalculate the alphabet display for updated data +DataTable.Api.register('alphabetSearch.recalc()', function () { + this.iterator('table', function (context) { + draw(new DataTable.Api(context), context._alphabet, context._alphabetOptions); + }); + return this; +}); +DataTable.Api.register('alphabetSearch.node()', function () { + return this._context.length + ? this._context._alphabet + : null; + ; +}); +// Search plug-in +DataTable.ext.search.push(function (context, searchData) { + // Ensure that there is a search applied to this table before running it + if (!context.alphabetSearch) { + return true; + } + var columnId = 0; + var caseSensitive = false; + if (context.oInit.alphabet !== undefined) { + columnId = + context.oInit.alphabet.column !== undefined + ? context.oInit.alphabet.column + : 0; + caseSensitive = + context.oInit.alphabet.caseSensitive !== undefined + ? context.oInit.alphabet.caseSensitive + : false; + } + if (caseSensitive) { + if (searchData[columnId].charAt(0) === context.alphabetSearch) { + return true; + } + } + else { + if (searchData[columnId].charAt(0).toUpperCase() === context.alphabetSearch) { + return true; + } + } + return false; +}); +// Private support methods +function bin(data, options) { + var letter, bins = {}; + for (var i = 0, ien = data.length; i < ien; i++) { + if (options.caseSensitive) { + letter = data[i].toString().replace(/<.*?>/g, '').charAt(0); + } + else { + letter = data[i].toString().replace(/<.*?>/g, '').charAt(0).toUpperCase(); + } + if (bins[letter]) { + bins[letter]++; + } + else { + bins[letter] = 1; + } + } + return bins; +} +function draw(table, alphabet, options) { + alphabet.empty(); + alphabet.append('Search: '); + var columnData = table.column(options.column).data(); + var bins = bin(columnData, options); + $('') + .data('letter', '') + .data('match-count', columnData.length) + .html('None') + .appendTo(alphabet); + if (options.numbers) { + for (var i = 0; i < 10; i++) { + var letter = String.fromCharCode(48 + i); + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + } + for (var i = 0; i < 26; i++) { + var letter = String.fromCharCode(65 + i); + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + if (options.caseSensitive) { + for (var i = 0; i < 26; i++) { + var letter = String.fromCharCode(97 + i); + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + } + $('
').appendTo(alphabet); +} +DataTable.AlphabetSearch = function (context) { + var table = new DataTable.Api(context); + var alphabet = $('
'); + var options = $.extend({ + column: 0, + caseSensitive: false, + numbers: false, + }, table.init().alphabet); + draw(table, alphabet, options); + context._alphabet = alphabet; + context._alphabetOptions = options; + // Trigger a search + alphabet.on('click', 'span', function () { + alphabet.find('.active').removeClass('active'); + $(this).addClass('active'); + table.alphabetSearch($(this).data('letter')).draw(); + }); + // Mouse events to show helper information + alphabet + .on('mouseenter', 'span', function () { + alphabet + .find('div.alphabetInfo') + .css({ + opacity: 1, + left: $(this).position().left, + width: $(this).width(), + }) // unsure why it needs any + .html($(this).data('match-count')); + }) + .on('mouseleave', 'span', function () { + alphabet.find('div.alphabetInfo').css('opacity', 0); + }); +}; +// Register a search plug-in +DataTable.ext.feature.push({ + fnInit: function (settings) { + var search = new DataTable.AlphabetSearch(settings); + return search.node(); + }, + cFeature: 'A', +}); + + +export default DataTable; diff --git a/features/alphabetSearch/src/dataTables.alphabetSearch.ts b/features/alphabetSearch/src/dataTables.alphabetSearch.ts new file mode 100644 index 0000000..211c4d6 --- /dev/null +++ b/features/alphabetSearch/src/dataTables.alphabetSearch.ts @@ -0,0 +1,238 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +/** + * @summary AlphabetSearch + * @description Show an set of alphabet buttons alongside a table providing + * search input options + * @version 1.1.0 + * @file dataTables.alphabetSearch.js + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * @contact www.sprymedia.co.uk/contact + * @copyright Copyright SpryMedia Ltd. + * + * License MIT - http://datatables.net/license/mit + * + * For more detailed information please see: + * http://datatables.net/blog/2014-09-22 + */ + +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface DataTablesStatic { + /** Show an set of alphabet buttons alongside a table providing search input options */ + AlphabetSearch(settings: any): void; + } + + interface Config { + alphabet?: { + column: number; + caseSensitive: boolean; + numbers: boolean; + }; + } + + interface Api { + alphabetSearch: ApiAlphabet; + } + + interface ApiAlphabet { + (searchTerm: string): ApiAlphabetMethods; + } + + interface ApiAlphabetMethods extends Api { + node(): JQuery | null; + + recalc(): Api; + } +} + +// Search function +DataTable.Api.register('alphabetSearch()', function (searchTerm) { + this.iterator('table', function (context) { + context.alphabetSearch = searchTerm; + }); + + return this; +}); + +// Recalculate the alphabet display for updated data +DataTable.Api.register('alphabetSearch.recalc()', function () { + this.iterator('table', function (context) { + draw( + new DataTable.Api(context), + context._alphabet, + context._alphabetOptions + ); + }); + + return this; +}); + +DataTable.Api.register('alphabetSearch.node()', function () { + return this._context.length + ? this._context._alphabet + : null;; +}); + +// Search plug-in +DataTable.ext.search.push(function (context, searchData) { + // Ensure that there is a search applied to this table before running it + if (!context.alphabetSearch) { + return true; + } + + var columnId = 0; + var caseSensitive = false; + + if (context.oInit.alphabet !== undefined) { + columnId = + context.oInit.alphabet.column !== undefined + ? context.oInit.alphabet.column + : 0; + caseSensitive = + context.oInit.alphabet.caseSensitive !== undefined + ? context.oInit.alphabet.caseSensitive + : false; + } + + if (caseSensitive) { + if (searchData[columnId].charAt(0) === context.alphabetSearch) { + return true; + } + } + else { + if ( + searchData[columnId].charAt(0).toUpperCase() === context.alphabetSearch + ) { + return true; + } + } + + return false; +}); + +// Private support methods +function bin(data, options) { + var letter, + bins = {}; + + for (var i = 0, ien = data.length; i < ien; i++) { + if (options.caseSensitive) { + letter = data[i].toString().replace(/<.*?>/g, '').charAt(0); + } + else { + letter = data[i].toString().replace(/<.*?>/g, '').charAt(0).toUpperCase(); + } + if (bins[letter]) { + bins[letter]++; + } + else { + bins[letter] = 1; + } + } + + return bins; +} + +function draw(table, alphabet, options) { + alphabet.empty(); + alphabet.append('Search: '); + + var columnData = table.column(options.column).data(); + var bins = bin(columnData, options); + + $('') + .data('letter', '') + .data('match-count', columnData.length) + .html('None') + .appendTo(alphabet); + + if (options.numbers) { + for (var i = 0; i < 10; i++) { + var letter = String.fromCharCode(48 + i); + + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + } + for (var i = 0; i < 26; i++) { + var letter = String.fromCharCode(65 + i); + + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + if (options.caseSensitive) { + for (var i = 0; i < 26; i++) { + var letter = String.fromCharCode(97 + i); + + $('') + .data('letter', letter) + .data('match-count', bins[letter] || 0) + .addClass(!bins[letter] ? 'empty' : '') + .html(letter) + .appendTo(alphabet); + } + } + + $('
').appendTo(alphabet); +} + +DataTable.AlphabetSearch = function (context) { + var table = new DataTable.Api(context); + var alphabet = $('
'); + var options = $.extend( + { + column: 0, + caseSensitive: false, + numbers: false, + }, + table.init().alphabet + ); + + draw(table, alphabet, options); + + context._alphabet = alphabet; + context._alphabetOptions = options; + + // Trigger a search + alphabet.on('click', 'span', function () { + alphabet.find('.active').removeClass('active'); + $(this).addClass('active'); + + table.alphabetSearch($(this).data('letter')).draw(); + }); + + // Mouse events to show helper information + alphabet + .on('mouseenter', 'span', function () { + alphabet + .find('div.alphabetInfo') + .css({ + opacity: 1, + left: $(this).position().left, + width: $(this).width(), + } as any) // unsure why it needs any + .html($(this).data('match-count')); + }) + .on('mouseleave', 'span', function () { + alphabet.find('div.alphabetInfo').css('opacity', 0); + }); +}; + +// Register a search plug-in +DataTable.ext.feature.push({ + fnInit: function (settings) { + var search = new DataTable.AlphabetSearch(settings); + return search.node(); + }, + cFeature: 'A', +}); diff --git a/features/conditionalPageLength/dataTables.conditionalPageLength.d.ts b/features/conditionalPageLength/dataTables.conditionalPageLength.d.ts new file mode 100644 index 0000000..ad6df40 --- /dev/null +++ b/features/conditionalPageLength/dataTables.conditionalPageLength.d.ts @@ -0,0 +1,7 @@ +/*! © SpryMedia Ltd, Garrett Hyder - datatables.net/license */ +declare module 'datatables.net' { + interface Config { + conditionalPageLength: boolean; + } +} +export {}; diff --git a/features/conditionalPageLength/dataTables.conditionalPageLength.js b/features/conditionalPageLength/dataTables.conditionalPageLength.js index cc68d78..c703ffc 100644 --- a/features/conditionalPageLength/dataTables.conditionalPageLength.js +++ b/features/conditionalPageLength/dataTables.conditionalPageLength.js @@ -1,10 +1,48 @@ +/*! © SpryMedia Ltd, Garrett Hyder - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + /** * @summary ConditionalPageLength * @description Hide the page length control when the amount of pages is <= 1 * @version 1.0.0 - * @file dataTables.conditionalPageLength.js * @author Garrett Hyder (https://github.com/garretthyder) - * @contact garrett.m.hyder@gmail.com * @copyright Copyright 2020 Garrett Hyder * * License MIT - http://datatables.net/license/mit @@ -34,76 +72,68 @@ * conditionalPageLength: { * conditionalOptions: true * } - * }); + * }); */ - -(function(window, document, $) { - $(document).on('init.dt', function(e, dtSettings) { - if ( e.namespace !== 'dt' ) { - return; - } - - var options = dtSettings.oInit.conditionalPageLength || $.fn.dataTable.defaults.conditionalPageLength, - lengthMenu = dtSettings.aLengthMenu || $.fn.dataTable.defaults.lengthMenu, - lengthMenuValues = Array.isArray(lengthMenu[0]) ? lengthMenu[0] : lengthMenu; - - lengthMenuValues = lengthMenuValues.filter(function(n) { return n > 0 }); - var smallestLength = Math.min.apply(Math, lengthMenuValues); - - if ($.isPlainObject(options) || options === true) { - var config = $.isPlainObject(options) ? options : {}, - api = new $.fn.dataTable.Api(dtSettings), - speed = 'slow', - conditionalPageLength = function(e) { - var $paging = $(api.table().container()).find('div.dataTables_length'), - pages = api.page.info().pages, - size = api.rows({search:'applied'}).count(); - - if (e instanceof $.Event) { - if (pages <= 1 && size <= smallestLength) { - if (config.style === 'fade') { - $paging.stop().fadeTo(speed, 0); - } - else { - $paging.css('visibility', 'hidden'); - } - } - else { - if (config.style === 'fade') { - $paging.stop().fadeTo(speed, 1); - } - else { - $paging.css('visibility', ''); - } - } +$(document).on('init.dt', function (e, dtSettings) { + if (e.namespace !== 'dt') { + return; + } + var options = dtSettings.oInit.conditionalPageLength || + DataTable.defaults.conditionalPageLength, lengthMenu = dtSettings.aLengthMenu || DataTable.defaults.lengthMenu, lengthMenuValues = Array.isArray(lengthMenu[0]) + ? lengthMenu[0] + : lengthMenu; + lengthMenuValues = lengthMenuValues.filter(function (n) { + return n > 0; + }); + var smallestLength = Math.min.apply(Math, lengthMenuValues); + if ($.isPlainObject(options) || options === true) { + var config = $.isPlainObject(options) ? options : {}, api = new DataTable.Api(dtSettings), speed = 500, conditionalPageLength = function (e) { + var $paging = $(api.table().container()).find('div.dataTables_length'), pages = api.page.info().pages, size = api.rows({ search: 'applied' }).count(); + if (e instanceof $.Event) { + if (pages <= 1 && size <= smallestLength) { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 0); } - else if (pages <= 1 && size <= smallestLength) { - if (config.style === 'fade') { - $paging.css('opacity', 0); - } - else { - $paging.css('visibility', 'hidden'); - } + else { + $paging.css('visibility', 'hidden'); } - - if (config.conditionalOptions) { - $paging.find('select option').each(function(index) { - if ($(this).attr('value') > size) { - $(this).hide(); - } else { - $(this).show(); - } - }); + } + else { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 1); } - }; - - if ( config.speed !== undefined ) { - speed = config.speed; + else { + $paging.css('visibility', ''); + } + } + } + else if (pages <= 1 && size <= smallestLength) { + if (config.style === 'fade') { + $paging.css('opacity', 0); + } + else { + $paging.css('visibility', 'hidden'); + } } + if (config.conditionalOptions) { + $paging.find('select option').each(function (index) { + if (parseInt($(this).attr('value'), 10) > size) { + $(this).hide(); + } + else { + $(this).show(); + } + }); + } + }; + if (config.speed !== undefined) { + speed = config.speed; + } + conditionalPageLength(null); + api.on('draw.dt', conditionalPageLength); + } +}); - conditionalPageLength(); - api.on('draw.dt', conditionalPageLength); - } - }); -})(window, document, jQuery); \ No newline at end of file +return DataTable; +})); diff --git a/features/conditionalPageLength/dataTables.conditionalPageLength.min.js b/features/conditionalPageLength/dataTables.conditionalPageLength.min.js new file mode 100644 index 0000000..c5aaeeb --- /dev/null +++ b/features/conditionalPageLength/dataTables.conditionalPageLength.min.js @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd, Garrett Hyder - datatables.net/license */ +!function(n){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return n(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,(t=t||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,t),n(t,0,e.document)}:n(jQuery,window,document)}(function(r,e,t,i){"use strict";var u=r.fn.dataTable;return r(t).on("init.dt",function(e,t){var a,o,d,s,n;"dt"===e.namespace&&(e=t.oInit.conditionalPageLength||u.defaults.conditionalPageLength,n=t.aLengthMenu||u.defaults.lengthMenu,n=(n=Array.isArray(n[0])?n[0]:n).filter(function(e){return 0i?r(this).hide():r(this).show()})})(null),d.on("draw.dt",n))}),u}); \ No newline at end of file diff --git a/features/conditionalPageLength/dataTables.conditionalPageLength.min.mjs b/features/conditionalPageLength/dataTables.conditionalPageLength.min.mjs new file mode 100644 index 0000000..a92f53c --- /dev/null +++ b/features/conditionalPageLength/dataTables.conditionalPageLength.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd, Garrett Hyder - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";$(document).on("init.dt",function(t,a){var n,s,o,l,e;"dt"===t.namespace&&(t=a.oInit.conditionalPageLength||DataTable.defaults.conditionalPageLength,e=a.aLengthMenu||DataTable.defaults.lengthMenu,e=(e=Array.isArray(e[0])?e[0]:e).filter(function(t){return 0i?$(this).hide():$(this).show()})})(null),o.on("draw.dt",e))});export default DataTable; \ No newline at end of file diff --git a/features/conditionalPageLength/dataTables.conditionalPageLength.mjs b/features/conditionalPageLength/dataTables.conditionalPageLength.mjs new file mode 100644 index 0000000..094918b --- /dev/null +++ b/features/conditionalPageLength/dataTables.conditionalPageLength.mjs @@ -0,0 +1,104 @@ +/*! © SpryMedia Ltd, Garrett Hyder - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary ConditionalPageLength + * @description Hide the page length control when the amount of pages is <= 1 + * @version 1.0.0 + * @author Garrett Hyder (https://github.com/garretthyder) + * @copyright Copyright 2020 Garrett Hyder + * + * License MIT - http://datatables.net/license/mit + * + * This feature plugin for DataTables hides the page length control when the amount + * of pages is <= 1. The control can either appear / disappear or fade in / out. + * + * Based off conditionalPaging by Matthew Hasbach (https://github.com/mjhasbach) + * Reference: https://github.com/DataTables/Plugins/blob/master/features/conditionalPaging/dataTables.conditionalPaging.js + * + * @example + * $('#myTable').DataTable({ + * conditionalPageLength: true + * }); + * + * @example + * $('#myTable').DataTable({ + * conditionalPageLength: { + * style: 'fade', + * speed: 500 // optional + * } + * }); + * + * Conditionally hide the Page Length options that are less than the current result size. + * @example + * $('#myTable').DataTable({ + * conditionalPageLength: { + * conditionalOptions: true + * } + * }); + */ +$(document).on('init.dt', function (e, dtSettings) { + if (e.namespace !== 'dt') { + return; + } + var options = dtSettings.oInit.conditionalPageLength || + DataTable.defaults.conditionalPageLength, lengthMenu = dtSettings.aLengthMenu || DataTable.defaults.lengthMenu, lengthMenuValues = Array.isArray(lengthMenu[0]) + ? lengthMenu[0] + : lengthMenu; + lengthMenuValues = lengthMenuValues.filter(function (n) { + return n > 0; + }); + var smallestLength = Math.min.apply(Math, lengthMenuValues); + if ($.isPlainObject(options) || options === true) { + var config = $.isPlainObject(options) ? options : {}, api = new DataTable.Api(dtSettings), speed = 500, conditionalPageLength = function (e) { + var $paging = $(api.table().container()).find('div.dataTables_length'), pages = api.page.info().pages, size = api.rows({ search: 'applied' }).count(); + if (e instanceof $.Event) { + if (pages <= 1 && size <= smallestLength) { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + else { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 1); + } + else { + $paging.css('visibility', ''); + } + } + } + else if (pages <= 1 && size <= smallestLength) { + if (config.style === 'fade') { + $paging.css('opacity', 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + if (config.conditionalOptions) { + $paging.find('select option').each(function (index) { + if (parseInt($(this).attr('value'), 10) > size) { + $(this).hide(); + } + else { + $(this).show(); + } + }); + } + }; + if (config.speed !== undefined) { + speed = config.speed; + } + conditionalPageLength(null); + api.on('draw.dt', conditionalPageLength); + } +}); + + +export default DataTable; diff --git a/features/conditionalPageLength/src/dataTables.conditionalPageLength.ts b/features/conditionalPageLength/src/dataTables.conditionalPageLength.ts new file mode 100644 index 0000000..b5b2455 --- /dev/null +++ b/features/conditionalPageLength/src/dataTables.conditionalPageLength.ts @@ -0,0 +1,124 @@ +/*! © SpryMedia Ltd, Garrett Hyder - datatables.net/license */ + +/** + * @summary ConditionalPageLength + * @description Hide the page length control when the amount of pages is <= 1 + * @version 1.0.0 + * @author Garrett Hyder (https://github.com/garretthyder) + * @copyright Copyright 2020 Garrett Hyder + * + * License MIT - http://datatables.net/license/mit + * + * This feature plugin for DataTables hides the page length control when the amount + * of pages is <= 1. The control can either appear / disappear or fade in / out. + * + * Based off conditionalPaging by Matthew Hasbach (https://github.com/mjhasbach) + * Reference: https://github.com/DataTables/Plugins/blob/master/features/conditionalPaging/dataTables.conditionalPaging.js + * + * @example + * $('#myTable').DataTable({ + * conditionalPageLength: true + * }); + * + * @example + * $('#myTable').DataTable({ + * conditionalPageLength: { + * style: 'fade', + * speed: 500 // optional + * } + * }); + * + * Conditionally hide the Page Length options that are less than the current result size. + * @example + * $('#myTable').DataTable({ + * conditionalPageLength: { + * conditionalOptions: true + * } + * }); + */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface Config { + conditionalPageLength: boolean; + } +} + +$(document).on('init.dt', function (e, dtSettings) { + if (e.namespace !== 'dt') { + return; + } + + var options = + dtSettings.oInit.conditionalPageLength || + DataTable.defaults.conditionalPageLength, + lengthMenu = dtSettings.aLengthMenu || DataTable.defaults.lengthMenu, + lengthMenuValues = Array.isArray(lengthMenu[0]) + ? lengthMenu[0] + : lengthMenu; + + lengthMenuValues = lengthMenuValues.filter(function (n) { + return n > 0; + }); + + var smallestLength = Math.min.apply(Math, lengthMenuValues); + + if ($.isPlainObject(options) || options === true) { + var config = $.isPlainObject(options) ? options : {}, + api = new DataTable.Api(dtSettings), + speed = 500, + conditionalPageLength = function (e) { + var $paging = $(api.table().container()).find('div.dataTables_length'), + pages = api.page.info().pages, + size = api.rows({ search: 'applied' }).count(); + + if (e instanceof $.Event) { + if (pages <= 1 && size <= smallestLength) { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + else { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 1); + } + else { + $paging.css('visibility', ''); + } + } + } + else if (pages <= 1 && size <= smallestLength) { + if (config.style === 'fade') { + $paging.css('opacity', 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + + if (config.conditionalOptions) { + $paging.find('select option').each(function (index) { + if (parseInt($(this).attr('value')!, 10) > size) { + $(this).hide(); + } + else { + $(this).show(); + } + }); + } + }; + + if (config.speed !== undefined) { + speed = config.speed; + } + + conditionalPageLength(null); + + api.on('draw.dt', conditionalPageLength); + } +}); diff --git a/features/conditionalPaging/dataTables.conditionalPaging.d.ts b/features/conditionalPaging/dataTables.conditionalPaging.d.ts new file mode 100644 index 0000000..62faea3 --- /dev/null +++ b/features/conditionalPaging/dataTables.conditionalPaging.d.ts @@ -0,0 +1,7 @@ +/*! © SpryMedia Ltd, Matthew Hasbach - datatables.net/license */ +declare module 'datatables.net' { + interface Config { + conditionalPaging: boolean; + } +} +export {}; diff --git a/features/conditionalPaging/dataTables.conditionalPaging.js b/features/conditionalPaging/dataTables.conditionalPaging.js index 4fb7fae..b76d0ca 100644 --- a/features/conditionalPaging/dataTables.conditionalPaging.js +++ b/features/conditionalPaging/dataTables.conditionalPaging.js @@ -1,10 +1,48 @@ +/*! © SpryMedia Ltd, Matthew Hasbach - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + /** * @summary ConditionalPaging * @description Hide paging controls when the amount of pages is <= 1 * @version 1.0.0 - * @file dataTables.conditionalPaging.js * @author Matthew Hasbach (https://github.com/mjhasbach) - * @contact hasbach.git@gmail.com * @copyright Copyright 2015 Matthew Hasbach * * License MIT - http://datatables.net/license/mit @@ -25,58 +63,50 @@ * } * }); */ - -(function(window, document, $) { - $(document).on('init.dt', function(e, dtSettings) { - if ( e.namespace !== 'dt' ) { - return; - } - - var options = dtSettings.oInit.conditionalPaging || $.fn.dataTable.defaults.conditionalPaging; - - if ($.isPlainObject(options) || options === true) { - var config = $.isPlainObject(options) ? options : {}, - api = new $.fn.dataTable.Api(dtSettings), - speed = 'slow', - conditionalPaging = function(e) { - var $paging = $(api.table().container()).find('div.dataTables_paginate'), - pages = api.page.info().pages; - - if (e instanceof $.Event) { - if (pages <= 1) { - if (config.style === 'fade') { - $paging.stop().fadeTo(speed, 0); - } - else { - $paging.css('visibility', 'hidden'); - } - } - else { - if (config.style === 'fade') { - $paging.stop().fadeTo(speed, 1); - } - else { - $paging.css('visibility', ''); - } - } +$(document).on('init.dt', function (e, dtSettings) { + if (e.namespace !== 'dt') { + return; + } + var options = dtSettings.oInit.conditionalPaging || + DataTable.defaults.conditionalPaging; + if ($.isPlainObject(options) || options === true) { + var config = $.isPlainObject(options) ? options : {}, api = new DataTable.Api(dtSettings), speed = 500, conditionalPaging = function (e) { + var $paging = $(api.table().container()).find('div.dataTables_paginate'), pages = api.page.info().pages; + if (e instanceof $.Event) { + if (pages <= 1) { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 0); } - else if (pages <= 1) { - if (config.style === 'fade') { - $paging.css('opacity', 0); - } - else { - $paging.css('visibility', 'hidden'); - } + else { + $paging.css('visibility', 'hidden'); } - }; - - if ( config.speed !== undefined ) { - speed = config.speed; + } + else { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 1); + } + else { + $paging.css('visibility', ''); + } + } + } + else if (pages <= 1) { + if (config.style === 'fade') { + $paging.css('opacity', 0); + } + else { + $paging.css('visibility', 'hidden'); + } } + }; + if (config.speed !== undefined) { + speed = config.speed; + } + conditionalPaging(null); + api.on('draw.dt', conditionalPaging); + } +}); - conditionalPaging(); - api.on('draw.dt', conditionalPaging); - } - }); -})(window, document, jQuery); +return DataTable; +})); diff --git a/features/conditionalPaging/dataTables.conditionalPaging.min.js b/features/conditionalPaging/dataTables.conditionalPaging.min.js new file mode 100644 index 0000000..fd0d365 --- /dev/null +++ b/features/conditionalPaging/dataTables.conditionalPaging.min.js @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd, Matthew Hasbach - datatables.net/license */ +!function(i){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return i(e,window,document)}):"object"==typeof exports?module.exports=function(e,n){return e=e||window,(n=n||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,n),i(n,0,e.document)}:i(jQuery,window,document)}(function(o,e,n,i){"use strict";var s=o.fn.dataTable;return o(n).on("init.dt",function(e,n){var t,a,d;"dt"===e.namespace&&(e=n.oInit.conditionalPaging||s.defaults.conditionalPaging,o.isPlainObject(e)||!0===e)&&(t=o.isPlainObject(e)?e:{},a=new s.Api(n),d=500,t.speed!==i&&(d=t.speed),(e=function(e){var n=o(a.table().container()).find("div.dataTables_paginate"),i=a.page.info().pages;e instanceof o.Event?i<=1?"fade"===t.style?n.stop().fadeTo(d,0):n.css("visibility","hidden"):"fade"===t.style?n.stop().fadeTo(d,1):n.css("visibility",""):i<=1&&("fade"===t.style?n.css("opacity",0):n.css("visibility","hidden"))})(null),a.on("draw.dt",e))}),s}); \ No newline at end of file diff --git a/features/conditionalPaging/dataTables.conditionalPaging.min.mjs b/features/conditionalPaging/dataTables.conditionalPaging.min.mjs new file mode 100644 index 0000000..b965115 --- /dev/null +++ b/features/conditionalPaging/dataTables.conditionalPaging.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd, Matthew Hasbach - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";$(document).on("init.dt",function(a,i){var e,n,s;"dt"===a.namespace&&(a=i.oInit.conditionalPaging||DataTable.defaults.conditionalPaging,$.isPlainObject(a)||!0===a)&&(e=$.isPlainObject(a)?a:{},n=new DataTable.Api(i),s=500,void 0!==e.speed&&(s=e.speed),(a=function(a){var i=$(n.table().container()).find("div.dataTables_paginate"),t=n.page.info().pages;a instanceof $.Event?t<=1?"fade"===e.style?i.stop().fadeTo(s,0):i.css("visibility","hidden"):"fade"===e.style?i.stop().fadeTo(s,1):i.css("visibility",""):t<=1&&("fade"===e.style?i.css("opacity",0):i.css("visibility","hidden"))})(null),n.on("draw.dt",a))});export default DataTable; \ No newline at end of file diff --git a/features/conditionalPaging/dataTables.conditionalPaging.mjs b/features/conditionalPaging/dataTables.conditionalPaging.mjs new file mode 100644 index 0000000..e9dbe3f --- /dev/null +++ b/features/conditionalPaging/dataTables.conditionalPaging.mjs @@ -0,0 +1,77 @@ +/*! © SpryMedia Ltd, Matthew Hasbach - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary ConditionalPaging + * @description Hide paging controls when the amount of pages is <= 1 + * @version 1.0.0 + * @author Matthew Hasbach (https://github.com/mjhasbach) + * @copyright Copyright 2015 Matthew Hasbach + * + * License MIT - http://datatables.net/license/mit + * + * This feature plugin for DataTables hides paging controls when the amount + * of pages is <= 1. The controls can either appear / disappear or fade in / out + * + * @example + * $('#myTable').DataTable({ + * conditionalPaging: true + * }); + * + * @example + * $('#myTable').DataTable({ + * conditionalPaging: { + * style: 'fade', + * speed: 500 // optional + * } + * }); + */ +$(document).on('init.dt', function (e, dtSettings) { + if (e.namespace !== 'dt') { + return; + } + var options = dtSettings.oInit.conditionalPaging || + DataTable.defaults.conditionalPaging; + if ($.isPlainObject(options) || options === true) { + var config = $.isPlainObject(options) ? options : {}, api = new DataTable.Api(dtSettings), speed = 500, conditionalPaging = function (e) { + var $paging = $(api.table().container()).find('div.dataTables_paginate'), pages = api.page.info().pages; + if (e instanceof $.Event) { + if (pages <= 1) { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + else { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 1); + } + else { + $paging.css('visibility', ''); + } + } + } + else if (pages <= 1) { + if (config.style === 'fade') { + $paging.css('opacity', 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + }; + if (config.speed !== undefined) { + speed = config.speed; + } + conditionalPaging(null); + api.on('draw.dt', conditionalPaging); + } +}); + + +export default DataTable; diff --git a/features/conditionalPaging/src/dataTables.conditionalPaging.ts b/features/conditionalPaging/src/dataTables.conditionalPaging.ts new file mode 100644 index 0000000..539f66a --- /dev/null +++ b/features/conditionalPaging/src/dataTables.conditionalPaging.ts @@ -0,0 +1,93 @@ +/*! © SpryMedia Ltd, Matthew Hasbach - datatables.net/license */ + +/** + * @summary ConditionalPaging + * @description Hide paging controls when the amount of pages is <= 1 + * @version 1.0.0 + * @author Matthew Hasbach (https://github.com/mjhasbach) + * @copyright Copyright 2015 Matthew Hasbach + * + * License MIT - http://datatables.net/license/mit + * + * This feature plugin for DataTables hides paging controls when the amount + * of pages is <= 1. The controls can either appear / disappear or fade in / out + * + * @example + * $('#myTable').DataTable({ + * conditionalPaging: true + * }); + * + * @example + * $('#myTable').DataTable({ + * conditionalPaging: { + * style: 'fade', + * speed: 500 // optional + * } + * }); + */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface Config { + conditionalPaging: boolean; + } +} + +$(document).on('init.dt', function (e, dtSettings) { + if (e.namespace !== 'dt') { + return; + } + + var options = + dtSettings.oInit.conditionalPaging || + DataTable.defaults.conditionalPaging; + + if ($.isPlainObject(options) || options === true) { + var config = $.isPlainObject(options) ? options : {}, + api = new DataTable.Api(dtSettings), + speed = 500, + conditionalPaging = function (e) { + var $paging = $(api.table().container()).find( + 'div.dataTables_paginate' + ), + pages = api.page.info().pages; + + if (e instanceof $.Event) { + if (pages <= 1) { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + else { + if (config.style === 'fade') { + $paging.stop().fadeTo(speed, 1); + } + else { + $paging.css('visibility', ''); + } + } + } + else if (pages <= 1) { + if (config.style === 'fade') { + $paging.css('opacity', 0); + } + else { + $paging.css('visibility', 'hidden'); + } + } + }; + + if (config.speed !== undefined) { + speed = config.speed; + } + + conditionalPaging(null); + + api.on('draw.dt', conditionalPaging); + } +}); diff --git a/features/deepLink/dataTables.deepLink.d.ts b/features/deepLink/dataTables.deepLink.d.ts new file mode 100644 index 0000000..2fa5f17 --- /dev/null +++ b/features/deepLink/dataTables.deepLink.d.ts @@ -0,0 +1,8 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStaticExt { + /** Deep linking options parsing support for DataTables */ + deepLink(whitelist: 'all' | string[]): any; + } +} +export {}; diff --git a/features/deepLink/dataTables.deepLink.js b/features/deepLink/dataTables.deepLink.js index 79f030f..edf4b34 100644 --- a/features/deepLink/dataTables.deepLink.js +++ b/features/deepLink/dataTables.deepLink.js @@ -1,14 +1,50 @@ -/*! Deep linking options parsing support for DataTables - * 2017 SpryMedia Ltd - datatables.net/license - */ +/*! © SpryMedia Ltd - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + /** * @summary LengthLinks * @description Deep linking options parsing support for DataTables - * @version 1.0.0 + * @version 1.1.0 * @file dataTables.deepLink.js * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @copyright Copyright 2017 SpryMedia Ltd. + * @copyright Copyright SpryMedia Ltd. * * License MIT - http://datatables.net/license/mit * @@ -26,19 +62,19 @@ * want to let the URL search string specify the `ajax` option). * * This specification is done by passing an array of property names - * to the `$.fn.dataTable.ext.deepLink` function. If you do which to + * to the `DataTable.ext.deepLink` function. If you do which to * allow _every_ parameter (I wouldn't recommend it) you can use `all` * instead of an array. * * @example * // Allow a display start point and search string to be specified * $('#myTable').DataTable( - * $.fn.dataTable.ext.deepLink( [ 'displayStart', 'search.search' ] ) + * DataTable.ext.deepLink( [ 'displayStart', 'search.search' ] ) * ); * * @example * // As above, but with a default search - * var options = $.fn.dataTable.ext.deepLink(['displayStart', 'search.search']); + * var options = DataTable.ext.deepLink(['displayStart', 'search.search']); * * $('#myTable').DataTable( * $.extend( true, { @@ -46,41 +82,39 @@ * }, options ) * ); */ -(function(window, document, $, undefined) { - // Use DataTables' object builder so strings can be used to represent - // nested objects - var setBuilder = $.fn.dataTable.ext.internal._fnSetObjectDataFn; - - $.fn.dataTable.ext.deepLink = function(whitelist) { - var search = location.search.replace(/^\?/, '').split('&'); - var out = {}; - - for (var i = 0, ien = search.length; i < ien; i++) { - var pair = search[i].split('='); - var key = decodeURIComponent(pair[0]); - var value = decodeURIComponent(pair[1]); +DataTable.ext.deepLink = function (whitelist) { + var search = location.search.replace(/^\?/, '').split('&'); + var out = {}; + for (var i = 0, ien = search.length; i < ien; i++) { + var pair = search[i].split('='); + var key = decodeURIComponent(pair[0]); + var value = decodeURIComponent(pair[1]); + // "Casting" + if (value === 'true') { + value = true; + } + else if (value === 'false') { + value = false; + } + else if (!value.match(/[^\d]/) && key !== 'search.search') { + // don't convert if searching or it'll break the search + value = value * 1; + } + else if (value.indexOf('{') === 0 || value.indexOf('[') === 0) { + // Try to JSON parse for arrays and obejcts + try { + value = $.parseJSON(value); + } + catch (e) { } + } + if (whitelist === 'all' || $.inArray(key, whitelist) !== -1) { + var setter = DataTable.util.set(key); + setter(out, value, {}); + } + } + return out; +}; - // "Casting" - if (value === 'true') { - value = true; - } else if (value === 'false') { - value = false; - } else if (!value.match(/[^\d]/) && key !== 'search.search') { - // don't convert if searching or it'll break the search - value = value * 1; - } else if (value.indexOf('{') === 0 || value.indexOf('[') === 0) { - // Try to JSON parse for arrays and obejcts - try { - value = $.parseJSON(value); - } catch (e) {} - } - - if (whitelist === 'all' || $.inArray(key, whitelist) !== -1) { - var setter = setBuilder(key); - setter(out, value); - } - } - return out; - }; -})(window, document, jQuery); +return DataTable; +})); diff --git a/features/deepLink/dataTables.deepLink.min.js b/features/deepLink/dataTables.deepLink.min.js index 649a87e..4276993 100644 --- a/features/deepLink/dataTables.deepLink.min.js +++ b/features/deepLink/dataTables.deepLink.min.js @@ -1,4 +1,2 @@ -/*! Deep linking options parsing support for DataTables - * 2017 SpryMedia Ltd - datatables.net/license - */ -!function(l){var f=l.fn.dataTable.ext.internal._fnSetObjectDataFn;l.fn.dataTable.ext.deepLink=function(e){for(var a=location.search.replace(/^\?/,"").split("&"),n={},t=0,r=a.length;t { + /** Set an exclude term */ + excludeSearch(searchTerm: string): Api; + } +} +export {}; diff --git a/features/excludeSearch/dataTables.excludeSearch.js b/features/excludeSearch/dataTables.excludeSearch.js index aeae53e..cc10c65 100644 --- a/features/excludeSearch/dataTables.excludeSearch.js +++ b/features/excludeSearch/dataTables.excludeSearch.js @@ -1,7 +1,47 @@ +/*! © Ulises Gomez / Gravity Lending, SpryMedia Ltd - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + /** * @summary ExcludeSearch * @description Add an input box that will remove matching items from the table - * @version 1.0.0 + * @version 1.0.1 * @file dataTables.excludeSearch.js * @author Ulises Gomez / Gravity Lending (https://www.linkedin.com/in/ulises-gomez/) * @copyright Copyright 2023 Ulises Gomez @@ -11,7 +51,7 @@ * This feature adds a search input box to DataTables that will remove any rows that * match the user's input from the display. Think of it as the inverse of the default * search. - * + * * An [example is available here](http://live.datatables.net/zohoyoqa/1/edit). * * @example @@ -19,52 +59,45 @@ * excludeSearch: true * }); */ - - (function(window, document, $) { - -$.fn.dataTable.Api.register('exclude_search()', function (searchTerm) { - this.iterator('table', function (context) { - context.exclude_search = searchTerm; - }); - return this; +DataTable.Api.register('excludeSearch()', function (searchTerm) { + this.iterator('table', function (context) { + context.exclude_search = searchTerm; + }); + return this; }); - -$.fn.dataTable.ext.search.push(function (context, search_data) { - if ( - context.exclude_search === '' || - context.exclude_search === undefined || - context.exclude_search === null - ) { - // No search term - all results shown - return true; - } - let show_row = true; - search_data.forEach((val) => { - if (val.toUpperCase().includes(context.exclude_search.toUpperCase())) { - show_row = false; - } - }); - return show_row; +DataTable.ext.search.push(function (context, search_data) { + if (context.exclude_search === '' || + context.exclude_search === undefined || + context.exclude_search === null) { + // No search term - all results shown + return true; + } + let show_row = true; + search_data.forEach(val => { + if (val.toUpperCase().includes(context.exclude_search.toUpperCase())) { + show_row = false; + } + }); + return show_row; }); -$.fn.dataTable.ExcludeSearch = function (context) { - let table = new $.fn.dataTable.Api(context); - // class mx-3 is from bootstrap v4 - let input_container = $( - '
' - ); - input_container.find('input').on('input', function () { - table.exclude_search($(this).val()).draw(); - }); - this.node = function () { - return input_container; - }; +DataTable.ExcludeSearch = function (context) { + let table = new DataTable.Api(context); + // class mx-3 is from bootstrap v4 + let input_container = $('
'); + input_container.find('input').on('input', function () { + table.excludeSearch($(this).val()).draw(); + }); + this.node = function () { + return input_container; + }; }; -$.fn.DataTable.ExcludeSearch = $.fn.dataTable.ExcludeSearch; -$.fn.dataTable.ext.feature.push({ - fnInit: function (settings) { - return new $.fn.dataTable.ExcludeSearch(settings).node(); - }, - cFeature: 'X', +DataTable.ext.feature.push({ + fnInit: function (settings) { + return new DataTable.ExcludeSearch(settings).node(); + }, + cFeature: 'X', }); -})(window, document, jQuery); + +return DataTable; +})); diff --git a/features/excludeSearch/dataTables.excludeSearch.min.js b/features/excludeSearch/dataTables.excludeSearch.min.js new file mode 100644 index 0000000..3b8ccbd --- /dev/null +++ b/features/excludeSearch/dataTables.excludeSearch.min.js @@ -0,0 +1,2 @@ +/*! © Ulises Gomez / Gravity Lending, SpryMedia Ltd - datatables.net/license */ +!function(n){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return n(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,(t=t||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,t),n(t,0,e.document)}:n(jQuery,window,document)}(function(u,e,t,r){"use strict";var i=u.fn.dataTable;return i.Api.register("excludeSearch()",function(t){return this.iterator("table",function(e){e.exclude_search=t}),this}),i.ext.search.push(function(t,e){if(""===t.exclude_search||t.exclude_search===r||null===t.exclude_search)return!0;let n=!0;return e.forEach(e=>{e.toUpperCase().includes(t.exclude_search.toUpperCase())&&(n=!1)}),n}),i.ExcludeSearch=function(e){let t=new i.Api(e),n=u('
');n.find("input").on("input",function(){t.excludeSearch(u(this).val()).draw()}),this.node=function(){return n}},i.ext.feature.push({fnInit:function(e){return new i.ExcludeSearch(e).node()},cFeature:"X"}),i}); \ No newline at end of file diff --git a/features/excludeSearch/dataTables.excludeSearch.min.mjs b/features/excludeSearch/dataTables.excludeSearch.min.mjs new file mode 100644 index 0000000..02d9601 --- /dev/null +++ b/features/excludeSearch/dataTables.excludeSearch.min.mjs @@ -0,0 +1,2 @@ +/*! © Ulises Gomez / Gravity Lending, SpryMedia Ltd - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";DataTable.Api.register("excludeSearch()",function(a){return this.iterator("table",function(e){e.exclude_search=a}),this}),DataTable.ext.search.push(function(a,e){if(""===a.exclude_search||void 0===a.exclude_search||null===a.exclude_search)return!0;let t=!0;return e.forEach(e=>{e.toUpperCase().includes(a.exclude_search.toUpperCase())&&(t=!1)}),t}),DataTable.ExcludeSearch=function(e){let a=new DataTable.Api(e),t=$('
');t.find("input").on("input",function(){a.excludeSearch($(this).val()).draw()}),this.node=function(){return t}},DataTable.ext.feature.push({fnInit:function(e){return new DataTable.ExcludeSearch(e).node()},cFeature:"X"});export default DataTable; \ No newline at end of file diff --git a/features/excludeSearch/dataTables.excludeSearch.mjs b/features/excludeSearch/dataTables.excludeSearch.mjs new file mode 100644 index 0000000..255e957 --- /dev/null +++ b/features/excludeSearch/dataTables.excludeSearch.mjs @@ -0,0 +1,68 @@ +/*! © Ulises Gomez / Gravity Lending, SpryMedia Ltd - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary ExcludeSearch + * @description Add an input box that will remove matching items from the table + * @version 1.0.1 + * @file dataTables.excludeSearch.js + * @author Ulises Gomez / Gravity Lending (https://www.linkedin.com/in/ulises-gomez/) + * @copyright Copyright 2023 Ulises Gomez + * + * License MIT - http://datatables.net/license/mit + * + * This feature adds a search input box to DataTables that will remove any rows that + * match the user's input from the display. Think of it as the inverse of the default + * search. + * + * An [example is available here](http://live.datatables.net/zohoyoqa/1/edit). + * + * @example + * $('#myTable').DataTable({ + * excludeSearch: true + * }); + */ +DataTable.Api.register('excludeSearch()', function (searchTerm) { + this.iterator('table', function (context) { + context.exclude_search = searchTerm; + }); + return this; +}); +DataTable.ext.search.push(function (context, search_data) { + if (context.exclude_search === '' || + context.exclude_search === undefined || + context.exclude_search === null) { + // No search term - all results shown + return true; + } + let show_row = true; + search_data.forEach(val => { + if (val.toUpperCase().includes(context.exclude_search.toUpperCase())) { + show_row = false; + } + }); + return show_row; +}); +DataTable.ExcludeSearch = function (context) { + let table = new DataTable.Api(context); + // class mx-3 is from bootstrap v4 + let input_container = $('
'); + input_container.find('input').on('input', function () { + table.excludeSearch($(this).val()).draw(); + }); + this.node = function () { + return input_container; + }; +}; +DataTable.ext.feature.push({ + fnInit: function (settings) { + return new DataTable.ExcludeSearch(settings).node(); + }, + cFeature: 'X', +}); + + +export default DataTable; diff --git a/features/excludeSearch/src/dataTables.excludeSearch.ts b/features/excludeSearch/src/dataTables.excludeSearch.ts new file mode 100644 index 0000000..9f7f19b --- /dev/null +++ b/features/excludeSearch/src/dataTables.excludeSearch.ts @@ -0,0 +1,94 @@ +/*! © Ulises Gomez / Gravity Lending, SpryMedia Ltd - datatables.net/license */ + +/** + * @summary ExcludeSearch + * @description Add an input box that will remove matching items from the table + * @version 1.0.1 + * @file dataTables.excludeSearch.js + * @author Ulises Gomez / Gravity Lending (https://www.linkedin.com/in/ulises-gomez/) + * @copyright Copyright 2023 Ulises Gomez + * + * License MIT - http://datatables.net/license/mit + * + * This feature adds a search input box to DataTables that will remove any rows that + * match the user's input from the display. Think of it as the inverse of the default + * search. + * + * An [example is available here](http://live.datatables.net/zohoyoqa/1/edit). + * + * @example + * $('#myTable').DataTable({ + * excludeSearch: true + * }); + */ + +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface DataTablesStatic { + /** Add an input box that will remove matching items from the table */ + ExcludeSearch(settings: any): void; + } + + interface Config { + alphabet?: { + column: number; + caseSensitive: boolean; + numbers: boolean; + }; + } + + interface Api { + /** Set an exclude term */ + excludeSearch(searchTerm: string): Api; + } +} + +DataTable.Api.register('excludeSearch()', function (searchTerm) { + this.iterator('table', function (context) { + context.exclude_search = searchTerm; + }); + return this; +}); + +DataTable.ext.search.push(function (context, search_data) { + if ( + context.exclude_search === '' || + context.exclude_search === undefined || + context.exclude_search === null + ) { + // No search term - all results shown + return true; + } + let show_row = true; + search_data.forEach(val => { + if (val.toUpperCase().includes(context.exclude_search.toUpperCase())) { + show_row = false; + } + }); + return show_row; +}); + +DataTable.ExcludeSearch = function (context) { + let table = new DataTable.Api(context); + + // class mx-3 is from bootstrap v4 + let input_container = $( + '
' + ); + + input_container.find('input').on('input', function () { + table.excludeSearch($(this).val() as string).draw(); + }); + + this.node = function () { + return input_container; + }; +}; + +DataTable.ext.feature.push({ + fnInit: function (settings) { + return new DataTable.ExcludeSearch(settings).node(); + }, + cFeature: 'X', +}); diff --git a/features/fuzzySearch/dataTables.fuzzySearch.d.ts b/features/fuzzySearch/dataTables.fuzzySearch.d.ts new file mode 100644 index 0000000..325435c --- /dev/null +++ b/features/fuzzySearch/dataTables.fuzzySearch.d.ts @@ -0,0 +1,25 @@ +/*! + * Fuzzy Search for DataTables + * 2021 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. + */ +declare module 'datatables.net' { + interface Config { + fuzzySearch?: boolean | { + rankColumn?: number; + threshold?: number; + toggleSmart?: boolean; + }; + } + interface State { + _fuzzySearch: { + active: 'true' | 'false'; + val: any; + }; + } +} +export {}; diff --git a/features/fuzzySearch/dataTables.fuzzySearch.js b/features/fuzzySearch/dataTables.fuzzySearch.js index 5f88562..c791358 100644 --- a/features/fuzzySearch/dataTables.fuzzySearch.js +++ b/features/fuzzySearch/dataTables.fuzzySearch.js @@ -1,450 +1,447 @@ /*! * Fuzzy Search for DataTables * 2021 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. */ -(function() { - function levenshtein(__this, that, limit) { - - var thisLength = __this.length, - thatLength = that.length, - matrix = []; - - // If the limit is not defined it will be calculate from this and that args. - limit = (limit || ((thatLength > thisLength ? thatLength : thisLength)))+1; - - for (var i = 0; i < limit; i++) { - matrix[i] = [i]; - matrix[i].length = limit; - } - for (i = 0; i < limit; i++) { - matrix[0][i] = i; - } - - if (Math.abs(thisLength - thatLength) > (limit || 100)){ - return prepare (limit || 100); - } - if (thisLength === 0){ - return prepare (thatLength); - } - if (thatLength === 0){ - return prepare (thisLength); + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + +function levenshtein(__this, that, limit) { + var thisLength = __this.length, thatLength = that.length, matrix = []; + // If the limit is not defined it will be calculate from this and that args. + limit = (limit || (thatLength > thisLength ? thatLength : thisLength)) + 1; + for (var i = 0; i < limit; i++) { + matrix[i] = [i]; + matrix[i].length = limit; + } + for (i = 0; i < limit; i++) { + matrix[0][i] = i; + } + if (Math.abs(thisLength - thatLength) > (limit || 100)) { + return prepare(limit || 100); + } + if (thisLength === 0) { + return prepare(thatLength); + } + if (thatLength === 0) { + return prepare(thisLength); + } + // Calculate matrix. + var j, this_i, that_j, cost, min, t; + for (i = 1; i <= thisLength; ++i) { + this_i = __this[i - 1]; + // Step 4 + for (j = 1; j <= thatLength; ++j) { + // Check the jagged ld total so far + if (i === j && matrix[i][j] > 4) + return prepare(thisLength); + that_j = that[j - 1]; + cost = this_i === that_j ? 0 : 1; // Step 5 + // Calculate the minimum (much faster than Math.min(...)). + min = matrix[i - 1][j] + 1; // Devarion. + if ((t = matrix[i][j - 1] + 1) < min) + min = t; // Insertion. + if ((t = matrix[i - 1][j - 1] + cost) < min) + min = t; // Substitution. + // Update matrix. + matrix[i][j] = + i > 1 && + j > 1 && + this_i === that[j - 2] && + __this[i - 2] === that_j && + (t = matrix[i - 2][j - 2] + cost) < min + ? t + : min; // Transposition. } - - // Calculate matrix. - var j, this_i, that_j, cost, min, t; - for (i = 1; i <= thisLength; ++i) { - this_i = __this[i-1]; - - // Step 4 - for (j = 1; j <= thatLength; ++j) { - // Check the jagged ld total so far - if (i === j && matrix[i][j] > 4) return prepare (thisLength); - - that_j = that[j-1]; - cost = (this_i === that_j) ? 0 : 1; // Step 5 - // Calculate the minimum (much faster than Math.min(...)). - min = matrix[i - 1][j ] + 1; // Devarion. - if ((t = matrix[i ][j - 1] + 1 ) < min) min = t; // Insertion. - if ((t = matrix[i - 1][j - 1] + cost) < min) min = t; // Substitution. - - // Update matrix. - matrix[i][j] = (i > 1 && j > 1 && this_i === that[j-2] && __this[i-2] === that_j && (t = matrix[i-2][j-2]+cost) < min) ? t : min; // Transposition. - } + } + return prepare(matrix[thisLength][thatLength]); + function prepare(steps) { + var length = Math.max(thisLength, thatLength); + var relative = length === 0 ? 0 : steps / length; + var similarity = 1 - relative; + return { + steps: steps, + relative: relative, + similarity: similarity, + }; + } +} +function fuzzySearch(searchVal, data, initial) { + // If no searchVal has been defined then return all rows. + if (searchVal === undefined || searchVal.length === 0) { + return { + pass: true, + score: '', + }; + } + var threshold = initial.threshold !== undefined ? initial.threshold : 0.5; + // Split the searchVal into individual words. + var splitSearch = searchVal.split(/ /g); + // Array to keep scores in + var highestCollated = []; + // Remove any empty words or spaces + for (var x = 0; x < splitSearch.length; x++) { + if (splitSearch[x].length === 0 || splitSearch[x] === ' ') { + splitSearch.splice(x, 1); + x--; } - - return prepare (matrix[thisLength][thatLength]); - - function prepare(steps) { - var length = Math.max(thisLength, thatLength) - var relative = length === 0 - ? 0 - : (steps / length); - var similarity = 1 - relative - return { - steps: steps, - relative: relative, - similarity: similarity - }; + // Aside - Add to the score collection if not done so yet for this search word + else if (highestCollated.length < splitSearch.length) { + highestCollated.push({ pass: false, score: 0 }); } } - - function fuzzySearch(searchVal, data, initial) { - // If no searchVal has been defined then return all rows. - if(searchVal === undefined || searchVal.length === 0) { - return { - pass: true, - score: '' - } - } - - var threshold = initial.threshold !== undefined ? initial.threshold : 0.5; - - // Split the searchVal into individual words. - var splitSearch = searchVal.split(/ /g); - - // Array to keep scores in - var highestCollated = []; - + // Going to check each cell for potential matches + for (var i = 0; i < data.length; i++) { + // Convert all data points to lower case fo insensitive sorting + data[i] = data[i].toLowerCase(); + // Split the data into individual words + var splitData = data[i].split(/ /g); // Remove any empty words or spaces - for(var x = 0; x < splitSearch.length; x++) { - if (splitSearch[x].length === 0 || splitSearch[x] === ' ') { - splitSearch.splice(x, 1); + for (var y = 0; y < splitData.length; y++) { + if (splitData[y].length === 0 || splitData[y] === ' ') { + splitData.splice(y, 1); x--; } - // Aside - Add to the score collection if not done so yet for this search word - else if (highestCollated.length < splitSearch.length) { - highestCollated.push({pass: false, score: 0}); - } } - - // Going to check each cell for potential matches - for(var i = 0; i < data.length; i++) { - // Convert all data points to lower case fo insensitive sorting - data[i] = data[i].toLowerCase(); - - // Split the data into individual words - var splitData = data[i].split(/ /g); - - // Remove any empty words or spaces - for (var y = 0; y < splitData.length; y++){ - if(splitData[y].length === 0 || splitData[y] === ' ') { - splitData.splice(y, 1); - x--; - } - } - - // Check each search term word - for(var x = 0; x < splitSearch.length; x++) { - // Reset highest score - var highest = { - pass: undefined, - score: 0 - }; - - // Against each word in the cell - for (var y = 0; y < splitData.length; y++){ - // If this search Term word is the beginning of the word in the cell we want to pass this word - if(splitData[y].indexOf(splitSearch[x]) === 0){ - var newScore = splitSearch[x].length / splitData[y].length; - highest = { - pass: true, - score: highest.score < newScore ? newScore : highest.score - }; - } - - // Get the levenshtein similarity score for the two words - var steps = levenshtein(splitSearch[x], splitData[y]).similarity; - - // If the levenshtein similarity score is better than a previous one for the search word then var's store it - if(steps > highest.score) { - highest.score = steps; - } - } - - // If this cell has a higher scoring word than previously found to the search term in the row, store it - if(highestCollated[x].score < highest.score || highest.pass) { - highestCollated[x] = { - pass: highest.pass || highestCollated.pass ? true : highest.score > threshold, - score: highest.score + // Check each search term word + for (var x = 0; x < splitSearch.length; x++) { + // Reset highest score + var highest = { + pass: undefined, + score: 0, + }; + // Against each word in the cell + for (var y = 0; y < splitData.length; y++) { + // If this search Term word is the beginning of the word in the cell we want to pass this word + if (splitData[y].indexOf(splitSearch[x]) === 0) { + var newScore = splitSearch[x].length / splitData[y].length; + highest = { + pass: true, + score: highest.score < newScore ? newScore : highest.score, }; } + // Get the levenshtein similarity score for the two words + var steps = levenshtein(splitSearch[x], splitData[y]).similarity; + // If the levenshtein similarity score is better than a previous one for the search word then var's store it + if (steps > highest.score) { + highest.score = steps; + } } - } - - // Check that all of the search words have passed - for(var i = 0; i < highestCollated.length; i++) { - if(!highestCollated[i].pass) { - return { - pass: false, - score: Math.round(((highestCollated.reduce((a,b) => a+b.score, 0) / highestCollated.length) * 100)) + "%" + // If this cell has a higher scoring word than previously found to the search term in the row, store it + if (highestCollated[x].score < highest.score || highest.pass) { + highestCollated[x] = { + pass: highest.pass || highestCollated[x].pass + ? true + : highest.score > threshold, + score: highest.score, }; } } - - // If we get to here, all scores greater than 0.5 so display the row - return { - pass: true, - score: Math.round(((highestCollated.reduce((a,b) => a+b.score, 0) / highestCollated.length) * 100)) + "%" - }; } - - $.fn.dataTable.ext.search.push( - function( settings, data, dataIndex ) { - var initial = settings.oInit.fuzzySearch; - - if (! initial) { - return true; - } - - // 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; + // Check that all of the search words have passed + for (var i = 0; i < highestCollated.length; i++) { + if (!highestCollated[i].pass) { + return { + pass: false, + score: Math.round((highestCollated.reduce((a, b) => a + b.score, 0) / + highestCollated.length) * + 100) + '%', + }; } - ); - - $(document).on('init.dt', function(e, settings) { - var api = new $.fn.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 we get to here, all scores greater than 0.5 so display the row + return { + pass: true, + score: Math.round((highestCollated.reduce((a, b) => a + b.score, 0) / + highestCollated.length) * + 100) + '%', + }; +} +DataTable.ext.search.push(function (settings, data, dataIndex) { + var initial = settings.oInit.fuzzySearch; + if (!initial) { + return true; + } + // 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); } - - var fromPlugin = false; - - // Find the input element - var input = $('div.dataTables_filter 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' + // 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; + } + var fromPlugin = false; + // Find the input element + var input = $('div.dataTables_filter 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 (typeof initialFuzzy === 'object' && initialFuzzy.toggleSmart) { + toggle = $('') + .insertAfter(input) + .css({ + border: 'none', + background: 'none', + position: 'relative', + right: '33px', + top: '0px', + cursor: 'pointer', + color: '#3b5e99', + 'margin-top': '1px', + }); + exact = $('') + .insertAfter(input) + .css(toggleCSS) + .css(fontBold) + .attr('highlighted', 'true'); + fuzzy = $('') + .insertAfter(input) + .css(toggleCSS); + input.css({ + 'padding-right': '30px', + }); + $(input.parent()).css('right', '-33px').css('position', 'relative'); + label = $('
Search Type
').css({ + 'padding-bottom': '0.5em', + 'font-size': '0.8em', + }); + tooltip = $('
') + .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); } - - // Only going to set the toggle if it is enabled - var toggle, tooltip, exact, fuzzy, label; - if(initialFuzzy.toggleSmart) { - toggle =$('') - .insertAfter(input) - .css({ - 'border': 'none', - 'background': 'none', - 'position': 'relative', - 'right': '33px', - 'top': '0px', - 'cursor': 'pointer', - 'color': '#3b5e99', - 'margin-top': '1px' - }); - exact =$('') - .insertAfter(input) - .css(toggleCSS) - .css(fontBold) - .attr('highlighted', true); - fuzzy =$('') - .insertAfter(input) - .css(toggleCSS); - input.css({ - 'padding-right': '30px' - }); - $(input.parent()).css('right', '-33px').css('position', 'relative'); - label = $('
Search Type
').css({'padding-bottom': '0.5em', 'font-size': '0.8em'}) - tooltip = $('
') - .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); + else { + toggle.css({ filter: 'blur(1px)' }).attr('blurred', true); + exact.removeAttr('highlighted').css(fontNormal); + fuzzy.attr('highlighted', true).css(fontBold); } - - 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); + // Whenever the search mode is changed we need to re-search + triggerSearchFunction(event); + } + // 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.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, rowIdx) { + settings.aoData[rowIdx]._fuzzySearch = undefined; + }, false); + searchVal = input.val(); + fuzzySearchVal = searchVal; + fromPlugin = true; + api.search(searchVal); + fromPlugin = false; + searchVal = ''; } + // Otherwise perform a fuzzy search 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); - } - - // 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.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, rowIdx) { - settings.aoData[rowIdx]._fuzzySearch = undefined; - }) - searchVal = input.val(); - fuzzySearchVal = searchVal; - fromPlugin = true; - api.search(searchVal); - fromPlugin = false; - searchVal = ""; + // Get the value from the input element and convert to lower case + fuzzySearchVal = input.val(); + searchVal = ''; + if (fuzzySearchVal !== undefined && fuzzySearchVal.length !== 0) { + fuzzySearchVal = fuzzySearchVal.toLowerCase(); } - // Otherwise perform a fuzzy search - else { - // Get the value from the input element and convert to lower case - fuzzySearchVal = input.val(); - 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, rowIdx) { - settings.aoData[rowIdx]._fuzzySearch = fuzzySearch(fuzzySearchVal, settings.aoData[rowIdx]._aFilterData, initialFuzzy) - }); - - fromPlugin = true; - // Empty the datatables search and replace it with our own - api.search(""); - input.val(fuzzySearchVal); - fromPlugin = false; - } - + // For each row call the fuzzy search function to get result + api.rows().iterator('row', function (settings, rowIdx) { + settings.aoData[rowIdx]._fuzzySearch = fuzzySearch(fuzzySearchVal, settings.aoData[rowIdx]._aFilterData, initialFuzzy); + }, false); fromPlugin = true; - api.draw(); + // 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 = $.fn.dataTable.Api.register; - apiRegister('search.fuzzy()', function(value) { - if(value === undefined) { - return fuzzySearchVal; - } - else { - fuzzySearchVal = value.toLowerCase(); - searchVal = api.search(); - input.val(fuzzySearchVal); - - // For each row call the fuzzy search function to get result - api.rows().iterator('row', function(settings, rowIdx) { - settings.aoData[rowIdx]._fuzzySearch = fuzzySearch(fuzzySearchVal, settings.aoData[rowIdx]._aFilterData, initialFuzzy) - }); - // triggerSearchFunction({key: 'Enter'}); - return this; + }; + var apiRegister = DataTable.Api.register; + apiRegister('search.fuzzy()', function (value) { + if (value === undefined) { + return fuzzySearchVal; + } + else { + fuzzySearchVal = value.toLowerCase(); + searchVal = api.search(); + input.val(fuzzySearchVal); + // For each row call the fuzzy search function to get result + api.rows().iterator('row', function (settings, 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) { + // 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(); + } + // 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)); }) - - input.off(); - // Set listeners to occur on toggle and typing - if(toggle) { - // 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(); - } - - // 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'); + .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() : fuzzySearchVal); + } + }); + // Always add this event no matter if toggling is enabled + input.on('input keydown', triggerSearchFunction); +}); - api.on('search', function(){ - if(!fromPlugin) { - input.val(api.search() !== searchVal ? api.search() : fuzzySearchVal); - } - }) - // Always add this event no matter if toggling is enabled - input.on('input keydown', triggerSearchFunction); - }) -}()); - \ No newline at end of file +return DataTable; +})); diff --git a/features/fuzzySearch/dataTables.fuzzySearch.min.js b/features/fuzzySearch/dataTables.fuzzySearch.min.js new file mode 100644 index 0000000..562b73a --- /dev/null +++ b/features/fuzzySearch/dataTables.fuzzySearch.min.js @@ -0,0 +1,10 @@ +/*! + * Fuzzy Search for DataTables + * 2021 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. + */ +!function(r){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return r(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,(t=t||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,t),r(t,0,e.document)}:r(jQuery,window,document)}(function(y,e,t,w){"use strict";var k=y.fn.dataTable;function x(e,t,r){if(e===w||0===e.length)return{pass:!0,score:""};for(var n=r.threshold!==w?r.threshold:.5,o=e.split(/ /g),a=[],s=0;s(r||100))return d(r||100);if(0===n)return d(o);if(0===o)return d(n);for(h=1;h<=n;++h)for(i=e[h-1],s=1;s<=o;++s){if(h===s&&4l.score&&(l.score=f)}(a[s].scoren,score:l.score})}}for(i=0;ie+t.score,0)/a.length*100)+"%"};return{pass:!0,score:Math.round(a.reduce((e,t)=>e+t.score,0)/a.length*100)+"%"}}return k.ext.search.push(function(e,t,r){var n,o=e.oInit.fuzzySearch;if(o){if(e.aoData[r]._fuzzySearch!==w)return n=e.aoData[r]._fuzzySearch.score,o.rankColumn!==w&&(e.aoData[r].anCells[o.rankColumn].innerHTML=n,e.aoData[r]._aSortData[o.rankColumn]=+n.substring(0,n.length-1)),e.aoData[r]._fuzzySearch.pass;o.rankColumn!==w&&(e.aoData[r].anCells[o.rankColumn].innerHTML="",e.aoData[r]._aSortData[o.rankColumn]="")}return!0}),y(t).on("init.dt",function(e,t){var r,n,o,a,s,i,c,u,l,f,h,d,p=new k.Api(t),g=p.init(),b=g.fuzzySearch;function v(e){(s.attr("blurred")?(s.css({filter:"blur(0px)"}).removeAttr("blurred"),u.removeAttr("highlighted").css(a),c):(s.css({filter:"blur(1px)"}).attr("blurred",!0),c.removeAttr("highlighted").css(a),u)).attr("highlighted",!0).css(o),h(e)}function m(e,t){e.attr("highlighted")||v(t)}function z(){i.remove()}b&&(r=!1,n=y("div.dataTables_filter input",p.table().container()),o={"font-weight":"600","background-color":"rgba(255,255,255,0.1)"},a={"font-weight":"500","background-color":"transparent"},d={border:"none",background:"none","font-size":"100%",width:"50%",display:"inline-block",color:"white",cursor:"pointer",padding:"0.5em"},"object"==typeof b&&b.toggleSmart&&(s=y('').insertAfter(n).css({border:"none",background:"none",position:"relative",right:"33px",top:"0px",cursor:"pointer",color:"#3b5e99","margin-top":"1px"}),c=y('').insertAfter(n).css(d).css(o).attr("highlighted","true"),u=y('').insertAfter(n).css(d),n.css({"padding-right":"30px"}),y(n.parent()).css("right","-33px").css("position","relative"),d=y("
Search Type
").css({"padding-bottom":"0.5em","font-size":"0.8em"}),i=y('
').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:n.outerWidth()-3}).append(d).append(c).append(u)),y(t.nTable).off("search.dt.DT"),h=function(e){("input"!==e.type||g.search!==w&&g.search.return)&&"Enter"!==e.key&&"click"!==e.type||(s&&!s.attr("blurred")?(p.rows().iterator("row",function(e,t){e.aoData[t]._fuzzySearch=w},!1),f=n.val(),l=f,r=!0,p.search(f),r=!1,f=""):(l=n.val(),f="",l!==w&&0!==l.length&&(l=l.toLowerCase()),p.rows().iterator("row",function(e,t){e.aoData[t]._fuzzySearch=x(l,e.aoData[t]._aFilterData,b)},!1),r=!0,p.search(""),n.val(l),r=!1),r=!0,p.draw(),r=!1)},(f=l="",k.Api.register)("search.fuzzy()",function(e){return e===w?l:(l=e.toLowerCase(),f=p.search(),n.val(l),p.rows().iterator("row",function(e,t){e.aoData[t]._fuzzySearch=x(l,e.aoData[t]._aFilterData,b)},!1),this)}),n.off(),s&&(s.on("click",v).on("mouseenter",function(){i.insertAfter(s).on("mouseleave",z),i.css("left",n.position().left+3),c.on("click",e=>m(c,e)),u.on("click",e=>m(u,e))}).on("mouseleave",z),n.on("mouseenter",function(){i.insertAfter(s).on("mouseleave",z),i.css("left",n.position().left+3),c.on("click",e=>m(c,e)),u.on("click",e=>m(u,e))}).on("mouseleave",function(){var e=!1;i.on("mouseenter",()=>e=!0),s.on("mouseenter",()=>e=!0),setTimeout(function(){e||z()},250)}),d=p.state.loaded(),p.on("stateSaveParams",function(e,t,r){r._fuzzySearch={active:s.attr("blurred"),val:n.val()}}),null!==d)&&d._fuzzySearch!==w&&(n.val(d._fuzzySearch.val),"true"===d._fuzzySearch.active)&&(s.click(),p.page(d.start/d.length).draw("page")),p.on("search",function(){r||n.val(p.search()!==f?p.search():l)}),n.on("input keydown",h))}),k}); \ No newline at end of file diff --git a/features/fuzzySearch/dataTables.fuzzySearch.min.mjs b/features/fuzzySearch/dataTables.fuzzySearch.min.mjs new file mode 100644 index 0000000..2d5d50b --- /dev/null +++ b/features/fuzzySearch/dataTables.fuzzySearch.min.mjs @@ -0,0 +1,10 @@ +/*! + * Fuzzy Search for DataTables + * 2021 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 $ from"jquery";import DataTable from"datatables.net";function levenshtein(e,t,r){var a=e.length,o=t.length,n=[];r=(r||(a(r||100))return d(r||100);if(0===a)return d(o);if(0===o)return d(a);for(f=1;f<=a;++f)for(i=e[f-1],s=1;s<=o;++s){if(f===s&&4u.score&&(u.score=h)}(n[s].scorea,score:u.score})}}for(i=0;ie+t.score,0)/n.length*100)+"%"};return{pass:!0,score:Math.round(n.reduce((e,t)=>e+t.score,0)/n.length*100)+"%"}}DataTable.ext.search.push(function(e,t,r){var a,o=e.oInit.fuzzySearch;if(o){if(void 0!==e.aoData[r]._fuzzySearch)return a=e.aoData[r]._fuzzySearch.score,void 0!==o.rankColumn&&(e.aoData[r].anCells[o.rankColumn].innerHTML=a,e.aoData[r]._aSortData[o.rankColumn]=+a.substring(0,a.length-1)),e.aoData[r]._fuzzySearch.pass;void 0!==o.rankColumn&&(e.aoData[r].anCells[o.rankColumn].innerHTML="",e.aoData[r]._aSortData[o.rankColumn]="")}return!0}),$(document).on("init.dt",function(e,t){var r,a,o,n,s,i,c,l,u,h,f,d,p=new DataTable.Api(t),g=p.init(),v=g.fuzzySearch;function b(e){(s.attr("blurred")?(s.css({filter:"blur(0px)"}).removeAttr("blurred"),l.removeAttr("highlighted").css(n),c):(s.css({filter:"blur(1px)"}).attr("blurred",!0),c.removeAttr("highlighted").css(n),l)).attr("highlighted",!0).css(o),f(e)}function z(e,t){e.attr("highlighted")||b(t)}function m(){i.remove()}v&&(r=!1,a=$("div.dataTables_filter input",p.table().container()),o={"font-weight":"600","background-color":"rgba(255,255,255,0.1)"},n={"font-weight":"500","background-color":"transparent"},d={border:"none",background:"none","font-size":"100%",width:"50%",display:"inline-block",color:"white",cursor:"pointer",padding:"0.5em"},"object"==typeof v&&v.toggleSmart&&(s=$('').insertAfter(a).css({border:"none",background:"none",position:"relative",right:"33px",top:"0px",cursor:"pointer",color:"#3b5e99","margin-top":"1px"}),c=$('').insertAfter(a).css(d).css(o).attr("highlighted","true"),l=$('').insertAfter(a).css(d),a.css({"padding-right":"30px"}),$(a.parent()).css("right","-33px").css("position","relative"),d=$("
Search Type
").css({"padding-bottom":"0.5em","font-size":"0.8em"}),i=$('
').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:a.outerWidth()-3}).append(d).append(c).append(l)),$(t.nTable).off("search.dt.DT"),f=function(e){("input"!==e.type||void 0!==g.search&&g.search.return)&&"Enter"!==e.key&&"click"!==e.type||(s&&!s.attr("blurred")?(p.rows().iterator("row",function(e,t){e.aoData[t]._fuzzySearch=void 0},!1),h=a.val(),u=h,r=!0,p.search(h),r=!1,h=""):(u=a.val(),h="",void 0!==u&&0!==u.length&&(u=u.toLowerCase()),p.rows().iterator("row",function(e,t){e.aoData[t]._fuzzySearch=fuzzySearch(u,e.aoData[t]._aFilterData,v)},!1),r=!0,p.search(""),a.val(u),r=!1),r=!0,p.draw(),r=!1)},(h=u="",DataTable.Api.register)("search.fuzzy()",function(e){return void 0===e?u:(u=e.toLowerCase(),h=p.search(),a.val(u),p.rows().iterator("row",function(e,t){e.aoData[t]._fuzzySearch=fuzzySearch(u,e.aoData[t]._aFilterData,v)},!1),this)}),a.off(),s&&(s.on("click",b).on("mouseenter",function(){i.insertAfter(s).on("mouseleave",m),i.css("left",a.position().left+3),c.on("click",e=>z(c,e)),l.on("click",e=>z(l,e))}).on("mouseleave",m),a.on("mouseenter",function(){i.insertAfter(s).on("mouseleave",m),i.css("left",a.position().left+3),c.on("click",e=>z(c,e)),l.on("click",e=>z(l,e))}).on("mouseleave",function(){var e=!1;i.on("mouseenter",()=>e=!0),s.on("mouseenter",()=>e=!0),setTimeout(function(){e||m()},250)}),d=p.state.loaded(),p.on("stateSaveParams",function(e,t,r){r._fuzzySearch={active:s.attr("blurred"),val:a.val()}}),null!==d)&&void 0!==d._fuzzySearch&&(a.val(d._fuzzySearch.val),"true"===d._fuzzySearch.active)&&(s.click(),p.page(d.start/d.length).draw("page")),p.on("search",function(){r||a.val(p.search()!==h?p.search():u)}),a.on("input keydown",f))});export default DataTable; \ No newline at end of file diff --git a/features/fuzzySearch/dataTables.fuzzySearch.mjs b/features/fuzzySearch/dataTables.fuzzySearch.mjs new file mode 100644 index 0000000..eb93151 --- /dev/null +++ b/features/fuzzySearch/dataTables.fuzzySearch.mjs @@ -0,0 +1,412 @@ +/*! + * Fuzzy Search for DataTables + * 2021 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 $ from 'jquery'; +import DataTable from 'datatables.net'; + + +function levenshtein(__this, that, limit) { + var thisLength = __this.length, thatLength = that.length, matrix = []; + // If the limit is not defined it will be calculate from this and that args. + limit = (limit || (thatLength > thisLength ? thatLength : thisLength)) + 1; + for (var i = 0; i < limit; i++) { + matrix[i] = [i]; + matrix[i].length = limit; + } + for (i = 0; i < limit; i++) { + matrix[0][i] = i; + } + if (Math.abs(thisLength - thatLength) > (limit || 100)) { + return prepare(limit || 100); + } + if (thisLength === 0) { + return prepare(thatLength); + } + if (thatLength === 0) { + return prepare(thisLength); + } + // Calculate matrix. + var j, this_i, that_j, cost, min, t; + for (i = 1; i <= thisLength; ++i) { + this_i = __this[i - 1]; + // Step 4 + for (j = 1; j <= thatLength; ++j) { + // Check the jagged ld total so far + if (i === j && matrix[i][j] > 4) + return prepare(thisLength); + that_j = that[j - 1]; + cost = this_i === that_j ? 0 : 1; // Step 5 + // Calculate the minimum (much faster than Math.min(...)). + min = matrix[i - 1][j] + 1; // Devarion. + if ((t = matrix[i][j - 1] + 1) < min) + min = t; // Insertion. + if ((t = matrix[i - 1][j - 1] + cost) < min) + min = t; // Substitution. + // Update matrix. + matrix[i][j] = + i > 1 && + j > 1 && + this_i === that[j - 2] && + __this[i - 2] === that_j && + (t = matrix[i - 2][j - 2] + cost) < min + ? t + : min; // Transposition. + } + } + return prepare(matrix[thisLength][thatLength]); + function prepare(steps) { + var length = Math.max(thisLength, thatLength); + var relative = length === 0 ? 0 : steps / length; + var similarity = 1 - relative; + return { + steps: steps, + relative: relative, + similarity: similarity, + }; + } +} +function fuzzySearch(searchVal, data, initial) { + // If no searchVal has been defined then return all rows. + if (searchVal === undefined || searchVal.length === 0) { + return { + pass: true, + score: '', + }; + } + var threshold = initial.threshold !== undefined ? initial.threshold : 0.5; + // Split the searchVal into individual words. + var splitSearch = searchVal.split(/ /g); + // Array to keep scores in + var highestCollated = []; + // Remove any empty words or spaces + for (var x = 0; x < splitSearch.length; x++) { + if (splitSearch[x].length === 0 || splitSearch[x] === ' ') { + splitSearch.splice(x, 1); + x--; + } + // Aside - Add to the score collection if not done so yet for this search word + else if (highestCollated.length < splitSearch.length) { + highestCollated.push({ pass: false, score: 0 }); + } + } + // Going to check each cell for potential matches + for (var i = 0; i < data.length; i++) { + // Convert all data points to lower case fo insensitive sorting + data[i] = data[i].toLowerCase(); + // Split the data into individual words + var splitData = data[i].split(/ /g); + // Remove any empty words or spaces + for (var y = 0; y < splitData.length; y++) { + if (splitData[y].length === 0 || splitData[y] === ' ') { + splitData.splice(y, 1); + x--; + } + } + // Check each search term word + for (var x = 0; x < splitSearch.length; x++) { + // Reset highest score + var highest = { + pass: undefined, + score: 0, + }; + // Against each word in the cell + for (var y = 0; y < splitData.length; y++) { + // If this search Term word is the beginning of the word in the cell we want to pass this word + if (splitData[y].indexOf(splitSearch[x]) === 0) { + var newScore = splitSearch[x].length / splitData[y].length; + highest = { + pass: true, + score: highest.score < newScore ? newScore : highest.score, + }; + } + // Get the levenshtein similarity score for the two words + var steps = levenshtein(splitSearch[x], splitData[y]).similarity; + // If the levenshtein similarity score is better than a previous one for the search word then var's store it + if (steps > highest.score) { + highest.score = steps; + } + } + // If this cell has a higher scoring word than previously found to the search term in the row, store it + if (highestCollated[x].score < highest.score || highest.pass) { + highestCollated[x] = { + pass: highest.pass || highestCollated[x].pass + ? true + : highest.score > threshold, + score: highest.score, + }; + } + } + } + // Check that all of the search words have passed + for (var i = 0; i < highestCollated.length; i++) { + if (!highestCollated[i].pass) { + return { + pass: false, + score: Math.round((highestCollated.reduce((a, b) => a + b.score, 0) / + highestCollated.length) * + 100) + '%', + }; + } + } + // If we get to here, all scores greater than 0.5 so display the row + return { + pass: true, + score: Math.round((highestCollated.reduce((a, b) => a + b.score, 0) / + highestCollated.length) * + 100) + '%', + }; +} +DataTable.ext.search.push(function (settings, data, dataIndex) { + var initial = settings.oInit.fuzzySearch; + if (!initial) { + return true; + } + // 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; + } + var fromPlugin = false; + // Find the input element + var input = $('div.dataTables_filter 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 (typeof initialFuzzy === 'object' && initialFuzzy.toggleSmart) { + toggle = $('') + .insertAfter(input) + .css({ + border: 'none', + background: 'none', + position: 'relative', + right: '33px', + top: '0px', + cursor: 'pointer', + color: '#3b5e99', + 'margin-top': '1px', + }); + exact = $('') + .insertAfter(input) + .css(toggleCSS) + .css(fontBold) + .attr('highlighted', 'true'); + fuzzy = $('') + .insertAfter(input) + .css(toggleCSS); + input.css({ + 'padding-right': '30px', + }); + $(input.parent()).css('right', '-33px').css('position', 'relative'); + label = $('
Search Type
').css({ + 'padding-bottom': '0.5em', + 'font-size': '0.8em', + }); + tooltip = $('
') + .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); + } + // 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.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, rowIdx) { + settings.aoData[rowIdx]._fuzzySearch = undefined; + }, false); + searchVal = input.val(); + 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(); + 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, 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(); + input.val(fuzzySearchVal); + // For each row call the fuzzy search function to get result + api.rows().iterator('row', function (settings, 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) { + // 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(); + } + // 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() : fuzzySearchVal); + } + }); + // Always add this event no matter if toggling is enabled + input.on('input keydown', triggerSearchFunction); +}); + + +export default DataTable; diff --git a/features/fuzzySearch/src/dataTables.fuzzySearch.ts b/features/fuzzySearch/src/dataTables.fuzzySearch.ts new file mode 100644 index 0000000..bb3dcb0 --- /dev/null +++ b/features/fuzzySearch/src/dataTables.fuzzySearch.ts @@ -0,0 +1,512 @@ +/*! + * Fuzzy Search for DataTables + * 2021 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'; + +declare module 'datatables.net' { + interface Config { + fuzzySearch?: + | boolean + | { + rankColumn?: number; + threshold?: number; + toggleSmart?: boolean; + }; + } + + interface State { + _fuzzySearch: { + active: 'true' | 'false'; + val: any; + }; + } +} + +function levenshtein(__this, that, limit?) { + var thisLength = __this.length, + thatLength = that.length, + matrix: any[] = []; + + // If the limit is not defined it will be calculate from this and that args. + limit = (limit || (thatLength > thisLength ? thatLength : thisLength)) + 1; + + for (var i = 0; i < limit; i++) { + matrix[i] = [i]; + matrix[i].length = limit; + } + for (i = 0; i < limit; i++) { + matrix[0][i] = i; + } + + if (Math.abs(thisLength - thatLength) > (limit || 100)) { + return prepare(limit || 100); + } + if (thisLength === 0) { + return prepare(thatLength); + } + if (thatLength === 0) { + return prepare(thisLength); + } + + // Calculate matrix. + var j, this_i, that_j, cost, min, t; + for (i = 1; i <= thisLength; ++i) { + this_i = __this[i - 1]; + + // Step 4 + for (j = 1; j <= thatLength; ++j) { + // Check the jagged ld total so far + if (i === j && matrix[i][j] > 4) return prepare(thisLength); + + that_j = that[j - 1]; + cost = this_i === that_j ? 0 : 1; // Step 5 + // Calculate the minimum (much faster than Math.min(...)). + min = matrix[i - 1][j] + 1; // Devarion. + if ((t = matrix[i][j - 1] + 1) < min) min = t; // Insertion. + if ((t = matrix[i - 1][j - 1] + cost) < min) min = t; // Substitution. + + // Update matrix. + matrix[i][j] = + i > 1 && + j > 1 && + this_i === that[j - 2] && + __this[i - 2] === that_j && + (t = matrix[i - 2][j - 2] + cost) < min + ? t + : min; // Transposition. + } + } + + return prepare(matrix[thisLength][thatLength]); + + function prepare(steps) { + var length = Math.max(thisLength, thatLength); + var relative = length === 0 ? 0 : steps / length; + var similarity = 1 - relative; + return { + steps: steps, + relative: relative, + similarity: similarity, + }; + } +} + +function fuzzySearch(searchVal, data, initial) { + // If no searchVal has been defined then return all rows. + if (searchVal === undefined || searchVal.length === 0) { + return { + pass: true, + score: '', + }; + } + + var threshold = initial.threshold !== undefined ? initial.threshold : 0.5; + + // Split the searchVal into individual words. + var splitSearch = searchVal.split(/ /g); + + // Array to keep scores in + var highestCollated: { pass: boolean; score: number }[] = []; + + // Remove any empty words or spaces + for (var x = 0; x < splitSearch.length; x++) { + if (splitSearch[x].length === 0 || splitSearch[x] === ' ') { + splitSearch.splice(x, 1); + x--; + } + // Aside - Add to the score collection if not done so yet for this search word + else if (highestCollated.length < splitSearch.length) { + highestCollated.push({ pass: false, score: 0 }); + } + } + + // Going to check each cell for potential matches + for (var i = 0; i < data.length; i++) { + // Convert all data points to lower case fo insensitive sorting + data[i] = data[i].toLowerCase(); + + // Split the data into individual words + var splitData = data[i].split(/ /g); + + // Remove any empty words or spaces + for (var y = 0; y < splitData.length; y++) { + if (splitData[y].length === 0 || splitData[y] === ' ') { + splitData.splice(y, 1); + x--; + } + } + + // Check each search term word + for (var x = 0; x < splitSearch.length; x++) { + // Reset highest score + var highest: { pass?: boolean; score: number } = { + pass: undefined, + score: 0, + }; + + // Against each word in the cell + for (var y = 0; y < splitData.length; y++) { + // If this search Term word is the beginning of the word in the cell we want to pass this word + if (splitData[y].indexOf(splitSearch[x]) === 0) { + var newScore = splitSearch[x].length / splitData[y].length; + highest = { + pass: true, + score: highest.score < newScore ? newScore : highest.score, + }; + } + + // Get the levenshtein similarity score for the two words + var steps = levenshtein(splitSearch[x], splitData[y]).similarity; + + // If the levenshtein similarity score is better than a previous one for the search word then var's store it + if (steps > highest.score) { + highest.score = steps; + } + } + + // If this cell has a higher scoring word than previously found to the search term in the row, store it + if (highestCollated[x].score < highest.score || highest.pass) { + highestCollated[x] = { + pass: + highest.pass || highestCollated[x].pass + ? true + : highest.score > threshold, + score: highest.score, + }; + } + } + } + + // Check that all of the search words have passed + for (var i = 0; i < highestCollated.length; i++) { + if (!highestCollated[i].pass) { + return { + pass: false, + score: + Math.round( + (highestCollated.reduce((a, b) => a + b.score, 0) / + highestCollated.length) * + 100 + ) + '%', + }; + } + } + + // If we get to here, all scores greater than 0.5 so display the row + return { + pass: true, + score: + Math.round( + (highestCollated.reduce((a, b) => a + b.score, 0) / + highestCollated.length) * + 100 + ) + '%', + }; +} + +DataTable.ext.search.push(function (settings, data, dataIndex) { + var initial = settings.oInit.fuzzySearch; + + if (!initial) { + return true; + } + + // 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; + } + + var fromPlugin = false; + + // Find the input element + var input = $('div.dataTables_filter 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 (typeof initialFuzzy === 'object' && initialFuzzy.toggleSmart) { + toggle = $('') + .insertAfter(input) + .css({ + border: 'none', + background: 'none', + position: 'relative', + right: '33px', + top: '0px', + cursor: 'pointer', + color: '#3b5e99', + 'margin-top': '1px', + }); + exact = $('') + .insertAfter(input) + .css(toggleCSS) + .css(fontBold) + .attr('highlighted', 'true'); + fuzzy = $('') + .insertAfter(input) + .css(toggleCSS); + input.css({ + 'padding-right': '30px', + }); + $(input.parent()).css('right', '-33px').css('position', 'relative'); + label = $('
Search Type
').css({ + 'padding-bottom': '0.5em', + 'font-size': '0.8em', + }); + tooltip = $('
') + .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); + } + + // 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(); + 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) { + // 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(); + } + + // 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() : fuzzySearchVal); + } + }); + + // Always add this event no matter if toggling is enabled + input.on('input keydown', triggerSearchFunction); +}); diff --git a/features/lengthLinks/dataTables.lengthLinks.d.ts b/features/lengthLinks/dataTables.lengthLinks.d.ts new file mode 100644 index 0000000..ab03f3d --- /dev/null +++ b/features/lengthLinks/dataTables.lengthLinks.d.ts @@ -0,0 +1,8 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStatic { + /** Page length control via links for DataTables */ + LengthLinks(settings: any): void; + } +} +export {}; diff --git a/features/lengthLinks/dataTables.lengthLinks.js b/features/lengthLinks/dataTables.lengthLinks.js index 8304eaf..5433a5f 100644 --- a/features/lengthLinks/dataTables.lengthLinks.js +++ b/features/lengthLinks/dataTables.lengthLinks.js @@ -1,17 +1,48 @@ -/*! Page length control via links for DataTables - * 2014 SpryMedia Ltd - datatables.net/license - */ +/*! © SpryMedia Ltd - datatables.net/license */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + /** * @summary LengthLinks * @description Page length control via links for DataTables - * @version 1.1.0 - * @file dataTables.lengthLinks.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2014 SpryMedia Ltd. - * - * License MIT - http://datatables.net/license/mit + * @version 1.2.0 + * @author Allan Jardine * * This feature plug-in for DataTables adds page length control links to the * DataTable. The `dom` option can be used to insert the control using the `L` @@ -29,62 +60,51 @@ * dom: 'Lfrtip' * } ); */ - -(function(window, document, $, undefined) { - - -$.fn.dataTable.LengthLinks = function ( inst ) { - var api = new $.fn.dataTable.Api( inst ); - var settings = api.settings()[0]; - var container = $('
').addClass( settings.oClasses.sLength ); - var lastLength = null; - - // API so the feature wrapper can return the node to insert - this.container = function () { - return container[0]; - }; - - // Listen for events to change the page length - container.on( 'click.dtll', 'a', function (e) { - e.preventDefault(); - api.page.len( $(this).data('length')*1 ).draw( false ); - } ); - - // Update on each draw - api.on( 'draw', function () { - // No point in updating - nothing has changed - if ( api.page.len() === lastLength ) { - return; - } - - var menu = settings.aLengthMenu; - var lang = menu.length===2 && Array.isArray(menu[0]) ? menu[1] : menu; - var lens = menu.length===2 && Array.isArray(menu[0]) ? menu[0] : menu; - - var out = $.map( lens, function (el, i) { - return el == api.page.len() ? - ''+lang[i]+'' : - ''+lang[i]+''; - } ); - - container.html( settings.oLanguage.sLengthMenu.replace( '_MENU_', out.join(' | ') ) ); - lastLength = api.page.len(); - } ); - - api.on( 'destroy', function () { - container.off( 'click.dtll', 'a' ); - } ); +DataTable.LengthLinks = function (inst) { + var api = new DataTable.Api(inst); + var settings = api.settings()[0]; + var container = $('
').addClass(settings.oClasses.sLength); + var lastLength = null; + // API so the feature wrapper can return the node to insert + this.container = function () { + return container[0]; + }; + // Listen for events to change the page length + container.on('click.dtll', 'a', function (e) { + e.preventDefault(); + api.page.len($(this).data('length') * 1).draw(false); + }); + // Update on each draw + api.on('draw', function () { + // No point in updating - nothing has changed + if (api.page.len() === lastLength) { + return; + } + var menu = settings.aLengthMenu; + var lang = menu.length === 2 && Array.isArray(menu[0]) ? menu[1] : menu; + var lens = menu.length === 2 && Array.isArray(menu[0]) ? menu[0] : menu; + var out = $.map(lens, function (el, i) { + return el == api.page.len() + ? '' + lang[i] + '' + : '' + lang[i] + ''; + }); + container.html(settings.oLanguage.sLengthMenu.replace('_MENU_', out.join(' | '))); + lastLength = api.page.len(); + }); + api.on('destroy', function () { + container.off('click.dtll', 'a'); + }); }; - // Subscribe the feature plug-in to DataTables, ready for use -$.fn.dataTable.ext.feature.push( { - "fnInit": function( settings ) { - var l = new $.fn.dataTable.LengthLinks( settings ); - return l.container(); - }, - "cFeature": "L", - "sFeature": "LengthLinks" -} ); +DataTable.ext.feature.push({ + fnInit: function (settings) { + var l = new DataTable.LengthLinks(settings); + return l.container(); + }, + cFeature: 'L', + sFeature: 'LengthLinks', +}); -})(window, document, jQuery); +return DataTable; +})); diff --git a/features/lengthLinks/dataTables.lengthLinks.min.js b/features/lengthLinks/dataTables.lengthLinks.min.js index 6b6b870..e46a7f3 100644 --- a/features/lengthLinks/dataTables.lengthLinks.min.js +++ b/features/lengthLinks/dataTables.lengthLinks.min.js @@ -1,4 +1,2 @@ -/*! Page length control via links for DataTables - * 2014 SpryMedia Ltd - datatables.net/license - */ -!function(u){u.fn.dataTable.LengthLinks=function(n){var i=new u.fn.dataTable.Api(n),a=i.settings()[0],l=u("
").addClass(a.oClasses.sLength),r=null;this.container=function(){return l[0]},l.on("click.dtll","a",function(n){n.preventDefault(),i.page.len(+u(this).data("length")).draw(!1)}),i.on("draw",function(){var e,t,n;i.page.len()!==r&&(n=a.aLengthMenu,e=2===n.length&&Array.isArray(n[0])?n[1]:n,t=2===n.length&&Array.isArray(n[0])?n[0]:n,n=u.map(t,function(n,a){return n==i.page.len()?''+e[a]+"":''+e[a]+""}),l.html(a.oLanguage.sLengthMenu.replace("_MENU_",n.join(" | "))),r=i.page.len())}),i.on("destroy",function(){l.off("click.dtll","a")})},u.fn.dataTable.ext.feature.push({fnInit:function(n){return new u.fn.dataTable.LengthLinks(n).container()},cFeature:"L",sFeature:"LengthLinks"})}((window,document,jQuery)); \ No newline at end of file +/*! © SpryMedia Ltd - datatables.net/license */ +!function(t){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return t(e,window,document)}):"object"==typeof exports?module.exports=function(e,n){return e=e||window,(n=n||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,n),t(n,0,e.document)}:t(jQuery,window,document)}(function(o,e,n,t){"use strict";var a=o.fn.dataTable;return a.LengthLinks=function(e){var r=new a.Api(e),n=r.settings()[0],i=o("
").addClass(n.oClasses.sLength),u=null;this.container=function(){return i[0]},i.on("click.dtll","a",function(e){e.preventDefault(),r.page.len(+o(this).data("length")).draw(!1)}),r.on("draw",function(){var t,a,e;r.page.len()!==u&&(e=n.aLengthMenu,t=2===e.length&&Array.isArray(e[0])?e[1]:e,a=2===e.length&&Array.isArray(e[0])?e[0]:e,e=o.map(a,function(e,n){return e==r.page.len()?''+t[n]+"":''+t[n]+""}),i.html(n.oLanguage.sLengthMenu.replace("_MENU_",e.join(" | "))),u=r.page.len())}),r.on("destroy",function(){i.off("click.dtll","a")})},a.ext.feature.push({fnInit:function(e){return new a.LengthLinks(e).container()},cFeature:"L",sFeature:"LengthLinks"}),a}); \ No newline at end of file diff --git a/features/lengthLinks/dataTables.lengthLinks.min.mjs b/features/lengthLinks/dataTables.lengthLinks.min.mjs new file mode 100644 index 0000000..de94e1a --- /dev/null +++ b/features/lengthLinks/dataTables.lengthLinks.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";DataTable.LengthLinks=function(a){var r=new DataTable.Api(a),e=r.settings()[0],l=$("
").addClass(e.oClasses.sLength),i=null;this.container=function(){return l[0]},l.on("click.dtll","a",function(a){a.preventDefault(),r.page.len(+$(this).data("length")).draw(!1)}),r.on("draw",function(){var t,n,a;r.page.len()!==i&&(a=e.aLengthMenu,t=2===a.length&&Array.isArray(a[0])?a[1]:a,n=2===a.length&&Array.isArray(a[0])?a[0]:a,a=$.map(n,function(a,e){return a==r.page.len()?''+t[e]+"":''+t[e]+""}),l.html(e.oLanguage.sLengthMenu.replace("_MENU_",a.join(" | "))),i=r.page.len())}),r.on("destroy",function(){l.off("click.dtll","a")})},DataTable.ext.feature.push({fnInit:function(a){return new DataTable.LengthLinks(a).container()},cFeature:"L",sFeature:"LengthLinks"});export default DataTable; \ No newline at end of file diff --git a/features/lengthLinks/dataTables.lengthLinks.mjs b/features/lengthLinks/dataTables.lengthLinks.mjs new file mode 100644 index 0000000..29c69d8 --- /dev/null +++ b/features/lengthLinks/dataTables.lengthLinks.mjs @@ -0,0 +1,75 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary LengthLinks + * @description Page length control via links for DataTables + * @version 1.2.0 + * @author Allan Jardine + * + * This feature plug-in for DataTables adds page length control links to the + * DataTable. The `dom` option can be used to insert the control using the `L` + * character option and it uses the `lengthMenu` options of DataTables to + * determine what to display. + * + * @example + * $('#myTable').DataTable( { + * dom: 'Lfrtip' + * } ); + * + * @example + * $('#myTable').DataTable( { + * lengthMenu: [ [10, 25, 50, -1], [10, 25, 50, "All"] ] + * dom: 'Lfrtip' + * } ); + */ +DataTable.LengthLinks = function (inst) { + var api = new DataTable.Api(inst); + var settings = api.settings()[0]; + var container = $('
').addClass(settings.oClasses.sLength); + var lastLength = null; + // API so the feature wrapper can return the node to insert + this.container = function () { + return container[0]; + }; + // Listen for events to change the page length + container.on('click.dtll', 'a', function (e) { + e.preventDefault(); + api.page.len($(this).data('length') * 1).draw(false); + }); + // Update on each draw + api.on('draw', function () { + // No point in updating - nothing has changed + if (api.page.len() === lastLength) { + return; + } + var menu = settings.aLengthMenu; + var lang = menu.length === 2 && Array.isArray(menu[0]) ? menu[1] : menu; + var lens = menu.length === 2 && Array.isArray(menu[0]) ? menu[0] : menu; + var out = $.map(lens, function (el, i) { + return el == api.page.len() + ? '' + lang[i] + '' + : '' + lang[i] + ''; + }); + container.html(settings.oLanguage.sLengthMenu.replace('_MENU_', out.join(' | '))); + lastLength = api.page.len(); + }); + api.on('destroy', function () { + container.off('click.dtll', 'a'); + }); +}; +// Subscribe the feature plug-in to DataTables, ready for use +DataTable.ext.feature.push({ + fnInit: function (settings) { + var l = new DataTable.LengthLinks(settings); + return l.container(); + }, + cFeature: 'L', + sFeature: 'LengthLinks', +}); + + +export default DataTable; diff --git a/features/lengthLinks/src/dataTables.lengthLinks.ts b/features/lengthLinks/src/dataTables.lengthLinks.ts new file mode 100644 index 0000000..7affda6 --- /dev/null +++ b/features/lengthLinks/src/dataTables.lengthLinks.ts @@ -0,0 +1,88 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +/** + * @summary LengthLinks + * @description Page length control via links for DataTables + * @version 1.2.0 + * @author Allan Jardine + * + * This feature plug-in for DataTables adds page length control links to the + * DataTable. The `dom` option can be used to insert the control using the `L` + * character option and it uses the `lengthMenu` options of DataTables to + * determine what to display. + * + * @example + * $('#myTable').DataTable( { + * dom: 'Lfrtip' + * } ); + * + * @example + * $('#myTable').DataTable( { + * lengthMenu: [ [10, 25, 50, -1], [10, 25, 50, "All"] ] + * dom: 'Lfrtip' + * } ); + */ + +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface DataTablesStatic { + /** Page length control via links for DataTables */ + LengthLinks(settings: any): void; + } +} + +DataTable.LengthLinks = function (inst) { + var api = new DataTable.Api(inst); + var settings = api.settings()[0]; + var container = $('
').addClass(settings.oClasses.sLength); + var lastLength: number | null = null; + + // API so the feature wrapper can return the node to insert + this.container = function () { + return container[0]; + }; + + // Listen for events to change the page length + container.on('click.dtll', 'a', function (e) { + e.preventDefault(); + api.page.len($(this).data('length') * 1).draw(false); + }); + + // Update on each draw + api.on('draw', function () { + // No point in updating - nothing has changed + if (api.page.len() === lastLength) { + return; + } + + var menu = settings.aLengthMenu; + var lang = menu.length === 2 && Array.isArray(menu[0]) ? menu[1] : menu; + var lens = menu.length === 2 && Array.isArray(menu[0]) ? menu[0] : menu; + + var out = $.map(lens, function (el, i) { + return el == api.page.len() + ? '' + lang[i] + '' + : '' + lang[i] + ''; + }); + + container.html( + settings.oLanguage.sLengthMenu.replace('_MENU_', out.join(' | ')) + ); + lastLength = api.page.len(); + }); + + api.on('destroy', function () { + container.off('click.dtll', 'a'); + }); +}; + +// Subscribe the feature plug-in to DataTables, ready for use +DataTable.ext.feature.push({ + fnInit: function (settings) { + var l = new DataTable.LengthLinks(settings); + return l.container(); + }, + cFeature: 'L', + sFeature: 'LengthLinks', +}); diff --git a/features/mark.js/datatables.mark.d.ts b/features/mark.js/datatables.mark.d.ts new file mode 100644 index 0000000..06b5783 --- /dev/null +++ b/features/mark.js/datatables.mark.d.ts @@ -0,0 +1,12 @@ +/*!*************************************************** + * datatables.mark.js v3.0.0 + * https://github.com/julmot/datatables.mark.js + * Copyright (c) 2016–2020, Julian Kühnel, SpryMedia Ltd + * Released under the MIT license https://git.io/voRZ7 + *****************************************************/ +declare module 'datatables.net' { + interface Config { + mark?: boolean; + } +} +export {}; diff --git a/features/mark.js/datatables.mark.js b/features/mark.js/datatables.mark.js index 34688f8..a2eded9 100644 --- a/features/mark.js/datatables.mark.js +++ b/features/mark.js/datatables.mark.js @@ -1,119 +1,130 @@ /*!*************************************************** - * datatables.mark.js v2.1.0 + * datatables.mark.js v3.0.0 * https://github.com/julmot/datatables.mark.js - * Copyright (c) 2016–2020, Julian Kühnel + * Copyright (c) 2016–2020, Julian Kühnel, SpryMedia Ltd * Released under the MIT license https://git.io/voRZ7 *****************************************************/ -'use strict'; +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } -var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } -var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); + } -function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; -(function (factory, window, document) { - if ((typeof exports === 'undefined' ? 'undefined' : _typeof(exports)) === 'object') { - var jquery = require('jquery'); - require('datatables.net'); - require('mark.js/dist/jquery.mark.js'); - module.exports = factory(window, document, jquery); - } else if (typeof define === 'function' && define.amd) { - define(['jquery', 'datatables.net', 'markjs'], function (jQuery) { - return factory(window, document, jQuery); - }); - } else { - factory(window, document, jQuery); - } -})(function (window, document, $) { - var MarkDataTables = function () { - function MarkDataTables(dtInstance, options) { - _classCallCheck(this, MarkDataTables); - if (!$.fn.mark || !$.fn.unmark) { - throw new Error('jquery.mark.js is necessary for datatables.mark.js'); - } - this.instance = dtInstance; - this.options = (typeof options === 'undefined' ? 'undefined' : _typeof(options)) === 'object' ? options : {}; - this.intervalThreshold = 49; - this.intervalMs = 300; - this.initMarkListener(); +class MarkDataTables { + instance; + options; + intervalThreshold; + intervalMs; + constructor(dtInstance, options) { + if (!$.fn.mark || !$.fn.unmark) { + throw new Error('jquery.mark.js is necessary for datatables.mark.js'); + } + this.instance = dtInstance; + this.options = typeof options === 'object' ? options : {}; + this.intervalThreshold = 49; + this.intervalMs = 300; + this.initMarkListener(); } - - _createClass(MarkDataTables, [{ - key: 'initMarkListener', - value: function initMarkListener() { - var _this = this; - - var ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'; + initMarkListener() { + let ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'; ev += ' responsive-display.dt.dth'; - var intvl = null; - this.instance.on(ev, function () { - var rows = _this.instance.rows({ - filter: 'applied', - page: 'current' - }).nodes().length; - if (rows > _this.intervalThreshold) { - clearTimeout(intvl); - intvl = setTimeout(function () { - _this.mark(); - }, _this.intervalMs); - } else { - _this.mark(); - } + let intvl = null; + this.instance.on(ev, () => { + const rows = this.instance + .rows({ + filter: 'applied', + page: 'current', + }) + .nodes().length; + if (rows > this.intervalThreshold) { + clearTimeout(intvl); + intvl = setTimeout(() => { + this.mark(); + }, this.intervalMs); + } + else { + this.mark(); + } }); - this.instance.on('destroy', function () { - _this.instance.off(ev); + this.instance.on('destroy', () => { + this.instance.off(ev); }); this.mark(); - } - }, { - key: 'mark', - value: function mark() { - var _this2 = this; - - var globalSearch = this.instance.search(); - var $tableBody = $(this.instance.table().body()); + } + mark() { + const globalSearch = this.instance.search(); + const $tableBody = $(this.instance.table().body()); $tableBody.unmark(this.options); if (this.instance.table().rows({ search: 'applied' }).data().length) { - $tableBody.mark(globalSearch, this.options); + $tableBody.mark(globalSearch, this.options); } - this.instance.columns({ - search: 'applied', - page: 'current' - }).nodes().each(function (nodes, colIndex) { - var columnSearch = _this2.instance.column(colIndex).search(), - searchVal = columnSearch || globalSearch; - if (searchVal) { - nodes.forEach(function (node) { - $(node).unmark(_this2.options).mark(searchVal, _this2.options); - }); - } + this.instance + .columns({ + search: 'applied', + page: 'current', + }) + .nodes() + .each((nodes, colIndex) => { + const columnSearch = this.instance.column(colIndex).search(), searchVal = columnSearch || globalSearch; + if (searchVal) { + nodes.forEach(node => { + $(node).unmark(this.options).mark(searchVal, this.options); + }); + } }); - } - }]); - - return MarkDataTables; - }(); - - $(document).on('init.dt.dth', function (event, settings) { + } +} +$(document).on('init.dt.dth', (event, settings) => { if (event.namespace !== 'dt') { - return; + return; } - - var dtInstance = $.fn.dataTable.Api(settings); - - var options = null; + const dtInstance = new DataTable.Api(settings); + let options = false; if (dtInstance.init().mark) { - options = dtInstance.init().mark; - } else if ($.fn.dataTable.defaults.mark) { - options = $.fn.dataTable.defaults.mark; + options = dtInstance.init().mark; } - if (options === null) { - return; + else if (DataTable.defaults.mark) { + options = DataTable.defaults.mark; + } + if (!options) { + return; } - new MarkDataTables(dtInstance, options); - }); -}, window, document); +}); + + +return DataTable; +})); diff --git a/features/mark.js/datatables.mark.min.js b/features/mark.js/datatables.mark.min.js index 4220b8a..f7f94e7 100644 --- a/features/mark.js/datatables.mark.min.js +++ b/features/mark.js/datatables.mark.min.js @@ -1,7 +1,7 @@ /*!*************************************************** - * datatables.mark.js v2.1.0 + * datatables.mark.js v3.0.0 * https://github.com/julmot/datatables.mark.js - * Copyright (c) 2016–2020, Julian Kühnel + * Copyright (c) 2016–2020, Julian Kühnel, SpryMedia Ltd * Released under the MIT license https://git.io/voRZ7 *****************************************************/ -"use strict";var _createClass=function(){function a(t,e){for(var n=0;nt.intervalThreshold?(clearTimeout(n),n=setTimeout(function(){t.mark()},t.intervalMs)):t.mark()}),this.instance.on("destroy",function(){t.instance.off(e)}),this.mark()}},{key:"mark",value:function(){var a=this,r=this.instance.search(),t=i(this.instance.table().body());t.unmark(this.options),this.instance.table().rows({search:"applied"}).data().length&&t.mark(r,this.options),this.instance.columns({search:"applied",page:"current"}).nodes().each(function(t,e){var n=a.instance.column(e).search()||r;n&&t.forEach(function(t){i(t).unmark(a.options).mark(n,a.options)})})}}]),n);function n(t,e){if(_classCallCheck(this,n),!i.fn.mark||!i.fn.unmark)throw new Error("jquery.mark.js is necessary for datatables.mark.js");this.instance=t,this.options="object"===(void 0===e?"undefined":_typeof(e))?e:{},this.intervalThreshold=49,this.intervalMs=300,this.initMarkListener()}i(e).on("init.dt.dth",function(t,e){var n,a;"dt"===t.namespace&&(a=null,(n=i.fn.dataTable.Api(e)).init().mark?a=n.init().mark:i.fn.dataTable.defaults.mark&&(a=i.fn.dataTable.defaults.mark),null!==a&&new r(n,a))})},window,document); \ No newline at end of file +!function(n){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(t){return n(t,window,document)}):"object"==typeof exports?module.exports=function(t,e){return t=t||window,(e=e||("undefined"!=typeof window?require("jquery"):require("jquery")(t))).fn.dataTable||require("datatables.net")(t,e),n(e,0,t.document)}:n(jQuery,window,document)}(function(r,t,e,n){"use strict";var i=r.fn.dataTable;class s{instance;options;intervalThreshold;intervalMs;constructor(t,e){if(!r.fn.mark||!r.fn.unmark)throw new Error("jquery.mark.js is necessary for datatables.mark.js");this.instance=t,this.options="object"==typeof e?e:{},this.intervalThreshold=49,this.intervalMs=300,this.initMarkListener()}initMarkListener(){let t="draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth",e=(t+=" responsive-display.dt.dth",null);this.instance.on(t,()=>{this.instance.rows({filter:"applied",page:"current"}).nodes().length>this.intervalThreshold?(clearTimeout(e),e=setTimeout(()=>{this.mark()},this.intervalMs)):this.mark()}),this.instance.on("destroy",()=>{this.instance.off(t)}),this.mark()}mark(){const s=this.instance.search();var t=r(this.instance.table().body());t.unmark(this.options),this.instance.table().rows({search:"applied"}).data().length&&t.mark(s,this.options),this.instance.columns({search:"applied",page:"current"}).nodes().each((t,e)=>{const n=this.instance.column(e).search(),i=n||s;i&&t.forEach(t=>{r(t).unmark(this.options).mark(i,this.options)})})}}return r(e).on("init.dt.dth",(e,n)=>{if("dt"===e.namespace){e=new i.Api(n);let t=!1;e.init().mark?t=e.init().mark:i.defaults.mark&&(t=i.defaults.mark),t&&new s(e,t)}}),i}); \ No newline at end of file diff --git a/features/mark.js/datatables.mark.min.mjs b/features/mark.js/datatables.mark.min.mjs new file mode 100644 index 0000000..578a2f6 --- /dev/null +++ b/features/mark.js/datatables.mark.min.mjs @@ -0,0 +1,7 @@ +/*!*************************************************** + * datatables.mark.js v3.0.0 + * https://github.com/julmot/datatables.mark.js + * Copyright (c) 2016–2020, Julian Kühnel, SpryMedia Ltd + * Released under the MIT license https://git.io/voRZ7 + *****************************************************/ +import $ from"jquery";import DataTable from"datatables.net";class MarkDataTables{instance;options;intervalThreshold;intervalMs;constructor(t,a){if(!$.fn.mark||!$.fn.unmark)throw new Error("jquery.mark.js is necessary for datatables.mark.js");this.instance=t,this.options="object"==typeof a?a:{},this.intervalThreshold=49,this.intervalMs=300,this.initMarkListener()}initMarkListener(){let t="draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth",a=(t+=" responsive-display.dt.dth",null);this.instance.on(t,()=>{this.instance.rows({filter:"applied",page:"current"}).nodes().length>this.intervalThreshold?(clearTimeout(a),a=setTimeout(()=>{this.mark()},this.intervalMs)):this.mark()}),this.instance.on("destroy",()=>{this.instance.off(t)}),this.mark()}mark(){const i=this.instance.search();var t=$(this.instance.table().body());t.unmark(this.options),this.instance.table().rows({search:"applied"}).data().length&&t.mark(i,this.options),this.instance.columns({search:"applied",page:"current"}).nodes().each((t,a)=>{const e=this.instance.column(a).search(),s=e||i;s&&t.forEach(t=>{$(t).unmark(this.options).mark(s,this.options)})})}}$(document).on("init.dt.dth",(a,e)=>{if("dt"===a.namespace){a=new DataTable.Api(e);let t=!1;a.init().mark?t=a.init().mark:DataTable.defaults.mark&&(t=DataTable.defaults.mark),t&&new MarkDataTables(a,t)}});export default DataTable; \ No newline at end of file diff --git a/features/mark.js/datatables.mark.mjs b/features/mark.js/datatables.mark.mjs new file mode 100644 index 0000000..aa5a345 --- /dev/null +++ b/features/mark.js/datatables.mark.mjs @@ -0,0 +1,95 @@ +/*!*************************************************** + * datatables.mark.js v3.0.0 + * https://github.com/julmot/datatables.mark.js + * Copyright (c) 2016–2020, Julian Kühnel, SpryMedia Ltd + * Released under the MIT license https://git.io/voRZ7 + *****************************************************/ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +class MarkDataTables { + instance; + options; + intervalThreshold; + intervalMs; + constructor(dtInstance, options) { + if (!$.fn.mark || !$.fn.unmark) { + throw new Error('jquery.mark.js is necessary for datatables.mark.js'); + } + this.instance = dtInstance; + this.options = typeof options === 'object' ? options : {}; + this.intervalThreshold = 49; + this.intervalMs = 300; + this.initMarkListener(); + } + initMarkListener() { + let ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'; + ev += ' responsive-display.dt.dth'; + let intvl = null; + this.instance.on(ev, () => { + const rows = this.instance + .rows({ + filter: 'applied', + page: 'current', + }) + .nodes().length; + if (rows > this.intervalThreshold) { + clearTimeout(intvl); + intvl = setTimeout(() => { + this.mark(); + }, this.intervalMs); + } + else { + this.mark(); + } + }); + this.instance.on('destroy', () => { + this.instance.off(ev); + }); + this.mark(); + } + mark() { + const globalSearch = this.instance.search(); + const $tableBody = $(this.instance.table().body()); + $tableBody.unmark(this.options); + if (this.instance.table().rows({ search: 'applied' }).data().length) { + $tableBody.mark(globalSearch, this.options); + } + this.instance + .columns({ + search: 'applied', + page: 'current', + }) + .nodes() + .each((nodes, colIndex) => { + const columnSearch = this.instance.column(colIndex).search(), searchVal = columnSearch || globalSearch; + if (searchVal) { + nodes.forEach(node => { + $(node).unmark(this.options).mark(searchVal, this.options); + }); + } + }); + } +} +$(document).on('init.dt.dth', (event, settings) => { + if (event.namespace !== 'dt') { + return; + } + const dtInstance = new DataTable.Api(settings); + let options = false; + if (dtInstance.init().mark) { + options = dtInstance.init().mark; + } + else if (DataTable.defaults.mark) { + options = DataTable.defaults.mark; + } + if (!options) { + return; + } + new MarkDataTables(dtInstance, options); +}); + + +export default DataTable; diff --git a/features/mark.js/src/datatables.mark.ts b/features/mark.js/src/datatables.mark.ts new file mode 100644 index 0000000..e7cdbb0 --- /dev/null +++ b/features/mark.js/src/datatables.mark.ts @@ -0,0 +1,107 @@ +/*!*************************************************** + * datatables.mark.js v3.0.0 + * https://github.com/julmot/datatables.mark.js + * Copyright (c) 2016–2020, Julian Kühnel, SpryMedia Ltd + * Released under the MIT license https://git.io/voRZ7 + *****************************************************/ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface Config { + mark?: boolean; + } +} + +class MarkDataTables { + private instance; + private options; + private intervalThreshold: number; + private intervalMs: number; + + constructor(dtInstance, options) { + if (!($.fn as any).mark || !($.fn as any).unmark) { + throw new Error('jquery.mark.js is necessary for datatables.mark.js'); + } + this.instance = dtInstance; + this.options = typeof options === 'object' ? options : {}; + this.intervalThreshold = 49; + this.intervalMs = 300; + this.initMarkListener(); + } + + initMarkListener() { + let ev = 'draw.dt.dth column-visibility.dt.dth column-reorder.dt.dth'; + ev += ' responsive-display.dt.dth'; + let intvl: any = null; + this.instance.on(ev, () => { + const rows = this.instance + .rows({ + filter: 'applied', + page: 'current', + }) + .nodes().length; + if (rows > this.intervalThreshold) { + clearTimeout(intvl); + intvl = setTimeout(() => { + this.mark(); + }, this.intervalMs); + } + else { + this.mark(); + } + }); + this.instance.on('destroy', () => { + this.instance.off(ev); + }); + this.mark(); + } + + mark() { + const globalSearch = this.instance.search(); + const $tableBody = $(this.instance.table().body()) as any; + $tableBody.unmark(this.options); + if (this.instance.table().rows({ search: 'applied' }).data().length) { + $tableBody.mark(globalSearch, this.options); + } + this.instance + .columns({ + search: 'applied', + page: 'current', + }) + .nodes() + .each((nodes, colIndex) => { + const columnSearch = this.instance.column(colIndex).search(), + searchVal = columnSearch || globalSearch; + if (searchVal) { + nodes.forEach(node => { + ($(node) as any).unmark(this.options).mark(searchVal, this.options); + }); + } + }); + } +} + +$(document).on('init.dt.dth', (event, settings) => { + if (event.namespace !== 'dt') { + return; + } + + const dtInstance = new DataTable.Api(settings); + + let options: boolean | undefined = false; + + if (dtInstance.init().mark) { + options = dtInstance.init().mark; + } + else if (DataTable.defaults.mark) { + options = DataTable.defaults.mark; + } + + if (!options) { + return; + } + + new MarkDataTables(dtInstance, options); +}); diff --git a/features/pageResize/dataTables.pageResize.d.ts b/features/pageResize/dataTables.pageResize.d.ts new file mode 100644 index 0000000..f5224b9 --- /dev/null +++ b/features/pageResize/dataTables.pageResize.d.ts @@ -0,0 +1,12 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStatic { + /** Automatically alter the DataTables page length to fit the table into a container */ + PageResize(settings: any, pageResizeManualDelta: boolean): void; + } + interface Config { + pageResize?: boolean; + pageResizeManualDelta?: boolean; + } +} +export {}; diff --git a/features/pageResize/dataTables.pageResize.js b/features/pageResize/dataTables.pageResize.js index 161ce06..b25d8b9 100644 --- a/features/pageResize/dataTables.pageResize.js +++ b/features/pageResize/dataTables.pageResize.js @@ -1,39 +1,5 @@ -/*! PageResize for DataTables v1.0.0 - * 2015 SpryMedia Ltd - datatables.net/license - */ +/*! © SpryMedia Ltd - datatables.net/license */ -/** - * @summary PageResize - * @description Automatically alter the DataTables page length to fit the table - into a container - * @version 1.0.0 - * @file dataTables.pageResize.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2015 SpryMedia Ltd. - * - * License MIT - http://datatables.net/license/mit - * - * This feature plug-in for DataTables will automatically change the DataTables - * page length in order to fit inside its container. This can be particularly - * useful for control panels and other interfaces which resize dynamically with - * the user's browser window instead of scrolling. - * - * Page resizing in DataTables can be enabled by using any one of the following - * options: - * - * * Adding the class `pageResize` to the HTML table - * * Setting the `pageResize` parameter in the DataTables initialisation to - * be true - i.e. `pageResize: true` - * * Setting the `pageResize` parameter to be true in the DataTables - * defaults (thus causing all tables to have this feature) - i.e. - * `$.fn.dataTable.defaults.pageResize = true`. - * * Creating a new instance: `new $.fn.dataTable.PageResize( table );` where - * `table` is a DataTable's API instance. - * - * For more detailed information please see: - * http://datatables.net/blog/2015-04-10 - */ (function( factory ){ if ( typeof define === 'function' && define.amd ) { // AMD @@ -45,11 +11,19 @@ // CommonJS module.exports = function (root, $) { if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise root = window; } - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); } return factory( $, root, root.document ); @@ -61,178 +35,186 @@ } }(function( $, window, document, undefined ) { 'use strict'; +var DataTable = $.fn.dataTable; -var PageResize = function ( dt, pageResizeManualDelta ) -{ - var table = dt.table(); - - this.s = { - dt: dt, - host: $(table.container()).parent(), - header: $(table.header()), - footer: $(table.footer()), - body: $(table.body()), - container: $(table.container()), - table: $(table.node()), - delta: pageResizeManualDelta +/** + * @summary PageResize + * @description Automatically alter the DataTables page length to fit the table + into a container + * @version 1.1.0 + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * + * This feature plug-in for DataTables will automatically change the DataTables + * page length in order to fit inside its container. This can be particularly + * useful for control panels and other interfaces which resize dynamically with + * the user's browser window instead of scrolling. + * + * Page resizing in DataTables can be enabled by using any one of the following + * options: + * + * * Adding the class `pageResize` to the HTML table + * * Setting the `pageResize` parameter in the DataTables initialisation to + * be true - i.e. `pageResize: true` + * * Setting the `pageResize` parameter to be true in the DataTables + * defaults (thus causing all tables to have this feature) - i.e. + * `DataTable.defaults.pageResize = true`. + * * Creating a new instance: `new DataTable.PageResize( table );` where + * `table` is a DataTable's API instance. + * + * For more detailed information please see: + * http://datatables.net/blog/2015-04-10 + */ +var PageResize = function (dt, pageResizeManualDelta) { + var table = dt.table(); + this.s = { + dt: dt, + host: $(table.container()).parent(), + header: $(table.header()), + footer: $(table.footer()), + body: $(table.body()), + container: $(table.container()), + table: $(table.node()), + delta: pageResizeManualDelta, }; - this.sizes = { offsetTop: this._getOffsetTop(), tableHeight: this._getTableHeight(), containerHeight: this._getContainerHeight(), headerHeight: this._getHeaderHeight(), - footerHeight: this._getFooterHeight() + footerHeight: this._getFooterHeight(), }; - - var host = this.s.host; - if ( host.css('position') === 'static' ) { - host.css( 'position', 'relative' ); - } - + var host = this.s.host; + if (host.css('position') === 'static') { + host.css('position', 'relative'); + } var onDestroy = function () { dt.off('.pageResize', onDestroy); this.s.obj && this.s.obj.remove(); }.bind(this); dt.on('destroy.pageResize', onDestroy); - - this._attach(); - - // Delay the initial sizing until the table is fully initialized - // such that the pagination element is also added and can be taken - // into account. - var initEvent = 'init.pageResize'; - dt.on(initEvent, function () { - dt.off(initEvent); - this._size(); - }.bind(this)); + this._attach(); + // Delay the initial sizing until the table is fully initialized + // such that the pagination element is also added and can be taken + // into account. + var initEvent = 'init.pageResize'; + dt.on(initEvent, function () { + dt.off(initEvent); + this._size(); + }.bind(this)); }; - - PageResize.prototype = { - _size: function () - { - var settings = this.s; - var dt = settings.dt; - var t = dt.table(); - var rows = $( 'tr', settings.body ); - var rowHeight = rows.eq( rows.length > 1 ? 1 : 0 ).height(); // Attempt to use the second row if poss, for top and bottom border - var availableHeight = settings.host.height(); - var scrolling = t.header().parentNode !== t.body().parentNode; + _size: function () { + var settings = this.s; + var dt = settings.dt; + var t = dt.table(); + var rows = $('tr', settings.body); + var rowHeight = rows.eq(rows.length > 1 ? 1 : 0).height(); // Attempt to use the second row if poss, for top and bottom border + var availableHeight = settings.host.height(); + var scrolling = t.header().parentNode !== t.body().parentNode; var delta = settings.delta; - - var offsetTop = this.sizes.offsetTop = this._getOffsetTop(); - var tableHeight = this.sizes.tableHeight = this._getTableHeight(); - var containerHeight = this.sizes.containerHeight = this._getContainerHeight(); - var headerHeight = this.sizes.headerHeight = this._getHeaderHeight(); - var footerHeight = this.sizes.footerHeight = this._getFooterHeight(); - - // Subtract the height of the header, footer and the elements - // surrounding the table - if ( ! scrolling ) { - if ( t.header() ) { - availableHeight -= headerHeight; - } - if ( t.footer() ) { - availableHeight -= footerHeight; - } - } - availableHeight -= offsetTop; - availableHeight -= containerHeight - ( offsetTop + tableHeight ); - - if ( !isNaN( parseFloat( delta ) ) && isFinite( delta ) ) { - availableHeight -= delta; - } - - var drawRows = Math.floor( availableHeight / rowHeight ); - - if ( drawRows !== Infinity && drawRows !== -Infinity && - ! isNaN( drawRows ) && drawRows > 0 && - drawRows !== dt.page.len() - ) { - dt.page.len( drawRows ).draw(); - } - }, - - _attach: function () { - // There is no `resize` event for elements, so to trigger this effect, - // create an empty HTML document using an which will issue a - // resize event inside itself when the document resizes. Since it is - // 100% x 100% that will occur whenever the host element is resized. - var that = this; - var obj = $('') - .css( { - position: 'absolute', - top: 0, - left: 0, - height: '100%', - width: '100%', - zIndex: -1 - } ) - .attr( 'type', 'text/html' ); - - obj[0].onload = function () { - var body = this.contentDocument.body; - var height = body.offsetHeight; - - this.contentDocument.defaultView.onresize = function () { - + var offsetTop = (this.sizes.offsetTop = this._getOffsetTop()); + var tableHeight = (this.sizes.tableHeight = this._getTableHeight()); + var containerHeight = (this.sizes.containerHeight = + this._getContainerHeight()); + var headerHeight = (this.sizes.headerHeight = this._getHeaderHeight()); + var footerHeight = (this.sizes.footerHeight = this._getFooterHeight()); + // Subtract the height of the header, footer and the elements + // surrounding the table + if (!scrolling) { + if (t.header()) { + availableHeight -= headerHeight; + } + if (t.footer()) { + availableHeight -= footerHeight; + } + } + availableHeight -= offsetTop; + availableHeight -= containerHeight - (offsetTop + tableHeight); + if (!isNaN(parseFloat(delta)) && isFinite(delta)) { + availableHeight -= delta; + } + var drawRows = Math.floor(availableHeight / rowHeight); + if (drawRows !== Infinity && + drawRows !== -Infinity && + !isNaN(drawRows) && + drawRows > 0 && + drawRows !== dt.page.len()) { + dt.page.len(drawRows).draw(); + } + }, + _attach: function () { + // There is no `resize` event for elements, so to trigger this effect, + // create an empty HTML document using an which will issue a + // resize event inside itself when the document resizes. Since it is + // 100% x 100% that will occur whenever the host element is resized. + var that = this; + var obj = $('') + .css({ + position: 'absolute', + top: 0, + left: 0, + height: '100%', + width: '100%', + zIndex: -1, + }) + .attr('type', 'text/html'); + obj[0].onload = function () { + var contentDocument = this.contentDocument; + var body = contentDocument.body; + var height = body.offsetHeight; + contentDocument.defaultView.onresize = function () { var newHeight = body.clientHeight || body.offsetHeight; if (newHeight !== height) { height = newHeight; that._size(); return; } - // Width changes might lead to layout changes, which might require // resizing the table - if (that.sizes.offsetTop !== that._getOffsetTop() - || that.sizes.containerHeight !== that._getContainerHeight() - || that.sizes.tableHeight !== that._getTableHeight() - || that.sizes.headerHeight !== that._getHeaderHeight() - || that.sizes.footerHeight !== that._getFooterHeight()) { + if (that.sizes.offsetTop !== that._getOffsetTop() || + that.sizes.containerHeight !== that._getContainerHeight() || + that.sizes.tableHeight !== that._getTableHeight() || + that.sizes.headerHeight !== that._getHeaderHeight() || + that.sizes.footerHeight !== that._getFooterHeight()) { that._size(); return; } - - }; - }; - - obj - .appendTo( this.s.host ) - .attr( 'data', 'about:blank' ); - - this.s.obj = obj; - }, - - _getOffsetTop: function () { return $(this.s.table).offset().top; }, - _getTableHeight: function () { return this.s.table.height(); }, - _getContainerHeight: function () { return this.s.container.height(); }, - _getHeaderHeight: function () { return this.s.dt.table().header() ? this.s.header.height() : 0; }, - _getFooterHeight: function () { return this.s.dt.table().footer() ? this.s.footer.height() : 0; } - + }; + }; + obj.appendTo(this.s.host).attr('data', 'about:blank'); + this.s.obj = obj; + }, + _getOffsetTop: function () { + return $(this.s.table).offset().top; + }, + _getTableHeight: function () { + return this.s.table.height(); + }, + _getContainerHeight: function () { + return this.s.container.height(); + }, + _getHeaderHeight: function () { + return this.s.dt.table().header() ? this.s.header.height() : 0; + }, + _getFooterHeight: function () { + return this.s.dt.table().footer() ? this.s.footer.height() : 0; + }, }; - - -$.fn.dataTable.PageResize = PageResize; -$.fn.DataTable.PageResize = PageResize; - +DataTable.PageResize = PageResize; // Automatic initialisation listener -$(document).on( 'preInit.dt', function ( e, settings ) { - if ( e.namespace !== 'dt' ) { - return; - } - - var api = new $.fn.dataTable.Api( settings ); - - if ( $( api.table().node() ).hasClass( 'pageResize' ) || - settings.oInit.pageResize || - $.fn.dataTable.defaults.pageResize ) - { - new PageResize( api, settings.oInit.pageResizeManualDelta ); - } -} ); - - +$(document).on('preInit.dt', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + var api = new DataTable.Api(settings); + if ($(api.table().node()).hasClass('pageResize') || + settings.oInit.pageResize || + DataTable.defaults.pageResize) { + new PageResize(api, settings.oInit.pageResizeManualDelta); + } +}); + + +return DataTable; })); diff --git a/features/pageResize/dataTables.pageResize.min.js b/features/pageResize/dataTables.pageResize.min.js index 4cf634e..b8e080b 100644 --- a/features/pageResize/dataTables.pageResize.min.js +++ b/features/pageResize/dataTables.pageResize.min.js @@ -1,4 +1,2 @@ -/*! PageResize for DataTables v1.0.0 - * 2015 SpryMedia Ltd - datatables.net/license - */ -!function(i){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return i(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,t&&t.fn.dataTable||(t=require("datatables.net")(e,t).$),i(t,0,e.document)}:i(jQuery,window,document)}(function(d,e,t,i){"use strict";function s(e,t){var i=e.table();this.s={dt:e,host:d(i.container()).parent(),header:d(i.header()),footer:d(i.footer()),body:d(i.body()),container:d(i.container()),table:d(i.node()),delta:t},this.sizes={offsetTop:this._getOffsetTop(),tableHeight:this._getTableHeight(),containerHeight:this._getContainerHeight(),headerHeight:this._getHeaderHeight(),footerHeight:this._getFooterHeight()};"static"===(i=this.s.host).css("position")&&i.css("position","relative");var s=function(){e.off(".pageResize",s),this.s.obj&&this.s.obj.remove()}.bind(this),o=(e.on("destroy.pageResize",s),this._attach(),"init.pageResize");e.on(o,function(){e.off(o),this._size()}.bind(this))}s.prototype={_size:function(){var e=this.s,t=e.dt,i=t.table(),s=d("tr",e.body),s=s.eq(1").css({position:"absolute",top:0,left:0,height:"100%",width:"100%",zIndex:-1}).attr("type","text/html");e[0].onload=function(){var t=this.contentDocument.body,i=t.offsetHeight;this.contentDocument.defaultView.onresize=function(){var e=t.clientHeight||t.offsetHeight;e!==i?(i=e,s._size()):s.sizes.offsetTop===s._getOffsetTop()&&s.sizes.containerHeight===s._getContainerHeight()&&s.sizes.tableHeight===s._getTableHeight()&&s.sizes.headerHeight===s._getHeaderHeight()&&s.sizes.footerHeight===s._getFooterHeight()||s._size()}},e.appendTo(this.s.host).attr("data","about:blank"),this.s.obj=e},_getOffsetTop:function(){return d(this.s.table).offset().top},_getTableHeight:function(){return this.s.table.height()},_getContainerHeight:function(){return this.s.container.height()},_getHeaderHeight:function(){return this.s.dt.table().header()?this.s.header.height():0},_getFooterHeight:function(){return this.s.dt.table().footer()?this.s.footer.height():0}},d.fn.dataTable.PageResize=s,d.fn.DataTable.PageResize=s,d(t).on("preInit.dt",function(e,t){"dt"===e.namespace&&(e=new d.fn.dataTable.Api(t),d(e.table().node()).hasClass("pageResize")||t.oInit.pageResize||d.fn.dataTable.defaults.pageResize)&&new s(e,t.oInit.pageResizeManualDelta)})}); \ No newline at end of file +/*! © SpryMedia Ltd - datatables.net/license */ +!function(i){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return i(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,(t=t||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,t),i(t,0,e.document)}:i(jQuery,window,document)}(function(d,e,t,i){"use strict";function o(e,t){var i=e.table();this.s={dt:e,host:d(i.container()).parent(),header:d(i.header()),footer:d(i.footer()),body:d(i.body()),container:d(i.container()),table:d(i.node()),delta:t},this.sizes={offsetTop:this._getOffsetTop(),tableHeight:this._getTableHeight(),containerHeight:this._getContainerHeight(),headerHeight:this._getHeaderHeight(),footerHeight:this._getFooterHeight()};"static"===(i=this.s.host).css("position")&&i.css("position","relative");var o=function(){e.off(".pageResize",o),this.s.obj&&this.s.obj.remove()}.bind(this),s=(e.on("destroy.pageResize",o),this._attach(),"init.pageResize");e.on(s,function(){e.off(s),this._size()}.bind(this))}var s=d.fn.dataTable;return o.prototype={_size:function(){var e=this.s,t=e.dt,i=t.table(),o=d("tr",e.body),o=o.eq(1").css({position:"absolute",top:0,left:0,height:"100%",width:"100%",zIndex:-1}).attr("type","text/html");e[0].onload=function(){var e=this.contentDocument,t=e.body,i=t.offsetHeight;e.defaultView.onresize=function(){var e=t.clientHeight||t.offsetHeight;e!==i?(i=e,o._size()):o.sizes.offsetTop===o._getOffsetTop()&&o.sizes.containerHeight===o._getContainerHeight()&&o.sizes.tableHeight===o._getTableHeight()&&o.sizes.headerHeight===o._getHeaderHeight()&&o.sizes.footerHeight===o._getFooterHeight()||o._size()}},e.appendTo(this.s.host).attr("data","about:blank"),this.s.obj=e},_getOffsetTop:function(){return d(this.s.table).offset().top},_getTableHeight:function(){return this.s.table.height()},_getContainerHeight:function(){return this.s.container.height()},_getHeaderHeight:function(){return this.s.dt.table().header()?this.s.header.height():0},_getFooterHeight:function(){return this.s.dt.table().footer()?this.s.footer.height():0}},s.PageResize=o,d(t).on("preInit.dt",function(e,t){"dt"===e.namespace&&(e=new s.Api(t),d(e.table().node()).hasClass("pageResize")||t.oInit.pageResize||s.defaults.pageResize)&&new o(e,t.oInit.pageResizeManualDelta)}),s}); \ No newline at end of file diff --git a/features/pageResize/dataTables.pageResize.min.mjs b/features/pageResize/dataTables.pageResize.min.mjs new file mode 100644 index 0000000..b903fa2 --- /dev/null +++ b/features/pageResize/dataTables.pageResize.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";var PageResize=function(e,t){var i=e.table(),i=(this.s={dt:e,host:$(i.container()).parent(),header:$(i.header()),footer:$(i.footer()),body:$(i.body()),container:$(i.container()),table:$(i.node()),delta:t},this.sizes={offsetTop:this._getOffsetTop(),tableHeight:this._getTableHeight(),containerHeight:this._getContainerHeight(),headerHeight:this._getHeaderHeight(),footerHeight:this._getFooterHeight()},this.s.host),s=("static"===i.css("position")&&i.css("position","relative"),function(){e.off(".pageResize",s),this.s.obj&&this.s.obj.remove()}.bind(this)),o=(e.on("destroy.pageResize",s),this._attach(),"init.pageResize");e.on(o,function(){e.off(o),this._size()}.bind(this))};PageResize.prototype={_size:function(){var e=this.s,t=e.dt,i=t.table(),s=$("tr",e.body),s=s.eq(1").css({position:"absolute",top:0,left:0,height:"100%",width:"100%",zIndex:-1}).attr("type","text/html");e[0].onload=function(){var e=this.contentDocument,t=e.body,i=t.offsetHeight;e.defaultView.onresize=function(){var e=t.clientHeight||t.offsetHeight;e!==i?(i=e,s._size()):s.sizes.offsetTop===s._getOffsetTop()&&s.sizes.containerHeight===s._getContainerHeight()&&s.sizes.tableHeight===s._getTableHeight()&&s.sizes.headerHeight===s._getHeaderHeight()&&s.sizes.footerHeight===s._getFooterHeight()||s._size()}},e.appendTo(this.s.host).attr("data","about:blank"),this.s.obj=e},_getOffsetTop:function(){return $(this.s.table).offset().top},_getTableHeight:function(){return this.s.table.height()},_getContainerHeight:function(){return this.s.container.height()},_getHeaderHeight:function(){return this.s.dt.table().header()?this.s.header.height():0},_getFooterHeight:function(){return this.s.dt.table().footer()?this.s.footer.height():0}},DataTable.PageResize=PageResize,$(document).on("preInit.dt",function(e,t){"dt"===e.namespace&&(e=new DataTable.Api(t),$(e.table().node()).hasClass("pageResize")||t.oInit.pageResize||DataTable.defaults.pageResize)&&new PageResize(e,t.oInit.pageResizeManualDelta)});export default DataTable; \ No newline at end of file diff --git a/features/pageResize/dataTables.pageResize.mjs b/features/pageResize/dataTables.pageResize.mjs new file mode 100644 index 0000000..27f4ba7 --- /dev/null +++ b/features/pageResize/dataTables.pageResize.mjs @@ -0,0 +1,185 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary PageResize + * @description Automatically alter the DataTables page length to fit the table + into a container + * @version 1.1.0 + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * + * This feature plug-in for DataTables will automatically change the DataTables + * page length in order to fit inside its container. This can be particularly + * useful for control panels and other interfaces which resize dynamically with + * the user's browser window instead of scrolling. + * + * Page resizing in DataTables can be enabled by using any one of the following + * options: + * + * * Adding the class `pageResize` to the HTML table + * * Setting the `pageResize` parameter in the DataTables initialisation to + * be true - i.e. `pageResize: true` + * * Setting the `pageResize` parameter to be true in the DataTables + * defaults (thus causing all tables to have this feature) - i.e. + * `DataTable.defaults.pageResize = true`. + * * Creating a new instance: `new DataTable.PageResize( table );` where + * `table` is a DataTable's API instance. + * + * For more detailed information please see: + * http://datatables.net/blog/2015-04-10 + */ +var PageResize = function (dt, pageResizeManualDelta) { + var table = dt.table(); + this.s = { + dt: dt, + host: $(table.container()).parent(), + header: $(table.header()), + footer: $(table.footer()), + body: $(table.body()), + container: $(table.container()), + table: $(table.node()), + delta: pageResizeManualDelta, + }; + this.sizes = { + offsetTop: this._getOffsetTop(), + tableHeight: this._getTableHeight(), + containerHeight: this._getContainerHeight(), + headerHeight: this._getHeaderHeight(), + footerHeight: this._getFooterHeight(), + }; + var host = this.s.host; + if (host.css('position') === 'static') { + host.css('position', 'relative'); + } + var onDestroy = function () { + dt.off('.pageResize', onDestroy); + this.s.obj && this.s.obj.remove(); + }.bind(this); + dt.on('destroy.pageResize', onDestroy); + this._attach(); + // Delay the initial sizing until the table is fully initialized + // such that the pagination element is also added and can be taken + // into account. + var initEvent = 'init.pageResize'; + dt.on(initEvent, function () { + dt.off(initEvent); + this._size(); + }.bind(this)); +}; +PageResize.prototype = { + _size: function () { + var settings = this.s; + var dt = settings.dt; + var t = dt.table(); + var rows = $('tr', settings.body); + var rowHeight = rows.eq(rows.length > 1 ? 1 : 0).height(); // Attempt to use the second row if poss, for top and bottom border + var availableHeight = settings.host.height(); + var scrolling = t.header().parentNode !== t.body().parentNode; + var delta = settings.delta; + var offsetTop = (this.sizes.offsetTop = this._getOffsetTop()); + var tableHeight = (this.sizes.tableHeight = this._getTableHeight()); + var containerHeight = (this.sizes.containerHeight = + this._getContainerHeight()); + var headerHeight = (this.sizes.headerHeight = this._getHeaderHeight()); + var footerHeight = (this.sizes.footerHeight = this._getFooterHeight()); + // Subtract the height of the header, footer and the elements + // surrounding the table + if (!scrolling) { + if (t.header()) { + availableHeight -= headerHeight; + } + if (t.footer()) { + availableHeight -= footerHeight; + } + } + availableHeight -= offsetTop; + availableHeight -= containerHeight - (offsetTop + tableHeight); + if (!isNaN(parseFloat(delta)) && isFinite(delta)) { + availableHeight -= delta; + } + var drawRows = Math.floor(availableHeight / rowHeight); + if (drawRows !== Infinity && + drawRows !== -Infinity && + !isNaN(drawRows) && + drawRows > 0 && + drawRows !== dt.page.len()) { + dt.page.len(drawRows).draw(); + } + }, + _attach: function () { + // There is no `resize` event for elements, so to trigger this effect, + // create an empty HTML document using an which will issue a + // resize event inside itself when the document resizes. Since it is + // 100% x 100% that will occur whenever the host element is resized. + var that = this; + var obj = $('') + .css({ + position: 'absolute', + top: 0, + left: 0, + height: '100%', + width: '100%', + zIndex: -1, + }) + .attr('type', 'text/html'); + obj[0].onload = function () { + var contentDocument = this.contentDocument; + var body = contentDocument.body; + var height = body.offsetHeight; + contentDocument.defaultView.onresize = function () { + var newHeight = body.clientHeight || body.offsetHeight; + if (newHeight !== height) { + height = newHeight; + that._size(); + return; + } + // Width changes might lead to layout changes, which might require + // resizing the table + if (that.sizes.offsetTop !== that._getOffsetTop() || + that.sizes.containerHeight !== that._getContainerHeight() || + that.sizes.tableHeight !== that._getTableHeight() || + that.sizes.headerHeight !== that._getHeaderHeight() || + that.sizes.footerHeight !== that._getFooterHeight()) { + that._size(); + return; + } + }; + }; + obj.appendTo(this.s.host).attr('data', 'about:blank'); + this.s.obj = obj; + }, + _getOffsetTop: function () { + return $(this.s.table).offset().top; + }, + _getTableHeight: function () { + return this.s.table.height(); + }, + _getContainerHeight: function () { + return this.s.container.height(); + }, + _getHeaderHeight: function () { + return this.s.dt.table().header() ? this.s.header.height() : 0; + }, + _getFooterHeight: function () { + return this.s.dt.table().footer() ? this.s.footer.height() : 0; + }, +}; +DataTable.PageResize = PageResize; +// Automatic initialisation listener +$(document).on('preInit.dt', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + var api = new DataTable.Api(settings); + if ($(api.table().node()).hasClass('pageResize') || + settings.oInit.pageResize || + DataTable.defaults.pageResize) { + new PageResize(api, settings.oInit.pageResizeManualDelta); + } +}); + + +export default DataTable; diff --git a/features/pageResize/src/dataTables.pageResize.ts b/features/pageResize/src/dataTables.pageResize.ts new file mode 100644 index 0000000..0370821 --- /dev/null +++ b/features/pageResize/src/dataTables.pageResize.ts @@ -0,0 +1,225 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +/** + * @summary PageResize + * @description Automatically alter the DataTables page length to fit the table + into a container + * @version 1.1.0 + * @author SpryMedia Ltd (www.sprymedia.co.uk) + * + * This feature plug-in for DataTables will automatically change the DataTables + * page length in order to fit inside its container. This can be particularly + * useful for control panels and other interfaces which resize dynamically with + * the user's browser window instead of scrolling. + * + * Page resizing in DataTables can be enabled by using any one of the following + * options: + * + * * Adding the class `pageResize` to the HTML table + * * Setting the `pageResize` parameter in the DataTables initialisation to + * be true - i.e. `pageResize: true` + * * Setting the `pageResize` parameter to be true in the DataTables + * defaults (thus causing all tables to have this feature) - i.e. + * `DataTable.defaults.pageResize = true`. + * * Creating a new instance: `new DataTable.PageResize( table );` where + * `table` is a DataTable's API instance. + * + * For more detailed information please see: + * http://datatables.net/blog/2015-04-10 + */ + +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface DataTablesStatic { + /** Automatically alter the DataTables page length to fit the table into a container */ + PageResize(settings: any, pageResizeManualDelta: boolean): void; + } + + interface Config { + pageResize?: boolean; + pageResizeManualDelta?: boolean; + } +} + +var PageResize = function (dt, pageResizeManualDelta) { + var table = dt.table(); + + this.s = { + dt: dt, + host: $(table.container()).parent(), + header: $(table.header()), + footer: $(table.footer()), + body: $(table.body()), + container: $(table.container()), + table: $(table.node()), + delta: pageResizeManualDelta, + }; + + this.sizes = { + offsetTop: this._getOffsetTop(), + tableHeight: this._getTableHeight(), + containerHeight: this._getContainerHeight(), + headerHeight: this._getHeaderHeight(), + footerHeight: this._getFooterHeight(), + }; + + var host = this.s.host; + if (host.css('position') === 'static') { + host.css('position', 'relative'); + } + + var onDestroy = function () { + dt.off('.pageResize', onDestroy); + this.s.obj && this.s.obj.remove(); + }.bind(this); + dt.on('destroy.pageResize', onDestroy); + + this._attach(); + + // Delay the initial sizing until the table is fully initialized + // such that the pagination element is also added and can be taken + // into account. + var initEvent = 'init.pageResize'; + dt.on( + initEvent, + function () { + dt.off(initEvent); + this._size(); + }.bind(this) + ); +}; + +PageResize.prototype = { + _size: function () { + var settings = this.s; + var dt = settings.dt; + var t = dt.table(); + var rows = $('tr', settings.body); + var rowHeight = rows.eq(rows.length > 1 ? 1 : 0).height()!; // Attempt to use the second row if poss, for top and bottom border + var availableHeight = settings.host.height(); + var scrolling = t.header().parentNode !== t.body().parentNode; + var delta = settings.delta; + + var offsetTop = (this.sizes.offsetTop = this._getOffsetTop()); + var tableHeight = (this.sizes.tableHeight = this._getTableHeight()); + var containerHeight = (this.sizes.containerHeight = + this._getContainerHeight()); + var headerHeight = (this.sizes.headerHeight = this._getHeaderHeight()); + var footerHeight = (this.sizes.footerHeight = this._getFooterHeight()); + + // Subtract the height of the header, footer and the elements + // surrounding the table + if (!scrolling) { + if (t.header()) { + availableHeight -= headerHeight; + } + if (t.footer()) { + availableHeight -= footerHeight; + } + } + availableHeight -= offsetTop; + availableHeight -= containerHeight - (offsetTop + tableHeight); + + if (!isNaN(parseFloat(delta)) && isFinite(delta)) { + availableHeight -= delta; + } + + var drawRows = Math.floor(availableHeight / rowHeight); + + if ( + drawRows !== Infinity && + drawRows !== -Infinity && + !isNaN(drawRows) && + drawRows > 0 && + drawRows !== dt.page.len() + ) { + dt.page.len(drawRows).draw(); + } + }, + + _attach: function () { + // There is no `resize` event for elements, so to trigger this effect, + // create an empty HTML document using an which will issue a + // resize event inside itself when the document resizes. Since it is + // 100% x 100% that will occur whenever the host element is resized. + var that = this; + var obj = $('') + .css({ + position: 'absolute', + top: 0, + left: 0, + height: '100%', + width: '100%', + zIndex: -1, + }) + .attr('type', 'text/html'); + + obj[0].onload = function () { + var contentDocument = (this as any).contentDocument; + var body = contentDocument.body; + var height = body.offsetHeight; + + contentDocument.defaultView.onresize = function () { + var newHeight = body.clientHeight || body.offsetHeight; + if (newHeight !== height) { + height = newHeight; + that._size(); + return; + } + + // Width changes might lead to layout changes, which might require + // resizing the table + if ( + that.sizes.offsetTop !== that._getOffsetTop() || + that.sizes.containerHeight !== that._getContainerHeight() || + that.sizes.tableHeight !== that._getTableHeight() || + that.sizes.headerHeight !== that._getHeaderHeight() || + that.sizes.footerHeight !== that._getFooterHeight() + ) { + that._size(); + return; + } + }; + }; + + obj.appendTo(this.s.host).attr('data', 'about:blank'); + + this.s.obj = obj; + }, + + _getOffsetTop: function () { + return $(this.s.table).offset()!.top; + }, + _getTableHeight: function () { + return this.s.table.height(); + }, + _getContainerHeight: function () { + return this.s.container.height(); + }, + _getHeaderHeight: function () { + return this.s.dt.table().header() ? this.s.header.height() : 0; + }, + _getFooterHeight: function () { + return this.s.dt.table().footer() ? this.s.footer.height() : 0; + }, +}; + +DataTable.PageResize = PageResize; + +// Automatic initialisation listener +$(document).on('preInit.dt', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + + var api = new DataTable.Api(settings); + + if ( + $(api.table().node()).hasClass('pageResize') || + settings.oInit.pageResize || + DataTable.defaults.pageResize + ) { + new PageResize(api, settings.oInit.pageResizeManualDelta); + } +}); diff --git a/features/rowFill/dataTables.rowFill.d.ts b/features/rowFill/dataTables.rowFill.d.ts new file mode 100644 index 0000000..630b3ff --- /dev/null +++ b/features/rowFill/dataTables.rowFill.d.ts @@ -0,0 +1,11 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStatic { + /** Match the number of rows in a table to the page length */ + RowFill(settings: any): void; + } + interface Config { + rowFill?: boolean; + } +} +export {}; diff --git a/features/rowFill/dataTables.rowFill.js b/features/rowFill/dataTables.rowFill.js index 4214c98..f280cca 100644 --- a/features/rowFill/dataTables.rowFill.js +++ b/features/rowFill/dataTables.rowFill.js @@ -1,112 +1,106 @@ -/*! RowFill for DataTables v1.0.0 - * 2018 SpryMedia Ltd - datatables.net/license - */ +/*! © SpryMedia Ltd - datatables.net/license */ -/** - * @summary RowFill - * @description Match the number of rows in a table to the page length - * @version 1.0.0 - * @file dataTables.rowFill.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2018 SpryMedia Ltd. - * - * License MIT - http://datatables.net/license/mit - * - * This feature plug-in for DataTables will automatically insert temporary rows - * into a DataTable that draws a page that is less than the configured page - * length. This can be handy to ensure that your table always as (e.g.) 10 rows - * visible. - * - * Filler rows have the class `dt-rowFill--filler` assigned to them allowing for - * additional styling (e.g. reducing opacity). - * - * To enable for a table add `rowFill: true` to your DataTables configuration. - */ -(function(factory) { - if (typeof define === 'function' && define.amd) { +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { // AMD - define(['jquery', 'datatables.net'], function($) { - return factory($, window, document); - }); - } else if (typeof exports === 'object') { + define( ['jquery', 'datatables.net'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { // CommonJS - module.exports = function(root, $) { - if (!root) { + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise root = window; } - if (!$ || !$.fn.dataTable) { - $ = require('datatables.net')(root, $).$; + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); } - return factory($, root, root.document); + return factory( $, root, root.document ); }; - } else { + } + else { // Browser - factory(jQuery, window, document); + factory( jQuery, window, document ); } -})(function($, window, document, undefined) { - 'use strict'; - - var RowFill = function(dt, pageResizeManualDelta) { - var table = dt.table(); - - this.s = { - dt: dt, - body: $(table.body()) - }; - - this._attach(); - }; +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; - RowFill.prototype = { - _attach: function() { - var dt = this.s.dt; - var body = this.s.body; - dt.on('draw', function() { - var colspan = dt.columns(':visible').count(); - var rowCount = dt.rows({ page: 'current' }).count(); - var class1 = 'even'; - var class2 = 'odd'; - - // Take account of the fact that DataTables will show a "Nothing found" row - // for an empty record set - if (rowCount === 0) { - rowCount = 1; - } - - // Reverse for continuation from the DataTable rows when a odd number of rows - if ( rowCount % 2 === 0 ) { - class1 = 'odd'; - class2 = 'even'; - } - - for (var i = 0; i < dt.page.len() - rowCount; i++) { - body.append( - $(' ') - .addClass( i%2 === 0 ? class1 : class2 ) - .addClass( 'dt-rowFill--filler' ) - ); - } - }); - } - }; - - $.fn.dataTable.RowFill = RowFill; - $.fn.DataTable.RowFill = RowFill; - - // Automatic initialisation listener - $(document).on('preInit.dt', function(e, settings) { - if (e.namespace !== 'dt') { - return; - } +/** + * @summary RowFill + * @description Match the number of rows in a table to the page length + * @version 1.1.0 + * @author SpryMedia Ltd + * + * This feature plug-in for DataTables will automatically insert temporary rows + * into a DataTable that draws a page that is less than the configured page + * length. This can be handy to ensure that your table always as (e.g.) 10 rows + * visible. + * + * Filler rows have the class `dt-rowFill--filler` assigned to them allowing for + * additional styling (e.g. reducing opacity). + * + * To enable for a table add `rowFill: true` to your DataTables configuration. + */ +var RowFill = function (dt) { + var table = dt.table(); + this.s = { + dt: dt, + body: $(table.body()), + }; + this._attach(); +}; +RowFill.prototype = { + _attach: function () { + var dt = this.s.dt; + var body = this.s.body; + dt.on('draw', function () { + var colspan = dt.columns(':visible').count(); + var rowCount = dt.rows({ page: 'current' }).count(); + var class1 = 'even'; + var class2 = 'odd'; + // Take account of the fact that DataTables will show a "Nothing found" row + // for an empty record set + if (rowCount === 0) { + rowCount = 1; + } + // Reverse for continuation from the DataTable rows when a odd number of rows + if (rowCount % 2 === 0) { + class1 = 'odd'; + class2 = 'even'; + } + for (var i = 0; i < dt.page.len() - rowCount; i++) { + body.append($(' ') + .addClass(i % 2 === 0 ? class1 : class2) + .addClass('dt-rowFill--filler')); + } + }); + }, +}; +DataTable.RowFill = RowFill; +// Automatic initialisation listener +$(document).on('preInit.dt', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + var api = new DataTable.Api(settings); + if (settings.oInit.rowFill || DataTable.defaults.rowFill) { + new RowFill(api); + } +}); - var api = new $.fn.dataTable.Api(settings); - if (settings.oInit.rowFill || $.fn.dataTable.defaults.rowFill) { - new RowFill(api); - } - }); -}); +return DataTable; +})); diff --git a/features/rowFill/dataTables.rowFill.min.js b/features/rowFill/dataTables.rowFill.min.js index 762b5ba..249dc8d 100644 --- a/features/rowFill/dataTables.rowFill.min.js +++ b/features/rowFill/dataTables.rowFill.min.js @@ -1,4 +1,2 @@ -/*! RowFill for DataTables v1.0.0 - * 2018 SpryMedia Ltd - datatables.net/license - */ -!function(e){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(t){return e(t,window,document)}):"object"==typeof exports?module.exports=function(t,n){return t=t||window,n&&n.fn.dataTable||(n=require("datatables.net")(t,n).$),e(n,0,t.document)}:e(jQuery,window,document)}(function(l,t,n,e){"use strict";function a(t,n){var e=t.table();this.s={dt:t,body:l(e.body())},this._attach()}a.prototype={_attach:function(){var d=this.s.dt,i=this.s.body;d.on("draw",function(){var t=d.columns(":visible").count(),n=d.rows({page:"current"}).count(),e="even",a="odd";(n=0===n?1:n)%2==0&&(e="odd",a="even");for(var o=0;o ').addClass(o%2==0?e:a).addClass("dt-rowFill--filler"))})}},l.fn.dataTable.RowFill=a,l.fn.DataTable.RowFill=a,l(n).on("preInit.dt",function(t,n){"dt"===t.namespace&&(t=new l.fn.dataTable.Api(n),n.oInit.rowFill||l.fn.dataTable.defaults.rowFill)&&new a(t)})}); \ No newline at end of file +/*! © SpryMedia Ltd - datatables.net/license */ +!function(n){"function"==typeof define&&define.amd?define(["jquery","datatables.net"],function(e){return n(e,window,document)}):"object"==typeof exports?module.exports=function(e,t){return e=e||window,(t=t||("undefined"!=typeof window?require("jquery"):require("jquery")(e))).fn.dataTable||require("datatables.net")(e,t),n(t,0,e.document)}:n(jQuery,window,document)}(function(i,e,t,n){"use strict";function o(e){var t=e.table();this.s={dt:e,body:i(t.body())},this._attach()}var d=i.fn.dataTable;return o.prototype={_attach:function(){var r=this.s.dt,a=this.s.body;r.on("draw",function(){var e=r.columns(":visible").count(),t=r.rows({page:"current"}).count(),n="even",o="odd";(t=0===t?1:t)%2==0&&(n="odd",o="even");for(var d=0;d ').addClass(d%2==0?n:o).addClass("dt-rowFill--filler"))})}},d.RowFill=o,i(t).on("preInit.dt",function(e,t){"dt"===e.namespace&&(e=new d.Api(t),t.oInit.rowFill||d.defaults.rowFill)&&new o(e)}),d}); \ No newline at end of file diff --git a/features/rowFill/dataTables.rowFill.min.mjs b/features/rowFill/dataTables.rowFill.min.mjs new file mode 100644 index 0000000..d495851 --- /dev/null +++ b/features/rowFill/dataTables.rowFill.min.mjs @@ -0,0 +1,2 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +import $ from"jquery";import DataTable from"datatables.net";var RowFill=function(t){var a=t.table();this.s={dt:t,body:$(a.body())},this._attach()};RowFill.prototype={_attach:function(){var n=this.s.dt,d=this.s.body;n.on("draw",function(){var t=n.columns(":visible").count(),a=n.rows({page:"current"}).count(),o="even",l="odd";(a=0===a?1:a)%2==0&&(o="odd",l="even");for(var e=0;e ').addClass(e%2==0?o:l).addClass("dt-rowFill--filler"))})}},DataTable.RowFill=RowFill,$(document).on("preInit.dt",function(t,a){"dt"===t.namespace&&(t=new DataTable.Api(a),a.oInit.rowFill||DataTable.defaults.rowFill)&&new RowFill(t)});export default DataTable; \ No newline at end of file diff --git a/features/rowFill/dataTables.rowFill.mjs b/features/rowFill/dataTables.rowFill.mjs new file mode 100644 index 0000000..c4adc56 --- /dev/null +++ b/features/rowFill/dataTables.rowFill.mjs @@ -0,0 +1,71 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + + +/** + * @summary RowFill + * @description Match the number of rows in a table to the page length + * @version 1.1.0 + * @author SpryMedia Ltd + * + * This feature plug-in for DataTables will automatically insert temporary rows + * into a DataTable that draws a page that is less than the configured page + * length. This can be handy to ensure that your table always as (e.g.) 10 rows + * visible. + * + * Filler rows have the class `dt-rowFill--filler` assigned to them allowing for + * additional styling (e.g. reducing opacity). + * + * To enable for a table add `rowFill: true` to your DataTables configuration. + */ +var RowFill = function (dt) { + var table = dt.table(); + this.s = { + dt: dt, + body: $(table.body()), + }; + this._attach(); +}; +RowFill.prototype = { + _attach: function () { + var dt = this.s.dt; + var body = this.s.body; + dt.on('draw', function () { + var colspan = dt.columns(':visible').count(); + var rowCount = dt.rows({ page: 'current' }).count(); + var class1 = 'even'; + var class2 = 'odd'; + // Take account of the fact that DataTables will show a "Nothing found" row + // for an empty record set + if (rowCount === 0) { + rowCount = 1; + } + // Reverse for continuation from the DataTable rows when a odd number of rows + if (rowCount % 2 === 0) { + class1 = 'odd'; + class2 = 'even'; + } + for (var i = 0; i < dt.page.len() - rowCount; i++) { + body.append($(' ') + .addClass(i % 2 === 0 ? class1 : class2) + .addClass('dt-rowFill--filler')); + } + }); + }, +}; +DataTable.RowFill = RowFill; +// Automatic initialisation listener +$(document).on('preInit.dt', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + var api = new DataTable.Api(settings); + if (settings.oInit.rowFill || DataTable.defaults.rowFill) { + new RowFill(api); + } +}); + + +export default DataTable; diff --git a/features/rowFill/src/dataTables.rowFill.ts b/features/rowFill/src/dataTables.rowFill.ts new file mode 100644 index 0000000..fe26b7a --- /dev/null +++ b/features/rowFill/src/dataTables.rowFill.ts @@ -0,0 +1,92 @@ +/*! © SpryMedia Ltd - datatables.net/license */ + +/** + * @summary RowFill + * @description Match the number of rows in a table to the page length + * @version 1.1.0 + * @author SpryMedia Ltd + * + * This feature plug-in for DataTables will automatically insert temporary rows + * into a DataTable that draws a page that is less than the configured page + * length. This can be handy to ensure that your table always as (e.g.) 10 rows + * visible. + * + * Filler rows have the class `dt-rowFill--filler` assigned to them allowing for + * additional styling (e.g. reducing opacity). + * + * To enable for a table add `rowFill: true` to your DataTables configuration. + */ + +import $ from 'jquery'; +import DataTable from 'datatables.net'; + +declare module 'datatables.net' { + interface DataTablesStatic { + /** Match the number of rows in a table to the page length */ + RowFill(settings: any): void; + } + + interface Config { + rowFill?: boolean; + } +} + +var RowFill = function (dt) { + var table = dt.table(); + + this.s = { + dt: dt, + body: $(table.body()), + }; + + this._attach(); +}; + +RowFill.prototype = { + _attach: function () { + var dt = this.s.dt; + var body = this.s.body; + + dt.on('draw', function () { + var colspan = dt.columns(':visible').count(); + var rowCount = dt.rows({ page: 'current' }).count(); + var class1 = 'even'; + var class2 = 'odd'; + + // Take account of the fact that DataTables will show a "Nothing found" row + // for an empty record set + if (rowCount === 0) { + rowCount = 1; + } + + // Reverse for continuation from the DataTable rows when a odd number of rows + if (rowCount % 2 === 0) { + class1 = 'odd'; + class2 = 'even'; + } + + for (var i = 0; i < dt.page.len() - rowCount; i++) { + body.append( + $(' ') + .addClass(i % 2 === 0 ? class1 : class2) + .addClass('dt-rowFill--filler') + ); + } + }); + }, +}; + +DataTable.RowFill = RowFill; + +// Automatic initialisation listener +$(document).on('preInit.dt', function (e, settings) { + if (e.namespace !== 'dt') { + return; + } + + var api = new DataTable.Api(settings); + + if (settings.oInit.rowFill || DataTable.defaults.rowFill) { + new RowFill(api); + } +}); diff --git a/features/scrollResize/dataTables.scrollResize.d.ts b/features/scrollResize/dataTables.scrollResize.d.ts new file mode 100644 index 0000000..4560c58 --- /dev/null +++ b/features/scrollResize/dataTables.scrollResize.d.ts @@ -0,0 +1,11 @@ +/*! © SpryMedia Ltd - datatables.net/license */ +declare module 'datatables.net' { + interface DataTablesStatic { + /** Automatically alter the DataTables page length to fit the table into a container */ + ScrollResize(settings: any): void; + } + interface Config { + scrollResize?: boolean; + } +} +export {}; diff --git a/features/scrollResize/dataTables.scrollResize.js b/features/scrollResize/dataTables.scrollResize.js index 6c6a1f4..4f6ef30 100644 --- a/features/scrollResize/dataTables.scrollResize.js +++ b/features/scrollResize/dataTables.scrollResize.js @@ -1,35 +1,5 @@ -/*! ScrollResize for DataTables v1.0.0 - * 2015 SpryMedia Ltd - datatables.net/license - */ +/*! © SpryMedia Ltd - datatables.net/license */ -/** - * @summary ScrollResize - * @description Automatically alter the DataTables page length to fit the table - into a container - * @version 1.0.0 - * @file dataTables.scrollResize.js - * @author SpryMedia Ltd (www.sprymedia.co.uk) - * @contact www.sprymedia.co.uk/contact - * @copyright Copyright 2015 SpryMedia Ltd. - * - * License MIT - http://datatables.net/license/mit - * - * This feature plug-in for DataTables will automatically change the DataTables - * page length in order to fit inside its container. This can be particularly - * useful for control panels and other interfaces which resize dynamically with - * the user's browser window instead of scrolling. - * - * Page resizing in DataTables can be enabled by using any one of the following - * options: - * - * * Setting the `scrollResize` parameter in the DataTables initialisation to - * be true - i.e. `scrollResize: true` - * * Setting the `scrollResize` parameter to be true in the DataTables - * defaults (thus causing all tables to have this feature) - i.e. - * `$.fn.dataTable.defaults.scrollResize = true`. - * * Creating a new instance: `new $.fn.dataTable.ScrollResize( table );` where - * `table` is a DataTable's API instance. - */ (function( factory ){ if ( typeof define === 'function' && define.amd ) { // AMD @@ -41,11 +11,19 @@ // CommonJS module.exports = function (root, $) { if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise root = window; } - if ( ! $ || ! $.fn.dataTable ) { - $ = require('datatables.net')(root, $).$; + if ( ! $ ) { + $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window + require('jquery') : + require('jquery')( root ); + } + + if ( ! $.fn.dataTable ) { + require('datatables.net')(root, $); } return factory( $, root, root.document ); @@ -57,139 +35,139 @@ } }(function( $, window, document, undefined ) { 'use strict'; +var DataTable = $.fn.dataTable; -var ScrollResize = function ( dt ) -{ - var that = this; - var table = dt.table(); - - this.s = { - dt: dt, - host: $(table.container()).parent(), - header: $(table.header()), - footer: $(table.footer()), - body: $(table.body()), - container: $(table.container()), - table: $(table.node()) - }; - - var host = this.s.host; - if ( host.css('position') === 'static' ) { - host.css( 'position', 'relative' ); - } - - dt.on( 'draw.scrollResize', function () { - that._size(); - } ); - - dt.on('destroy.scrollResize', function () { - dt.off('.scrollResize'); - this.s.obj && this.s.obj.remove(); - }.bind(this)); - - this._attach(); - this._size(); - - // Redraw the header if the scrollbar was visible before feature - // initialization, but no longer after initialization. Otherwise, - // the header width would differ from the body width, because the - // scrollbar is no longer present. - var settings = dt.settings()[0]; - var divBodyEl = settings.nScrollBody; - var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; - if (settings.scrollBarVis && !scrollBarVis) { - dt.columns.adjust(); - } +/** + * @summary ScrollResize + * @description Automatically alter the DataTables page length to fit the table + into a container + * @version 1.1.0 + * @author SpryMedia Ltd + * + * This feature plug-in for DataTables will automatically change the DataTables + * page length in order to fit inside its container. This can be particularly + * useful for control panels and other interfaces which resize dynamically with + * the user's browser window instead of scrolling. + * + * Page resizing in DataTables can be enabled by using any one of the following + * options: + * + * * Setting the `scrollResize` parameter in the DataTables initialisation to + * be true - i.e. `scrollResize: true` + * * Setting the `scrollResize` parameter to be true in the DataTables + * defaults (thus causing all tables to have this feature) - i.e. + * `DataTable.defaults.scrollResize = true`. + * * Creating a new instance: `new DataTable.ScrollResize( table );` where + * `table` is a DataTable's API instance. + */ +var ScrollResize = function (dt) { + var that = this; + var table = dt.table(); + this.s = { + dt: dt, + host: $(table.container()).parent(), + header: $(table.header()), + footer: $(table.footer()), + body: $(table.body()), + container: $(table.container()), + table: $(table.node()), + }; + var host = this.s.host; + if (host.css('position') === 'static') { + host.css('position', 'relative'); + } + dt.on('draw.scrollResize', function () { + that._size(); + }); + dt.on('destroy.scrollResize', function () { + dt.off('.scrollResize'); + this.s.obj && this.s.obj.remove(); + }.bind(this)); + this._attach(); + this._size(); + // Redraw the header if the scrollbar was visible before feature + // initialization, but no longer after initialization. Otherwise, + // the header width would differ from the body width, because the + // scrollbar is no longer present. + var settings = dt.settings()[0]; + var divBodyEl = settings.nScrollBody; + var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight; + if (settings.scrollBarVis && !scrollBarVis) { + dt.columns.adjust(); + } }; - - ScrollResize.prototype = { - _size: function () - { - var settings = this.s; - var dt = settings.dt; - var t = dt.table(); - var offsetTop = $( settings.table ).offset().top; - var availableHeight = settings.host.height(); - var scrollBody = $('div.dataTables_scrollBody', t.container()); - - // Subtract the height of the header, footer and the elements - // surrounding the table - availableHeight -= offsetTop; - availableHeight -= settings.container.height() - ( offsetTop + scrollBody.height() ); - - $('div.dataTables_scrollBody', t.container()).css( { - maxHeight: availableHeight, - height: availableHeight - } ); - }, - - _attach: function () { - // There is no `resize` event for elements, so to trigger this effect, - // create an empty HTML document using an