PageRenderTime 60ms CodeModel.GetById 28ms app.highlight 26ms RepoModel.GetById 1ms app.codeStats 0ms

/public/js/tablesorter/widgets/widget-build-table.js

https://gitlab.com/webster5361/UserFrosting
JavaScript | 454 lines | 309 code | 27 blank | 118 comment | 105 complexity | c409dba72c7ea052366c031ad293a049 MD5 | raw file
  1/*! Widget: Build Table - updated 3/26/2015 (v2.21.3) *//*
  2 * for tableSorter v2.16.0+
  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 = $.tablesorter || {},
 10
 11	// build a table from data (requires existing <table> tag)
 12	// data.header contains an array of header titles
 13	// data.rows contains an array of rows which contains an array of cells
 14	bt = ts.buildTable = function(tar, c){
 15		// add table if one doesn't exist
 16		var $tbl = tar.nodeName === 'TABLE' ? $(tar) : $('<table>').appendTo(tar),
 17			table = $tbl[0],
 18			wo = c.widgetOptions = $.extend( true, {}, bt.defaults, c.widgetOptions ),
 19			p = wo.build_processing,
 20			typ = wo.build_type,
 21			d = wo.build_source || c.data,
 22
 23		// determine type: html, json, array, csv, object
 24		runType = function(d){
 25			var t = $.type(d),
 26				jq = d instanceof jQuery;
 27			// run any processing if set
 28			if ( typeof p === 'function' ) { d = p(d, wo); }
 29			// store processed data in table.config.data
 30			c.data = d;
 31			// String (html or unprocessed json) or jQuery object
 32			if ( jq || t === 'string' ) {
 33				// look for </tr> closing tag, then we have an HTML string
 34				if ( jq || /<\s*\/tr\s*>/.test(d) ) {
 35					return bt.html( table, d, wo );
 36				}
 37				try {
 38					d = $.parseJSON(d || 'null');
 39					if (d) {
 40						// valid JSON!
 41						return bt.object( table, d, wo );
 42					}
 43				} catch (ignore) {}
 44				// fall through in case it's a csv string
 45			}
 46			// Array
 47			if (t === 'array' || t === 'string' || typ === 'array' || typ === 'csv') {
 48				// build table using an array (csv & array combined script)
 49				return bt.csv( table, d, wo );
 50			}
 51			// if we got here, it's an object, or nothing
 52			return bt.object( table, d, wo );
 53		};
 54
 55		// store config
 56		table.config = c;
 57
 58		// even if wo.build_type is undefined, we can try to figure out the type
 59		if ( !ts.buildTable.hasOwnProperty(typ) && typ !== '' ) {
 60			if (c.debug) { console.error('aborting build table widget, incorrect build type'); }
 61			return false;
 62		}
 63
 64		if ( d instanceof jQuery ) {
 65			// get data from within a jQuery object (csv)
 66			runType( $.trim( d.html() ) );
 67		} else if ( d && ( d.hasOwnProperty('url') || typ === 'json' ) ) {
 68			// load data via ajax
 69			$.ajax( wo.build_source )
 70			.done(function(data) {
 71				runType(data);
 72			})
 73			.fail(function( jqXHR, textStatus, errorThrown) {
 74				if (c.debug) { console.error('aborting build table widget, failed ajax load'); }
 75				$tbl.html('<tr><td class="error">' + jqXHR.status + ' '  + textStatus + '</td></tr>');
 76			});
 77		} else {
 78			runType(d);
 79		}
 80	};
 81
 82	bt.defaults = {
 83		// *** build widget core ***
 84		build_type       : '',   // array, csv, object, json, html
 85		build_source     : '',   // array, object, jQuery Object or ajaxObject { url: '', dataType: 'json' },
 86		build_processing : null, // function that returns a useable build_type (e.g. string to array)
 87		build_complete   : 'tablesorter-build-complete', // triggered event when build completes
 88
 89		// *** CSV & Array ***
 90		build_headers   : {
 91			rows    : 1,  // Number of header rows from the csv
 92			classes : [], // Header classes to apply to cells
 93			text    : [], // Header cell text
 94			widths  : []  // set header cell widths (set in colgroup)
 95		},
 96		build_footers : {
 97			rows    : 1,   // Number of header rows from the csv
 98			classes : [],  // Footer classes to apply to cells
 99			text    : []   // Footer cell text
100		},
101		build_numbers : {
102			addColumn : false, // include row numbering column?
103			sortable  : false  // make column sortable?
104		},
105
106		// *** CSV only options ***
107		build_csvStartLine : 0,   // line within the csv to start adding to table
108		build_csvSeparator : ',', // csv separator
109
110		// *** build object options ***
111		build_objectRowKey    : 'rows',    // object key containing table rows
112		build_objectCellKey   : 'cells',   // object key containing table cells (within the rows object)
113		build_objectHeaderKey : 'headers', // object key containing table headers
114		build_objectFooterKey : 'footers'  // object key containing table footers
115	};
116
117	bt.build = {
118		colgroup : function(widths) {
119			var t = '';
120			// add colgroup if widths set
121			if (widths && widths.length) {
122				t += '<colgroup>';
123				$.each(widths, function(i, w){
124					t += '<col' + ( w ? ' style="width:' + w + '"' : '' ) + '>';
125				});
126				t += '</colgroup>';
127			}
128			return t;
129		},
130		// d = cell data; typ = 'th' or 'td'; first = save widths from first header row only
131		cell : function(d, wo, typ, col, first){
132			var j, $td,
133				$col = first ? $('<col>') : '',
134				cls = wo.build_headers.classes,
135				cw = wo.build_headers.widths;
136			// d is just an array
137			if (/string|number/.test(typeof d)) {
138				// add classes from options, but not text
139				$td = $('<' + typ + (cls && cls[col] ? ' class="' + cls[col] + '"' : '') + '>' + d + '</' + typ + '>');
140				// get widths from options (only from first row)
141				if (first && cw && cw[col]) {
142					$col.width(cw[col] || '');
143				}
144			} else {
145				// assume we have an object
146				$td = $('<' + typ + '>');
147				for (j in d) {
148					if (d.hasOwnProperty(j)){
149						if (j === 'text' || j === 'html') {
150							$td[j]( d[j] );
151						} else if (first && j === 'width') {
152							// set column width, but only from first row
153							$col.width(d[j] || '');
154						} else {
155							$td.attr(j, d[j]);
156						}
157					}
158				}
159			}
160			return [ $td, $col ];
161		},
162		// h1 = header text from data
163		header : function(h1, wo){
164			var h2 = wo.build_headers.text,
165				cls = wo.build_headers.classes,
166				t = '<tr>' + (wo.build_numbers.addColumn ? '<th' + (wo.build_numbers.sortable ? '' :
167					' class="sorter-false"') + '>' + wo.build_numbers.addColumn + '</th>' : '');
168			$.each(h1, function(i, h) {
169				if (/<\s*\/t(d|h)\s*>/.test(h)) {
170					t += h;
171				} else {
172					t += '<th' + (cls && cls[i] ? ' class="' + cls[i] + '"' : '') + '>' +
173						(h2 && h2[i] ? h2[i] : h) + '</th>';
174				}
175			});
176			return t + '</tr>';
177		},
178		rows : function(items, txt, c, wo, num, ftr){
179			var h = (ftr ? 'th' : 'td'),
180				t = '<tr>' + (wo.build_numbers.addColumn ? '<' + h + '>' + (ftr ? '' : num) + '</' + h + '>' : '');
181			$.each(items, function(i, item) {
182				// test if HTML is already included; look for closing </td>
183				if (/<\s*\/t(d|h)\s*>/.test(item)) {
184					t += item;
185				} else {
186					t += '<' + (ftr ? h + (c && c[i] ? ' class="' + c[i] + '"' : '') : h) + '>' +
187						(ftr && txt && txt.length && txt[i] ? txt[i] : item) + '</' + h + '>';
188				}
189			});
190			return t + '</tr>';
191		}
192	};
193
194	bt.buildComplete = function(table, wo){
195		$(table).trigger(wo.build_complete);
196		ts.setup(table, table.config);
197	};
198
199	/* ==== Array example ====
200	[
201		[ "header1", "header2", ... "headerN" ],
202		[ "row1cell1", "row1cell2", ... "row1cellN" ],
203		[ "row2cell1", "row2cell2", ... "row2cellN" ],
204		...
205		[ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
206	]
207	*/
208	bt.array = function(table, data, wo) {
209		return bt.csv(table, data, wo);
210	};
211
212	/* ==== CSV example ====
213	ID, Name, Age, Date
214	A42b, Parker, 28, "Jul 6, 2006 8:14 AM"
215	A255, Hood, 33, "Dec 10, 2002 5:14 AM"
216	A33, Kent, 18, "Jan 12, 2003 11:14 AM"
217	A1, Franklin, 45, "Jan 18, 2001 9:12 AM"
218	A102, Evans, 22, "Jan 18, 2007 9:12 AM"
219	A42a, Everet, 22, "Jan 18, 2007 9:12 AM"
220	ID, Name, Age, Date
221	*/
222	// Adapted & modified from csvToTable.js by Steve Sobel
223	// MIT license: https://code.google.com/p/jquerycsvtotable/
224	bt.csv = function(table, data, wo) {
225		var c, h,
226			csv = wo.build_type === 'csv' || typeof data === 'string',
227			$t = $(table),
228			lines = csv ? data.replace('\r', '').split('\n') : data,
229			len = lines.length,
230			printedLines = 0,
231			infooter = false,
232			r = wo.build_headers.rows + (csv ? wo.build_csvStartLine : 0),
233			f = wo.build_footers.rows,
234			headerCount = 0,
235			error = '',
236			items,
237			tableHTML = bt.build.colgroup( wo.build_headers.widths ) + '<thead>';
238
239		$.each(lines, function(n, line) {
240			if ( n >= len - f ) { infooter = true; }
241			// build header
242			if ( (csv ? n >= wo.build_csvStartLine : true) && ( n < r ) ) {
243				h = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line;
244				headerCount = h.length;
245				tableHTML += bt.build.header(h, wo);
246			} else if ( n >= r ) {
247				// build tbody & tfoot rows
248				if (n === r) {
249					tableHTML += '</thead><tbody>';
250				}
251				items = csv ? bt.splitCSV( line, wo.build_csvSeparator ) : line;
252				if (infooter && f > 0) {
253					tableHTML += (n === len - f ? '</tbody><tfoot>' : '') +
254						(n === len ? '</tfoot>' : '');
255				}
256				if (items.length > 1) {
257					printedLines++;
258					if ( items.length !== headerCount ) {
259						error += 'error on line ' + n + ': Item count (' + items.length +
260							') does not match header count (' + headerCount + ') \n';
261					}
262					c = infooter ? wo.build_footers.classes : '';
263					tableHTML += bt.build.rows(items, wo.build_footers.text, c, wo, printedLines, infooter);
264				}
265			}
266		});
267		tableHTML += (f > 0 ? '' : '</tbody>');
268		if (error) {
269			$t.html(error);
270		} else {
271			$t.html(tableHTML);
272			bt.buildComplete(table, wo);
273		}
274	};
275
276	// CSV Parser by Brian Huisman (http://www.greywyvern.com/?post=258)
277	bt.splitCSV = function(str, sep) {
278		var x, tl,
279			thisCSV = $.trim(str).split(sep = sep || ',');
280		for ( x = thisCSV.length - 1; x >= 0; x-- ) {
281			if ( thisCSV[x].replace(/\"\s+$/, '"').charAt(thisCSV[x].length - 1) === '"' ) {
282				if ( (tl = thisCSV[x].replace(/^\s+\"/, '"')).length > 1 && tl.charAt(0) === '"' ) {
283					thisCSV[x] = thisCSV[x].replace(/^\s*"|"\s*$/g, '').replace(/""/g, '"');
284				} else if (x) {
285					thisCSV.splice(x - 1, 2, [ thisCSV[x - 1], thisCSV[x] ].join(sep));
286				} else {
287					thisCSV = thisCSV.shift().split(sep).concat(thisCSV);
288				}
289			} else {
290				thisCSV[x].replace(/""/g, '"');
291			}
292		}
293		return thisCSV;
294	};
295
296	// data may be a jQuery object after processing
297	bt.html = function(table, data, wo) {
298		var $t = $(table);
299		if ( data instanceof jQuery ) {
300			$t.empty().append(data);
301		} else {
302			$t.html(data);
303		}
304		bt.buildComplete(table, wo);
305	};
306
307	/* ==== Object example ====
308	data : {
309		headers : [
310			[
311				{ text: 'First Name', class: 'fname', width: '20%' }, // row 1 cell 1
312				'Last Name',
313				{ text: 'Age', class: 'age', 'data-sorter' : false },
314				'Total',
315				{ text: 'Discount', class : 'sorter-false' },
316				{ text: 'Date', class : 'date' }                      // row 1 cell 6
317			]
318		],
319		footers : 'clone', // clone headers or assign array like headers
320		rows : [
321			// TBODY 1
322			[ 'Peter', 'Parker',   28, '$9.99',   '20%', 'Jul 6, 2006 8:14 AM'   ], // row 1
323			[ 'John',  'Hood',     33, '$19.99',  '25%', 'Dec 10, 2002 5:14 AM'  ], // row 2
324			[ 'Clark', 'Kent',     18, '$15.89',  '44%', 'Jan 12, 2003 11:14 AM' ], // row 3
325
326			// TBODY 2
327			{ newTbody: true, class: 'tablesorter-infoOnly' },
328			{ cells : [ { text: 'Info Row', colSpan: 6 } ] }, // row 4
329
330			// TBODY 3
331			{ newTbody: true },
332			[ 'Bruce', 'Evans',    22, '$13.19',  '11%', 'Jan 18, 2007 9:12 AM'  ], // row 5
333			[ 'Brice', 'Almighty', 45, '$153.19', '44%', 'Jan 18, 2001 9:12 AM'  ], // row 6
334
335			{ class: 'specialRow', // row 7
336				cells: [
337					{ text: 'Fred', class: 'fname' },
338					{ text: 'Smith', class: 'lname' },
339					{ text: 18, class: 'age', 'data-info': 'fake ID!, he is really 16' },
340					{ text: '$22.44', class: 'total' },
341					{ text: '8%', class: 'discount' },
342					{ text: 'Aug 20, 2012 10:15 AM', class: 'date' }
343				],
344				'data-info' : 'This row likes turtles'
345			}
346		]
347	}
348	*/
349	bt.object = function(table, data, wo) {
350		// 'rows'
351		var j, l, t, $c, $t, $tb, $tr,
352			c = table.config,
353			kh = wo.build_objectHeaderKey,
354			kr = wo.build_objectRowKey,
355			h = data.hasOwnProperty(kh) && !$.isEmptyObject(data.kh) ? data.kh : data.hasOwnProperty('headers') ? data.headers : false,
356			r = data.hasOwnProperty(kr) && !$.isEmptyObject(data.kr) ? data.kr : data.hasOwnProperty('rows') ? data.rows : false;
357
358		if (!h || !r || h.length === 0 || r.length === 0) {
359			if (c.debug) { console.error('aborting build table widget, missing data for object build'); }
360			return false;
361		}
362
363		$c = $('<colgroup>');
364		$t = $('<table><thead/></table>');
365
366		// Build thead
367		// h = [ ['headerRow1Cell1', 'headerRow1Cell2', ... 'headerRow1CellN' ], ['headerRow2Cell1', ... ] ]
368		// or h = [ [ { text: 'firstCell', class: 'fc', width: '20%' }, ..., { text: 'last Cell' } ], [ /* second row */ ] ]
369		$.each(h, function(i, d){
370			$tr = $('<tr>').appendTo( $t.find('thead') );
371			l = d.length; // header row
372			for ( j = 0; j < l; j++ ) {
373				// cell(cellData, widgetOptions, 'th', first row)
374				t = bt.build.cell(d[j], wo, 'th', j, i === 0);
375				if (t[0] && t[0].length) { t[0].appendTo( $tr ); } // add cell
376				if (i === 0 && t[1]) { t[1].appendTo( $c ); } // add col to colgroup
377			}
378		});
379		if ($c.find('col[style]').length) {
380			// add colgroup if it contains col elements
381			$t.prepend( $c );
382		}
383
384		$tb = $('<tbody>');
385		// Build tbody
386		$.each(r, function(i, d){
387			var j;
388			t = $.type(d) === 'object';
389			// add new tbody
390			if (t && d.newTbody) {
391				$tb = $('<tbody>').appendTo( $t );
392				for (j in d) {
393					if (d.hasOwnProperty(j) && j !== 'newTbody'){
394						$tb.attr(j, d[j]);
395					}
396				}
397			} else {
398				if (i === 0) {
399					// add tbody, if the first item in the object isn't a call for a new tbody
400					$tb.appendTo( $t );
401				}
402
403				$tr = $('<tr>').appendTo( $tb );
404				if (t) {
405					// row defined by object
406					for (j in d) {
407						if (d.hasOwnProperty(j) && j !== wo.build_objectCellKey){
408							$tr.attr(j, d[j]);
409						}
410					}
411					if (d.hasOwnProperty(wo.build_objectCellKey)) {
412						// cells contains each cell info
413						d = d.cells;
414					}
415				}
416
417				l = d.length;
418				for ( j = 0; j < l; j++ ) {
419					// cell(cellData, widgetOptions, 'td')
420					$c = bt.build.cell(d[j], wo, 'td', j);
421					if ($c[0] && $c[0].length) { $c[0].appendTo( $tr ); } // add cell
422				}
423			}
424		});
425
426		// add footer
427		if (data.hasOwnProperty(wo.build_objectFooterKey)) {
428			t = data[wo.build_objectFooterKey];
429			if (t === 'clone') {
430				$c = $t.find('thead').html();
431				$t.append('<tfoot>' + $c + '</tfoot>');
432			} else {
433				$c = $('<tfoot>').appendTo( $t );
434				$.each(t, function(i, d) {
435					$tr = $('<tr>').appendTo( $c );
436					l = d.length; // footer cells
437					for ( j = 0; j < l; j++ ) {
438						// cell(cellData, widgetOptions, 'th')
439						$tb = bt.build.cell(d[j], wo, 'th', j);
440						if ($tb[0] && $tb[0].length) { $tb[0].appendTo( $tr ); } // add cell
441					}
442				});
443			}
444		}
445
446		$(table).html( $t.html() );
447		bt.buildComplete(table, wo);
448	};
449
450	bt.ajax = bt.json = function(table, data, wo) {
451		return bt.object(table, data, wo);
452	};
453
454})(jQuery);