Skip to content

Here is non jquery version of the same #48

@junkfix

Description

@junkfix

For those who are not using jquery here is the same

(function() {
	function tablesort(table, settings) {
		const self = this;
		this.table = table;
		this.thead = this.table.querySelector('thead');
		this.settings = Object.assign({}, tablesort.defaults, settings);
		this.sortCells = this.thead ? this.thead.querySelectorAll('th:not(.no-sort)') : this.table.querySelectorAll('th:not(.no-sort)');
		
		this.sortCells.forEach(function(cell) {
			cell.addEventListener('click', function() {
				self.sort(cell);
			});
		});
		
		this.index = null;
		this.direction = null;
	}

	tablesort.prototype = {
		sort: function(th, direction) {
			const start = new Date(),
				self = this,
				rowsContainer = this.table.querySelector('tbody') || this.table,
				rows = rowsContainer.querySelectorAll('tr'),
				cells = Array.from(rows).map(function(row) {
					return row.querySelectorAll('td, th')[th.cellIndex];
				}),
				sortBy = th.sortBy;
			let sortedMap = [];

			let unsortedValues = cells.map(function(cell) {
				if (sortBy)
					return (typeof sortBy === 'function') ? sortBy(th, cell, self) : sortBy;
				return (cell.dataset.sortValue != null ? cell.dataset.sortValue : cell.textContent);
			});

			if (unsortedValues.length === 0) return;

			if (this.index !== th.cellIndex) {
				this.direction = 'asc';
				this.index = th.cellIndex;
			} else if (direction !== 'asc' && direction !== 'desc') {
				this.direction = (this.direction === 'asc' ? 'desc' : 'asc');
			} else {
				this.direction = direction;
			}

			direction = (this.direction === 'asc' ? 1 : -1);

			self.table.dispatchEvent(new CustomEvent('tablesort:start', { detail: self }));
			
			self.table.style.display = 'none';

			setTimeout(function() {
				self.sortCells.forEach(function(cell) {
					cell.classList.remove(...self.settings.asc.split(' '), ...self.settings.desc.split(' '));

				});

				sortedMap = unsortedValues.map(function(value, i) {
					return {
						index: i,
						cell: cells[i],
						row: rows[i],
						value: value
					};
				}).sort(function(a, b) {
					return self.settings.compare(a.value, b.value) * direction;
				});

				sortedMap.forEach(function(entry) {
					rowsContainer.appendChild(entry.row);
				});

				th.classList.add(...self.settings[self.direction].split(' '));

				self.log('Sort finished in ' + ((new Date()).getTime() - start.getTime()) + 'ms');
				self.table.dispatchEvent(new CustomEvent('tablesort:complete', { detail: self }));
				self.table.style.display = '';
			}, unsortedValues.length > 2000 ? 200 : 10);
		},

		log: function(msg) {
			if ((tablesort.DEBUG || this.settings.debug) && console && console.log) {
				console.log('[tablesort] ' + msg);
			}
		},

		destroy: function() {
			const self = this;
			this.sortCells.forEach(function(cell) {
				cell.removeEventListener('click', function() {
					self.sort(cell);
				});
			});
			this.table.dtablesort = '';
			return null;
		}
	};

	tablesort.DEBUG = false;

	tablesort.defaults = {
		debug: tablesort.DEBUG,
		asc: 'sorted ascending',
		desc: 'sorted descending',
		compare: function(a, b) {
			if (a > b) {
				return 1;
			} else if (a < b) {
				return -1;
			} else {
				return 0;
			}
		}
	};

	HTMLElement.prototype.tablesort = function(settings) {
		const previous = this.dtablesort;
		if (previous) {
			previous.destroy();
		}
		this.dtablesort = new tablesort(this, settings);
	};

})();

//usage
document.querySelectorAll('table').forEach(function(table) {
	table.tablesort();
});

document.querySelectorAll('thead th.number').forEach(th=>{
	th.sortBy = function(sorter, td) {
		return parseInt(td.textContent, 10);
	};
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions