<commit_before>import {Datasource} from './datasource.js';

function is_string(object) {
	return typeof(object) === 'string';
}

function create_element(tag, attributes, text, listeners) {
	const element = document.createElement(tag);
	if(attributes) {
		for(const attribute in attributes) {
			if(attributes.hasOwnProperty(attribute)) {
				element.setAttribute(attribute, attributes[attribute]);
			}
		}
	}
	if(text !== undefined) {
		element.appendChild(document.createTextNode(text));
	}
	if(listeners) {
		for(const listener in listeners) {
			if(listeners.hasOwnProperty(listener)) {
				element.addEventListener(listener, listeners[listener], false);
			}
		}
	}
	return element;
}

function clear_element(element) {
	while(element.firstChild) {
		element.removeChild(element.firstChild);
	}
}

function resort(table) {
	table.start = 0;
	table.draw();
	const sorting_order = table.datasource.sortingOrders[0];
	//update sort image
	for(let i = 0; i < table.columns.length; i++) {
		const column = table.columns[i];
		//only columns with data are sortable
		if(column.data && !column.unsortable) {
			const header_column = table.head.firstChild.childNodes[i];
			header_column.classList.remove('sort_ascending');
			header_column.classList.remove('sort_descending');
			if(column.data === sorting_order.field) {
				header_column.classList.add(sorting_order.descendant ? 'sort_descending' : 'sort_ascending');
			}
		}
	}
}

function data_filter(filter) {
	this.datasource.filter(filter);
	this.start = 0;
	this.draw();
}

export class Table {
	constructor(parameters) {
		//required parameters
		this.container = undefined;
		this.columns = [];
		this.datasource;
		//optional parameters with default value
		this.id;
		this.title = undefined;
		this.actions = [];
		this.statusText = 'Display items ${start} - ${stop} of ${total}';
		this.rowPerPage = 10;
		this.rowClass = undefined;
		this.enableSearch = true;
		this.allowMissingData = false;
		//events
		this.afterRender = undefined;

		//bind parameters
		for(const parameter in parameters) {
			this[parameter] = parameters[parameter];
		}

		//internal variables
		this.start = 0;

		//try to identify table
		if(!this.id) {
			this.id = this.container.id;
		}

		//check required parameters
		if(!this.container || !this.columns) {
			throw new Error('Following parameters are required: container and columns');
		}

		//check columns
		for(let i = 0; i < this.columns.length; i++) {
			const column = this.columns[i];
			if(!column.data && !column.render || !column.label) {
				throw new Error(`Column ${i} is incomplete (must have data or render, and label)`);
			}
			if(!column.unsortable && (!column.data || !column.type)) {
				throw new Error(`Column ${column.label} must have data or type to be sortable or be set as unsortable`);
			}
		}

		const that = this;

		//header
		this.header = create_element('div', {'class': 'table_header'});
		if(this.title) {
			this.header.appendChild(create_element('h2', {}, this.title));
		}

		//table
		this.table = create_element('table', {'class': 'table_content'});

		//table header
		this.head = document.createElement('thead');
		const header_line = create_element('tr');
		this.head.appendChild(header_line);

		for(let i = 0; i < this.columns.length; i++) {
			const column = this.columns[i];
			const header_column = create_element('th', {style: 'width: ' + column.width + 'px;'});
			//create or use label
			const header_label = is_string(column.label) ? document.createTextNode(column.label) : column.label;
			header_column.appendChild(header_label);
			if(!column.unsortable) {
				header_column.style.cursor = 'pointer';
				header_column.addEventListener(
					'click',
					(function(field) {
						return function() {
							const previous_sort_order = that.datasource.sortingOrders[0];
							that.addOrdering(field, !previous_sort_order.descendant);
						};
					})(column.data)
				);
			}
			header_line.appendChild(header_column);
		}
		this.table.appendChild(this.head);

		//table body
		this.body = create_element('tbody');
		this.table.appendChild(this.body);

		//footer
		this.footer = create_element('div', {'class': 'table_footer'});

		const search_bar = create_element('div', {'class': 'table_footer_search'});
		this.footer.appendChild(search_bar);

		if(this.enableSearch) {
			const search_form = create_element('form');
			const search_label = create_element('label', {}, 'Filter');
			this.search_input = create_element('input', {type: 'search'});
			//scan search input
			let last_filter = '';
			setInterval(() => {
				if(last_filter !== this.search_input.value) {
					last_filter = this.search_input.value;
					this.filter(last_filter);
				}
			}, 300);
			search_label.appendChild(this.search_input);
			search_form.appendChild(search_label);
			search_bar.appendChild(search_form);
		}

		this.buttons = create_element('div', {'class': 'table_footer_buttons'});
		this.footer.appendChild(this.buttons);

		this.setActions(this.actions);

		if(this.rowPerPage) {
			//controls
			this.controls = create_element('div', {'class': 'table_footer_controls'});
			this.footer.appendChild(this.controls);

			//first
			this.firstButton = create_element('button', {title: 'First', alt: 'First', 'class': 'control_first'}, undefined,
				{
					'click': function() {
						if(that.start !== 0) {
							that.start = 0;
							that.draw();
						}
					}
				}
			);
			this.controls.appendChild(this.firstButton);
			//previous
			this.previousButton = create_element('button', {title: 'Previous', alt: 'Previous', 'class': 'control_previous'}, undefined,
				{<commit_msg>Make search more reactive<commit_after>import {Datasource} from './datasource.js';

function is_string(object) {
	return typeof(object) === 'string';
}

function create_element(tag, attributes, text, listeners) {
	const element = document.createElement(tag);
	if(attributes) {
		for(const attribute in attributes) {
			if(attributes.hasOwnProperty(attribute)) {
				element.setAttribute(attribute, attributes[attribute]);
			}
		}
	}
	if(text !== undefined) {
		element.appendChild(document.createTextNode(text));
	}
	if(listeners) {
		for(const listener in listeners) {
			if(listeners.hasOwnProperty(listener)) {
				element.addEventListener(listener, listeners[listener], false);
			}
		}
	}
	return element;
}

function clear_element(element) {
	while(element.firstChild) {
		element.removeChild(element.firstChild);
	}
}

function resort(table) {
	table.start = 0;
	table.draw();
	const sorting_order = table.datasource.sortingOrders[0];
	//update sort image
	for(let i = 0; i < table.columns.length; i++) {
		const column = table.columns[i];
		//only columns with data are sortable
		if(column.data && !column.unsortable) {
			const header_column = table.head.firstChild.childNodes[i];
			header_column.classList.remove('sort_ascending');
			header_column.classList.remove('sort_descending');
			if(column.data === sorting_order.field) {
				header_column.classList.add(sorting_order.descendant ? 'sort_descending' : 'sort_ascending');
			}
		}
	}
}

function data_filter(filter) {
	this.datasource.filter(filter);
	this.start = 0;
	this.draw();
}

export class Table {
	constructor(parameters) {
		//required parameters
		this.container = undefined;
		this.columns = [];
		this.datasource;
		//optional parameters with default value
		this.id;
		this.title = undefined;
		this.actions = [];
		this.statusText = 'Display items ${start} - ${stop} of ${total}';
		this.rowPerPage = 10;
		this.rowClass = undefined;
		this.enableSearch = true;
		this.allowMissingData = false;
		//events
		this.afterRender = undefined;

		//bind parameters
		for(const parameter in parameters) {
			this[parameter] = parameters[parameter];
		}

		//internal variables
		this.start = 0;

		//try to identify table
		if(!this.id) {
			this.id = this.container.id;
		}

		//check required parameters
		if(!this.container || !this.columns) {
			throw new Error('Following parameters are required: container and columns');
		}

		//check columns
		for(let i = 0; i < this.columns.length; i++) {
			const column = this.columns[i];
			if(!column.data && !column.render || !column.label) {
				throw new Error(`Column ${i} is incomplete (must have data or render, and label)`);
			}
			if(!column.unsortable && (!column.data || !column.type)) {
				throw new Error(`Column ${column.label} must have data or type to be sortable or be set as unsortable`);
			}
		}

		const that = this;

		//header
		this.header = create_element('div', {'class': 'table_header'});
		if(this.title) {
			this.header.appendChild(create_element('h2', {}, this.title));
		}

		//table
		this.table = create_element('table', {'class': 'table_content'});

		//table header
		this.head = document.createElement('thead');
		const header_line = create_element('tr');
		this.head.appendChild(header_line);

		for(let i = 0; i < this.columns.length; i++) {
			const column = this.columns[i];
			const header_column = create_element('th', {style: 'width: ' + column.width + 'px;'});
			//create or use label
			const header_label = is_string(column.label) ? document.createTextNode(column.label) : column.label;
			header_column.appendChild(header_label);
			if(!column.unsortable) {
				header_column.style.cursor = 'pointer';
				header_column.addEventListener(
					'click',
					(function(field) {
						return function() {
							const previous_sort_order = that.datasource.sortingOrders[0];
							that.addOrdering(field, !previous_sort_order.descendant);
						};
					})(column.data)
				);
			}
			header_line.appendChild(header_column);
		}
		this.table.appendChild(this.head);

		//table body
		this.body = create_element('tbody');
		this.table.appendChild(this.body);

		//footer
		this.footer = create_element('div', {'class': 'table_footer'});

		const search_bar = create_element('div', {'class': 'table_footer_search'});
		this.footer.appendChild(search_bar);

		if(this.enableSearch) {
			const search_form = create_element('form');
			const search_label = create_element('label', {}, 'Filter');
			this.search_input = create_element('input', {type: 'search'});
			//scan search input
			let last_filter = '';
			setInterval(() => {
				if(last_filter !== this.search_input.value) {
					last_filter = this.search_input.value;
					this.filter(last_filter);
				}
			}, 100);
			search_label.appendChild(this.search_input);
			search_form.appendChild(search_label);
			search_bar.appendChild(search_form);
		}

		this.buttons = create_element('div', {'class': 'table_footer_buttons'});
		this.footer.appendChild(this.buttons);

		this.setActions(this.actions);

		if(this.rowPerPage) {
			//controls
			this.controls = create_element('div', {'class': 'table_footer_controls'});
			this.footer.appendChild(this.controls);

			//first
			this.firstButton = create_element('button', {title: 'First', alt: 'First', 'class': 'control_first'}, undefined,
				{
					'click': function() {
						if(that.start !== 0) {
							that.start = 0;
							that.draw();
						}
					}
				}
			);
			this.controls.appendChild(this.firstButton);
			//previous
			this.previousButton = create_element('button', {title: 'Previous', alt: 'Previous', 'class': 'control_previous'}, undefined,
				{
{'fraction_non_alphanumeric': 0.15010645848119233, 'fraction_numerical': 0.0028388928317956, 'mean_word_length': 3.9968971631205674, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3457802', 'n_tokens_mistral': 4137, 'n_tokens_neox': 3533, 'n_words': 711}