PageSourceSearch

https://www.psh-bult.de/files/luxe/js/ColumnFilterWidgets.js

js psh-bult.de collected 2026-10-08 09:37:35 UTC 10,806 bytes, 300 lines download raw bytes

1/*
2 * File:        ColumnFilterWidgets.js
3 * Version:     1.0.2
4 * Description: Controls for filtering based on unique column values in DataTables
5 * Author:      Dylan Kuhn (www.cyberhobo.net)
6 * Language:    Javascript
7 * License:     GPL v2 or BSD 3 point style
8 * Contact:     [email protected]
9 * 
10 * Copyright 2011 Dylan Kuhn (except fnGetColumnData by Benedikt Forchhammer), all rights reserved.
11 *
12 * This source file is free software, under either the GPL v2 license or a
13 * BSD style license, available at:
14 *   http://datatables.net/license_gpl2
15 *   http://datatables.net/license_bsd
16 */
17
18(function($) {
19	/*
20	 * Function: fnGetColumnData
21	 * Purpose:  Return an array of table values from a particular column.
22	 * Returns:  array string: 1d data array 
23	 * Inputs:   object:oSettings - dataTable settings object. This is always the last argument past to the function
24	 *           int:iColumn - the id of the column to extract the data from
25	 *           bool:bUnique - optional - if set to false duplicated values are not filtered out
26	 *           bool:bFiltered - optional - if set to false all the table data is used (not only the filtered)
27	 *           bool:bIgnoreEmpty - optional - if set to false empty values are not filtered from the result array
28	 * Author:   Benedikt Forchhammer <b.forchhammer /AT\ mind2.de>
29	 */
30
31	$.fn.dataTableExt.oApi.fnGetColumnData = function ( oSettings, iColumn, bUnique, bFiltered, bIgnoreEmpty ) {
32		// check that we have a column id
33		if ( typeof iColumn == "undefined" ) return new Array();
34		
35		// by default we only wany unique data
36		if ( typeof bUnique == "undefined" ) bUnique = true;
37		
38		// by default we do want to only look at filtered data
39		if ( typeof bFiltered == "undefined" ) bFiltered = true;
40		
41		// by default we do not wany to include empty values
42		if ( typeof bIgnoreEmpty == "undefined" ) bIgnoreEmpty = true;
43		
44		// list of rows which we're going to loop through
45		var aiRows;
46		
47		// use only filtered rows
48		if (bFiltered == true) aiRows = oSettings.aiDisplay; 
49		// use all rows
50		else aiRows = oSettings.aiDisplayMaster; // all row numbers
51	
52		// set up data array	
53		var asResultData = new Array();
54		
55		for (var i=0,c=aiRows.length; i<c; i++) {
56			iRow = aiRows[i];
57			var aData = this.fnGetData(iRow);
58			var sValue = aData[iColumn];
59			
60			// ignore empty values?
61			if (bIgnoreEmpty == true && sValue.length == 0) continue;
62	
63			// ignore unique values?
64			else if (bUnique == true && jQuery.inArray(sValue, asResultData) > -1) continue;
65			
66			// else push the value onto the result data array
67			else asResultData.push(sValue);
68		}
69		
70		return asResultData;
71	};
72
73	/**
74	* Add backslashes to regular expression symbols in a string.
75	* 
76	* Allows a regular expression to be constructed to search for 
77	* variable text.
78	* 
79	* @param string sText The text to escape.
80	* @return string The escaped string.
81	*/
82	var fnRegExpEscape = function( sText ) { 
83		return sText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 
84	};
85
86	/**
87	* Menu-based filter widgets based on distinct column values for a table.
88	*
89	* @class ColumnFilterWidgets 
90	* @constructor
91	* @param {object} oDataTableSettings Settings for the target table.
92	*/
93	var ColumnFilterWidgets = function( oDataTableSettings ) {
94		var me = this;
95		var sExcludeList = '';
96		me.$WidgetContainer = $( '<div class="column-filter-widgets"></div>' );
97		me.$MenuContainer = me.$WidgetContainer;
98		me.$TermContainer = null;
99		me.aoWidgets = [];
100		me.sSeparator = '';
101		if ( 'oColumnFilterWidgets' in oDataTableSettings.oInit ) {
102			if ( 'aiExclude' in oDataTableSettings.oInit.oColumnFilterWidgets ) {
103				sExcludeList = '|' + oDataTableSettings.oInit.oColumnFilterWidgets.aiExclude.join( '|' ) + '|';
104			}
105			if ( 'bGroupTerms' in oDataTableSettings.oInit.oColumnFilterWidgets && oDataTableSettings.oInit.oColumnFilterWidgets.bGroupTerms ) {
106				me.$MenuContainer = $( '<div class="column-filter-widget-menus"></div>' );
107				me.$TermContainer = $( '<div class="column-filter-widget-selected-terms"></div>' ).hide();
108			}
109		}
110
111		// Add a widget for each visible and filtered column
112		$.each( oDataTableSettings.aoColumns, function ( i, oColumn ) {
113			var $columnTh = $( oColumn.nTh );
114			var $WidgetElem = $( '<div class="column-filter-widget"></div>' );
115			if ( oColumn.bVisible && sExcludeList.indexOf( '|' + i + '|' ) < 0 ) {
116				me.aoWidgets.push( new ColumnFilterWidget( $WidgetElem, oDataTableSettings, i, me ) );
117			}
118			me.$MenuContainer.append( $WidgetElem );
119		} );
120		if ( me.$TermContainer ) {
121			me.$WidgetContainer.append( me.$MenuContainer );
122			me.$WidgetContainer.append( me.$TermContainer );
123		}
124		oDataTableSettings.aoDrawCallback.push( {
125			name: 'ColumnFilterWidgets',
126			fn: function() {
127				$.each( me.aoWidgets, function( i, oWidget ) {
128					oWidget.fnDraw();
129				} );
130			}
131		} );
132
133		return me;
134	};
135
136	/**
137	* Get the container node of the column filter widgets.
138	* 
139	* @method
140	* @return {Node} The container node.
141	*/
142	ColumnFilterWidgets.prototype.getContainer = function() {
143		return this.$WidgetContainer.get( 0 );
144	}
145
146	/**
147	* A filter widget based on data in a table column.
148	* 
149	* @class ColumnFilterWidget
150	* @constructor
151	* @param {object} $Container The jQuery object that should contain the widget.
152	* @param {object} oSettings The target table's settings.
153	* @param {number} i The numeric index of the target table column.
154	* @param {object} widgets The ColumnFilterWidgets instance the widget is a member of.
155	*/
156	var ColumnFilterWidget = function( $Container, oDataTableSettings, i, widgets ) {
157		var widget = this;
158		widget.iColumn = i;
159		widget.oColumn = oDataTableSettings.aoColumns[i];
160		widget.$Container = $Container;
161		widget.oDataTable = oDataTableSettings.oInstance;
162		widget.asFilters = [];
163		widget.sSeparator = '';
164		widget.iMaxSelections = -1;
165		if ( 'oColumnFilterWidgets' in oDataTableSettings.oInit ) {
166			if ( 'sSeparator' in oDataTableSettings.oInit.oColumnFilterWidgets ) {
167				widget.sSeparator = oDataTableSettings.oInit.oColumnFilterWidgets.sSeparator;
168			}
169			if ( 'iMaxSelections' in oDataTableSettings.oInit.oColumnFilterWidgets ) {
170				widget.iMaxSelections = oDataTableSettings.oInit.oColumnFilterWidgets.iMaxSelections;
171			}
172		}
173		widget.$Select = $( '<select></select>' ).change( function() {
174			var sSelected = widget.$Select.val(), sText, $TermLink, $SelectedOption; 
175			if ( '' === sSelected ) {
176				// The blank option is a default, not a filter, and is re-selected after filtering
177				return;
178			}
179			sText = $( '<div>' + sSelected + '</div>' ).text();
180			$TermLink = $( '<a class="filter-term" href="#"></a>' ).text( 'Filter deaktivieren' ).click( function() {
181				// Remove from current filters array
182				widget.asFilters = $.grep( widget.asFilters, function( sFilter ) {
183					return sFilter != sSelected;
184				} );
185				$TermLink.remove();
186				if ( widgets.$TermContainer && 0 === widgets.$TermContainer.find( '.filter-term' ).length ) {
187					widgets.$TermContainer.hide();
188				}
189				// Add it back to the select
190				widget.$Select.append( $( '<option></option>' ).attr( 'value', sSelected ).text( sText ) );
191				if ( widget.iMaxSelections > 0 && widget.iMaxSelections > widget.asFilters.length ) {
192					widget.$Select.attr( 'disabled', false );
193				}
194				widget.fnFilter();
195				return false;
196			} );
197			widget.asFilters.push( sSelected );
198			if ( widgets.$TermContainer ) {
199				widgets.$TermContainer.show();
200				widgets.$TermContainer.prepend( $TermLink );
201			} else {
202				widget.$Select.after( $TermLink );
203			}
204			$SelectedOption = widget.$Select.children( 'option:selected' );
205			widget.$Select.val( '' );
206			$SelectedOption.remove();
207			if ( widget.iMaxSelections > 0 && widget.iMaxSelections <= widget.asFilters.length ) {
208				widget.$Select.attr( 'disabled', true );
209			}
210			widget.fnFilter();
211		} );
212		widget.$Container.append( widget.$Select );
213		widget.fnDraw();
214	};
215
216	/**
217	* Perform filtering on the target column.
218	* 
219	* @method fnFilter
220	*/
221	ColumnFilterWidget.prototype.fnFilter = function() {
222		var widget = this;
223		var asEscapedFilters = [];
224		var sFilterStart, sFilterEnd;
225		if ( widget.asFilters.length > 0 ) {
226			// Filters must have RegExp symbols escaped
227			$.each( widget.asFilters, function( i, sFilter ) {
228				asEscapedFilters.push( fnRegExpEscape( sFilter ) );
229			} );
230			// This regular expression filters by either whole column values or an item in a comma list
231			sFilterStart = widget.sSeparator ? '(^|' + widget.sSeparator + ')(' : '^(';
232			sFilterEnd = widget.sSeparator ? ')(' + widget.sSeparator + '|$)' : ')$';
233			widget.oDataTable.fnFilter( sFilterStart + asEscapedFilters.join('|') + sFilterEnd, widget.iColumn, true, false );
234		} else { 
235			// Clear any filters for this column
236			widget.oDataTable.fnFilter( '', widget.iColumn );
237		}
238	};
239
240	/**
241	* On each table draw, update filter menu items as needed. This allows any process to
242	* update the table's column visiblity and menus will still be accurate.
243	* 
244	* @method fnDraw
245	*/
246	ColumnFilterWidget.prototype.fnDraw = function() {
247		var widget = this;
248		var oDistinctOptions = {};
249		var aDistinctOptions = [];
250		var aData;
251		if ( widget.asFilters.length === 0 ) {
252			// Find distinct column values
253			aData = widget.oDataTable.fnGetColumnData( widget.iColumn );
254			$.each( aData, function( i, sValue ) {
255				var asValues = widget.sSeparator ? sValue.split( new RegExp( widget.sSeparator ) ) : [ sValue ];
256				$.each( asValues, function( j, sOption ) {
257					if ( !oDistinctOptions.hasOwnProperty( sOption ) ) {
258						oDistinctOptions[sOption] = true;
259						aDistinctOptions.push( sOption );
260					}
261				} );
262			} );
263			// Build the menu
264			widget.$Select.empty().append( $( '<option></option>' ).attr( 'value', '' ).text( widget.oColumn.sTitle ) );
265			aDistinctOptions.sort();
266			$.each( aDistinctOptions, function( i, sOption ) {
267				var sText; 
268				sText = $( '<div>' + sOption + '</div>' ).text();
269				widget.$Select.append( $( '<option></option>' ).attr( 'value', sOption ).text( sText ) );
270			} );
271			if ( aDistinctOptions.length > 1 ) {
272				// Enable the menu 
273				widget.$Select.attr( 'disabled', false );
274			} else {
275				// One option is not a useful menu, disable it
276				widget.$Select.attr( 'disabled', true );
277			}
278		}
279	};
280
281	/*
282	 * Register a new feature with DataTables
283	 */
284	if ( typeof $.fn.dataTable === 'function' && typeof $.fn.dataTableExt.fnVersionCheck === 'function' && $.fn.dataTableExt.fnVersionCheck('1.7.0') ) {
285
286		$.fn.dataTableExt.aoFeatures.push( {
287			'fnInit': function( oDTSettings ) {
288				var oWidgets = new ColumnFilterWidgets( oDTSettings );
289				return oWidgets.getContainer();
290			},
291			'cFeature': 'W',
292			'sFeature': 'ColumnFilterWidgets'
293		} );
294
295	} else {
296		throw 'Warning: ColumnFilterWidgets requires DataTables 1.7 or greater - www.datatables.net/download';
297	}
298
299
300}(jQuery));

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.