PageSourceSearch

https://handspantheatre.com.au/info/vendor_bundled/vendor/mottie/tablesorter/js/widgets/widget-grouping.js

js handspantheatre.com.au collected 2026-10-02 13:59:43 UTC 14,747 bytes, 361 lines download raw bytes

1/*! Widget: grouping - updated 9/27/2017 (v2.29.0) *//*
2 * Requires tablesorter v2.8+ and jQuery 1.7+
3 * by Rob Garrison
4 */
5/*jshint browser:true, jquery:true, unused:false */
6/*global jQuery: false */
7;(function($) {
8	'use strict';
9	var ts = $.tablesorter,
10
11	tsg = ts.grouping = {
12
13		types : {
14			number : function(c, $column, txt, num) {
15				var result,
16					ascSort = $column.hasClass( ts.css.sortAsc );
17				if ( num > 1 && txt !== '' ) {
18					if ( ascSort ) {
19						result = Math.floor( parseFloat( txt ) / num ) * num;
20					} else {
21						result = Math.ceil( parseFloat( txt ) / num ) * num;
22					}
23					// show range
24					result += ' - ' + ( result + ( num - 1 ) * ( ascSort ? 1 : -1 ) );
25				} else {
26					result = parseFloat( txt ) || txt;
27				}
28				return result;
29			},
30			separator : function(c, $column, txt, num) {
31				var word = (txt + '').split(c.widgetOptions.group_separator);
32				// return $.trim(word && num > 0 && word.length >= num ? word[(num || 1) - 1] : '');
33				return $.trim( word[ num - 1 ] || '' );
34			},
35			text : function( c, $column, txt ) {
36				return txt;
37			},
38			word : function(c, $column, txt, num) {
39				var word = (txt + ' ').match(/\w+/g) || [];
40				// return word && word.length >= num ? word[num - 1] : txt || '';
41				return word[ num - 1 ] || '';
42			},
43			letter : function(c, $column, txt, num) {
44				return txt ? (txt + ' ').substring(0, num) : '';
45			},
46			date : function(c, $column, txt, part) {
47				var year, month,
48					wo = c.widgetOptions,
49					time = new Date(txt || '');
50				// check for valid date
51				if ( time instanceof Date && isFinite( time ) ) {
52					year = time.getFullYear();
53					month = tsg.findMonth( wo, time.getMonth() );
54					return part === 'year' ? year :
55						part === 'month' ? month :
56						part === 'monthyear' ?  month + ' ' + year :
57						part === 'day' ? month + ' ' + time.getDate() :
58						part === 'week' ? tsg.findWeek( wo, time.getDay() ) :
59						part === 'time' ? tsg.findTime( wo, time ) :
60						part === 'hour' ? tsg.findTime( wo, time, 'hour' ) :
61						wo.group_dateString( time, c, $column );
62				} else {
63					return wo.group_dateInvalid;
64				}
65			}
66		},
67
68		// group date type functions to allow using this widget with Globalize
69		findMonth : function( wo, month ) {
70			// CLDR returns an object { 1: "Jan", 2: "Feb", 3: "Mar", ..., 12: "Dec" }
71			return wo.group_months[ month + ( ( wo.group_months[0] || '' ) === '' ? 1 : 0 ) ];
72		},
73		findWeek : function( wo, day ) {
74			if ( $.isArray( wo.group_week ) ) {
75				return wo.group_week[ day ];
76			} else if ( !$.isEmptyObject( wo.group_week ) ) {
77				// CLDR returns { sun: "Sun", mon: "Mon", tue: "Tue", wed: "Wed", thu: "Thu", ... }
78				var cldrWeek = [ 'sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat' ];
79				return wo.group_week[ cldrWeek[ day ] ];
80			}
81		},
82		findTime : function( wo, time, part ) {
83			var suffix,
84				// CLDR returns { am: "AM", pm: "PM", ... }
85				isObj = wo.group_time.am && wo.group_time.pm,
86				h = time.getHours(),
87				period = h >= 12 ? 1 : 0,
88				p24 = wo.group_time24Hour && h > 12 ? h - 12 :
89					wo.group_time24Hour && h === 0 ? h + 12 : h,
90				hours = ( '00' + p24 ).slice(-2),
91				min = ( '00' + time.getMinutes() ).slice(-2);
92			suffix = wo.group_time[ isObj ? [ 'am', 'pm' ][ period ] : period ];
93			if ( part === 'hour' ) {
94				return hours;
95			}
96			return hours + ':' + min + ( wo.group_time24Hour ? '' : ' ' + ( suffix || '' ) );
97		},
98
99		update : function(table) {
100			if ($.isEmptyObject(table.config.cache)) { return; }
101			var c = table.config,
102				wo = c.widgetOptions,
103				hasSort = typeof c.sortList[0] !== 'undefined',
104				data = {},
105				column = $.isArray( wo.group_forceColumn ) && typeof wo.group_forceColumn[0] !== 'undefined' ?
106					( wo.group_enforceSort && !hasSort ? -1 : wo.group_forceColumn[0] ) :
107					( hasSort ? c.sortList[0][0] : -1 );
108			c.$table
109				.find('tr.group-hidden').removeClass('group-hidden').end()
110				.find('tr.group-header').remove();
111			if (wo.group_collapsible) {
112				// clear pager saved spacer height (in case the rows are collapsed)
113				c.$table.data('pagerSavedHeight', 0);
114			}
115			if (column >= 0 && column < c.columns && !c.$headerIndexed[column].hasClass('group-false')) {
116				wo.group_collapsedGroup = ''; // save current groups
117				wo.group_collapsedGroups = {};
118
119				data.column = column;
120				// group class finds 'group-{word/separator/letter/number/date/false}-{optional:#/year/month/day/week/time}'
121				data.groupClass = (c.$headerIndexed[column].attr('class') || '').match(/(group-\w+(-\w+)?)/g);
122				// grouping = [ 'group', '{word/separator/letter/number/date/false}', '{#/year/month/day/week/time}' ]
123				data.grouping = data.groupClass ? data.groupClass[0].split('-') : [ 'group', 'letter', 1 ]; // default to letter 1
124
125				// save current grouping
126				data.savedGroup = tsg.saveCurrentGrouping( c, wo, data );
127
128				// find column groups
129				tsg.findColumnGroups( c, wo, data );
130				tsg.processHeaders( c, wo, data );
131
132				c.$table.triggerHandler(wo.group_complete);
133			}
134		},
135
136		processHeaders : function( c, wo, data ) {
137			var index, isHidden, $label, name, $rows, $row,
138				$headers = c.$table.find( 'tr.group-header' ),
139				len = $headers.length;
140
141			$headers.bind( 'selectstart', false );
142			for ( index = 0; index < len; index++ ) {
143				$row = $headers.eq( index );
144				$rows = $row.nextUntil( 'tr.group-header' ).filter( ':visible' );
145
146				// add group count (only visible rows!)
147				if ( wo.group_count || $.isFunction( wo.group_callback ) ) {
148					$label = $row.find( '.group-count' );
149					if ( $label.length ) {
150						if ( wo.group_count ) {
151							$label.html( wo.group_count.toString().replace( /\{num\}/g, $rows.length ) );
152						}
153						if ( $.isFunction( wo.group_callback ) ) {
154							wo.group_callback( $row.find( 'td' ), $rows, data.column, c.table );
155						}
156					}
157				}
158				// save collapsed groups
159				if ( wo.group_saveGroups &&
160					!$.isEmptyObject( wo.group_collapsedGroups ) &&
161					wo.group_collapsedGroups[ wo.group_collapsedGroup ].length ) {
162					name = $row.find( '.group-name' ).text().toLowerCase() + $row.attr( 'data-group-index' );
163					isHidden = $.inArray( name, wo.group_collapsedGroups[ wo.group_collapsedGroup ] ) > -1;
164					$row.toggleClass( 'collapsed', isHidden );
165					$rows.toggleClass( 'group-hidden', isHidden );
166				} else if ( wo.group_collapsed && wo.group_collapsible ) {
167					$row.addClass( 'collapsed' );
168					$rows.addClass( 'group-hidden' );
169				}
170			}
171		},
172
173		groupHeaderHTML : function( c, wo, data ) {
174			var name = ( data.currentGroup || '' ).toString().replace(/</g, '&lt;').replace(/>/g, '&gt;');
175			return '<tr class="group-header ' + c.selectorRemove.slice(1) + ' ' +
176				// prevent grouping row from being hidden by the columnSelector;
177				// classHasSpan option added 2.29.0
178				( wo.columnSelector_classHasSpan || 'hasSpan' ) +
179				'" unselectable="on" ' + ( c.tabIndex ? 'tabindex="0" ' : '' ) + 'data-group-index="' +
180				data.groupIndex + '">' +
181				'<td colspan="' + c.columns + '">' +
182					( wo.group_collapsible ? '<i/>' : '' ) +
183					'<span class="group-name">' + name + '</span>' +
184					'<span class="group-count"></span>' +
185				'</td></tr>';
186		},
187		saveCurrentGrouping : function( c, wo, data ) {
188			// save current grouping
189			var saveName, direction,
190				savedGroup = false;
191			if (wo.group_collapsible && wo.group_saveGroups) {
192				wo.group_collapsedGroups = ts.storage && ts.storage( c.table, 'tablesorter-groups' ) || {};
193				// include direction when saving groups (reversed numbers shows different range values)
194				direction = 'dir' + c.sortList[0][1];
195				// combine column, sort direction & grouping as save key
196				saveName = wo.group_collapsedGroup = '' + c.sortList[0][0] + direction + data.grouping.join('');
197				if (!wo.group_collapsedGroups[saveName]) {
198					wo.group_collapsedGroups[saveName] = [];
199				} else {
200					savedGroup = true;
201				}
202			}
203			return savedGroup;
204		},
205		findColumnGroups : function( c, wo, data ) {
206			var tbodyIndex, norm_rows, rowIndex, end, undef,
207				hasPager = ts.hasWidget( c.table, 'pager' ),
208				p = c.pager || {};
209			data.groupIndex = 0;
210			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
211				norm_rows = c.cache[ tbodyIndex ].normalized;
212				data.group = undef; // clear grouping across tbodies
213				rowIndex = hasPager && !p.ajax ? p.startRow - 1 : 0;
214				end = hasPager ? p.endRow - ( p.ajax ? p.startRow : 0 ) : norm_rows.length;
215				for ( ; rowIndex < end; rowIndex++ ) {
216					data.rowData = norm_rows[ rowIndex ];
217					// fixes #1232 - ajax issue; if endRow > norm_rows.length (after filtering), then data.rowData is undefined
218					if (data.rowData) {
219						data.$row = data.rowData[ c.columns ].$row;
220						// fixes #438
221						if ( data.$row.is( ':visible' ) && tsg.types[ data.grouping[ 1 ] ] ) {
222							tsg.insertGroupHeader( c, wo, data );
223						}
224					}
225				}
226			}
227			if ( ts.hasWidget( c.table, 'columnSelector' ) ) {
228				// make sure to handle the colspan adjustments of the grouping rows
229				ts.columnSelector.setUpColspan( c, wo );
230			}
231		},
232		insertGroupHeader: function( c, wo, data ) {
233			var $header = c.$headerIndexed[ data.column ],
234				txt = data.rowData[ data.column ],
235				num = /date/.test( data.groupClass ) ? data.grouping[ 2 ] : parseInt( data.grouping[ 2 ] || 1, 10 ) || 1;
236			data.currentGroup = data.rowData ?
237				tsg.types[ data.grouping[ 1 ] ]( c, $header, txt, num, data.group ) :
238				data.currentGroup;
239			if ( data.group !== data.currentGroup ) {
240				data.group = data.currentGroup;
241				if ( $.isFunction( wo.group_formatter ) ) {
242					data.currentGroup = wo.group_formatter( ( data.group || '' ).toString(), data.column, c.table, c, wo, data ) || data.group;
243				}
244				// add first() for grouping with childRows
245				data.$row.first().before( tsg.groupHeaderHTML( c, wo, data ) );
246				if ( wo.group_saveGroups && !data.savedGroup && wo.group_collapsed && wo.group_collapsible ) {
247					// all groups start collapsed; data.groupIndex is 1 more than the expected index.
248					wo.group_collapsedGroups[ wo.group_collapsedGroup ].push( data.currentGroup + data.groupIndex );
249				}
250				data.groupIndex++;
251			}
252		},
253
254		bindEvents : function(table, c, wo) {
255			if (wo.group_collapsible) {
256				wo.group_collapsedGroups = [];
257				// .on() requires jQuery 1.7+
258				c.$table.on('click toggleGroup keyup', 'tr.group-header', function(event) {
259					event.stopPropagation();
260					// pressing enter will toggle the group
261					if (event.type === 'keyup' && event.which !== 13) { return; }
262					var isCollapsed, indx,
263						$this = $(this),
264						name = $this.find('.group-name').text().toLowerCase() + $this.attr('data-group-index');
265					// use shift-click to toggle ALL groups
266					if (event.shiftKey && (event.type === 'click' || event.type === 'keyup')) {
267						$this.siblings('.group-header').trigger('toggleGroup');
268					}
269					$this.toggleClass('collapsed');
270					// nextUntil requires jQuery 1.4+
271					$this.nextUntil('tr.group-header').toggleClass('group-hidden', $this.hasClass('collapsed') );
272					isCollapsed = $this.hasClass('collapsed');
273					// reapply zebra widget after opening collapsed group - see #1156
274					if (!isCollapsed && ts.hasWidget(c.$table, 'zebra')) {
275						ts.applyWidgetId(c.$table, 'zebra');
276					}
277					// save collapsed groups
278					if (wo.group_saveGroups && ts.storage) {
279						if (!wo.group_collapsedGroups[wo.group_collapsedGroup]) {
280							wo.group_collapsedGroups[wo.group_collapsedGroup] = [];
281						}
282						if (isCollapsed && wo.group_collapsedGroup) {
283							wo.group_collapsedGroups[wo.group_collapsedGroup].push( name );
284						} else if (wo.group_collapsedGroup) {
285							indx = $.inArray( name, wo.group_collapsedGroups[wo.group_collapsedGroup]  );
286							if (indx > -1) {
287								wo.group_collapsedGroups[wo.group_collapsedGroup].splice( indx, 1 );
288							}
289						}
290						ts.storage( table, 'tablesorter-groups', wo.group_collapsedGroups );
291					}
292				});
293			}
294			$(wo.group_saveReset).on('click', function() {
295				tsg.clearSavedGroups(table);
296			});
297			c.$table.on('pagerChange.tsgrouping', function() {
298				tsg.update(table);
299			});
300		},
301
302		clearSavedGroups: function(table) {
303			if (table && ts.storage) {
304				ts.storage(table, 'tablesorter-groups', '');
305				tsg.update(table);
306			}
307		}
308
309	};
310
311	ts.addWidget({
312		id: 'group',
313		priority: 100,
314		options: {
315			group_collapsible : true, // make the group header clickable and collapse the rows below it.
316			group_collapsed   : false, // start with all groups collapsed
317			group_saveGroups  : true, // remember collapsed groups
318			group_saveReset   : null, // element to clear saved collapsed groups
319			group_count       : ' ({num})', // if not false, the '{num}' string is replaced with the number of rows in the group
320			group_separator   : '-',  // group name separator; used when group-separator-# class is used.
321			group_formatter   : null, // function(txt, column, table, c, wo) { return txt; }
322			group_callback    : null, // function($cell, $rows, column, table) {}, callback allowing modification of the group header labels
323			group_complete    : 'groupingComplete', // event triggered on the table when the grouping widget has finished work
324
325			// apply the grouping widget only to selected column
326			group_forceColumn : [],   // only the first value is used; set as an array for future expansion
327			group_enforceSort : true, // only apply group_forceColumn when a sort is applied to the table
328
329			// checkbox parser text used for checked/unchecked values
330			group_checkbox    : [ 'checked', 'unchecked' ],
331			// change these default date names based on your language preferences
332			group_months      : [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ],
333			group_week        : [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ],
334			group_time        : [ 'AM', 'PM' ],
335
336			// use 12 vs 24 hour time
337			group_time24Hour  : false,
338			// group header text added for invalid dates
339			group_dateInvalid : 'Invalid Date',
340
341			// this function is used when 'group-date' is set to create the date string
342			// you can just return date, date.toLocaleString(), date.toLocaleDateString() or d.toLocaleTimeString()
343			// reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#Conversion_getter
344			group_dateString  : function(date) { return date.toLocaleString(); }
345		},
346		init: function(table, thisWidget, c, wo) {
347			tsg.bindEvents(table, c, wo);
348		},
349		format: function(table) {
350			tsg.update(table);
351		},
352		remove : function(table, c) {
353			c.$table
354				.off('click', 'tr.group-header')
355				.off('pagerChange.tsgrouping')
356				.find('.group-hidden').removeClass('group-hidden').end()
357				.find('tr.group-header').remove();
358		}
359	});
360
361})(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.