All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.yadaframework.views.yada.js.yada.datatables.js Maven / Gradle / Ivy

The newest version!
//////////////////
/// DataTables ///
//////////////////

(function( yada ) {
	"use strict";
	
	// Namespace trick explained here: http://stackoverflow.com/a/5947280/587641
	// For a public property or function, use "yada.xxx = ..."
	// For a private property use "var xxx = "
	// For a private function use "function xxx(..."

	/**
	 * Create a new DataTable with the given options:
	 * @param $table the jquery table, e.g. $('#myTable'). It must have an id.
	 * @param dataUrl the ajax url to retrieve data in json format, e.g. [[@{/gestione/ajaxCompanyTablePage}]]
	 * @param dataAttributes names of the json attributes for data of each column, e.g. ['name', 'surname', 'address']
	 *        The array can also contain full DataTable objects with data/name/orderable/searchable fields, e.g. ['name', 'surname', {data:'address',orderable:false}]
	 * @param editDef object containing url and text (can be null): 
	 * 	- url that returns the edit form e.g. [[@{/gestione/ajaxRenameTagForm}]]
	 * 	- title to show in the tooltip
	 *  - idName the name of the id request parameter (optional - defaults to "id")
	 *  - noLoader true to hide the ajax loader
	 *  - noAjax true to make a normal request and load a new page
	 * @param deleteDef object containing url and text (can be null):
	 * 	- url to delete the row e.g. [[@{/gestione/ajaxDeleteTag}]]
	 * 	- title to show in the tooltip
	 *  - confirmTitle (optional)
	 * 	- confirmOneMessage (optional)
	 * 	- confirmManyMessage (optional)
	 *  - confirmButtonText (optional)
	 *  - abortButtonText (optional)
	 *  - idName the name of the id request parameter (optional - defaults to "id")
	 *  - nameColumn the index of the column holding the text to show in the dialog when deleting one element (checkboxes = 1)
	 * @param order array of column ordering, e.g. [ [1, 'asc'] ] or [ [ 0, 'asc' ], [ 1, 'asc' ] ]
	 *        - be careful that in thymeleaf you need a space between two open squares: [ [ not [[
	 * NOTE: index 1 is the checkbox column
	 * @param pageLength the number of rows per page
	 * @param (optional) languageUrl url to the language file, like http://server.example/path/18n/italian.lang
	 * @param (optional) extraButtons additional command button definitions in an array of objects:
	 * - url to call when the button is clicked 
	 * - title to show in the tooltip
	 * - icon for the button, like ''
	 * - idName the name of the id request parameter (optional - defaults to "id")
	 * - ajax (optional) false to make a normal page transition to the target link
	 * - confirmTitle (optional)
	 * - confirmOneMessage (optional)
	 * - confirmNameColumn the index of the column holding the element name, will replace the {0} placeholder in the message
	 * - confirmManyMessage (optional)
	 * - confirmButtonText (optional)
	 * - abortButtonText (optional)
	 * @returns the DataTable object
	 */
	yada.dataTableCrud = function($table, dataUrl, dataAttributes, editDef, deleteDef, order, pageLength, languageUrl, extraButtons, removeCheckbox) {
		// Method argument validation
		if ($table == null || typeof $table != "object" || $table.length!=1 || typeof $table[0] != "object") {
			return;
		}
		if (dataUrl==null || typeof dataUrl != "string") {
			console.error("yada.datatables: dataUrl must be a string");
			return;
		}
		if (!Array.isArray(dataAttributes) || dataAttributes.length == 0) {
			console.error("yada.datatables: dataAttributes must be a non-empty array");
			return;
		}
		if (editDef!=null && (typeof editDef != "object" || Array.isArray(editDef))) {
			console.error("yada.datatables: editDef must be an object or null");
			return;
		}
		if (deleteDef!=null && (typeof deleteDef != "object" || Array.isArray(deleteDef))) {
			console.error("yada.datatables: deleteDef must be an object or null");
			return;
		}
		if (!Array.isArray(order) || order.length == 0 ) {
			console.error("yada.datatables: order must be a non-empty array");
			return;
		}
		if (typeof pageLength != "number" ) {
			console.error("yada.datatables: pageLength must be an integer");
			return;
		}
		if (languageUrl!=null && typeof languageUrl != "string") {
			console.error("yada.datatables: languageUrl must be a string or null");
			return;
		}
		if (extraButtons!=null && (!Array.isArray(extraButtons) || extraButtons.length == 0 || typeof extraButtons[0] != "object" || Array.isArray(extraButtons[0]) ) ) {
			console.error("yada.datatables: extraButtons must be a non-empty array of objects or null");
			return;
		}
		if (removeCheckbox!=null && typeof removeCheckbox != "boolean") {
			console.error("yada.datatables: removeCheckbox must be a boolean or null");
			return;
		}
		
		//
		var tableId = $table.attr('id');
		if (tableId==undefined) {
			console.error("yada.datatables: $table must have a valid id attribute");
			return;
		}
		
		var totColumns = $('th', $table).length;
		var neededColumns = dataAttributes.length + 2 + (removeCheckbox?0:1);
		if (totColumns!=neededColumns) {
			yada.showErrorModal("Internal Error", "Table '" + $table[0].id + "' has " + totColumns + " columns but " + neededColumns + " where expected - (ignored)");
		}
		var columnDef = [
		    {
		    	data: null,
		    	defaultContent:'',
		    	className: 'control',
		    	orderable: false,
				searchable: false,
				visible: false
		    }
		];
		if (!removeCheckbox) {
			columnDef.push(
				{	// Colonna dei checkbox
					data: null,
					name: '_yadaSelectionColumn', // Non usato
					orderable: false,
					searchable: false,
					render: function ( data, type, row ) {
						if ( type === 'display' ) {
							return '';
						}
						return data;
					},
					width: "50px",
					className: "yadaCheckInCell"
				}	                   
			);
		}
		// Add field columns
		for (var i = 0; i < dataAttributes.length; i++) {
			var field = dataAttributes[i];
			// Default column definition:
			var fieldDef = {
				data: field, // Supposed to be a string
				defaultContent: '---',
				name: field,
				orderable: true,
				searchable: true
			}
			if (typeof field == "object") {
				fieldDef = field;
				if (fieldDef.name == undefined && typeof fieldDef.data == "string" ) {
					// If not specified, the name is the same as the data
					fieldDef.name = fieldDef.data; 
				}
			}
//			var fieldData=field, fieldName=field, fieldSearchable=true, fieldOrderable=true; // Defaults
//			if (field.data != undefined) {
//				fieldData = field.data;
////				if (typeof field.data == "string") {
//				fieldName = field.data.toString(); // Default is same as data
////				}
//			}
//			if (field.name != undefined) {
//				fieldName = field.name;
//			}
//			if (field.searchable != undefined) {
//				fieldSearchable = field.searchable;
//			}
//			if (field.orderable != undefined) {
//				fieldOrderable = field.orderable;
//			}
			
			columnDef.push(
				fieldDef
//				{
//				data: fieldData, // nome dell'attributo or function
//				defaultContent: '---', // Value when null or undefined
//				name: fieldName, // nome interno pari al nome dell'attributo
//				orderable: fieldOrderable,
//				searchable: fieldSearchable
//				}
			);
		}
		// Colonna dei comandi
		columnDef.push({ 
			data: null, 
			className: 'yadaCommandButtonCell',
			name: '_yadaCommandColumn',
			orderable: false,
			searchable: false,
			width: '50px',
		    render: function ( data, type, row ) {
		    	var rowId = yada.getHashValue(data.DT_RowId);
		        if ( type === 'display' ) {
		        	var buttons = '';
		        	for (var i=0; extraButtons!=null && i' + extraButtons[i].icon + '';
		        		} else if (displayIconOnRow=="disabled") {
		        			buttons += '' + extraButtons[i].icon + '';
		        		} else {
		        			// No button
		        		}
		        	}
		        	if (editDef!=null) {
		        		buttons +=
		        			'';
		        	}
		        	if (deleteDef!=null) {
		        		buttons +=
		        			'';
		        	}
		        	return buttons;
		        }
		        return data;
		    }
	    });
		var dataTable = $table.DataTable( {
	        responsive: true,
	        pageLength: pageLength,
			orderMulti: order.length>1,
			order: order,
			columns: columnDef,					
		    serverSide: true,
		    ajax: function(data, callback, settings) {
		    	// Need to add any extra parameter if a form is present
		    	var addedData = $("form.yada_dataTables_"+tableId).serializeArray();
		    	var extraParam = data['extraParam']={};
		    	var i=0;
		    	for (i=0; i 1) {
					$(this).parents('div.yadaTableBlock').find('div.yadaTableToolbar .yadaTableMultirowButton').removeClass('disabled');
					$(this).parents('div.yadaTableBlock').find('div.yadaTableToolbar .yadaTableSinglerowButton:not(.yadaTableMultirowButton)').addClass('disabled');
					// Legacy:
					$(this).parents('div.yadaTableBlock').find('div.yadaTableToolbar .s_multirowButton').removeClass('disabled');
					$(this).parents('div.yadaTableBlock').find('div.yadaTableToolbar .s_singlerowButton:not(.s_multirowButton)').addClass('disabled');
				} else {
					var toolbarButtons = $(this).parents('div.yadaTableBlock').find('div.yadaTableToolbar .btn:not(.s_addButton):not(.yadaTableAlwaysButton)');
					toolbarButtons.addClass('disabled');
				}
			});
		} );
		
		// yadaTableToolbar "add button"
		if (editDef!=null) {
			var addButton = $table.parents('.yadaTableBlock').find('.yadaTableToolbar a.s_addButton');
			addButton.click(function(e) {
				e.preventDefault();
				// The handler enables ajax forms on the loaded response, and adds a handler to redraw the table on modal close
				// Devo abilitare ajax ricorsivamente per quando il form ritorna con un errore di validazione
				var handler = function(responseText, responseHtml) {
					yada.datatableDrawOnModalClose(dataTable);
					recursiveEnableAjaxForm(responseText, responseHtml);
				};
				var noLoader = editDef.noLoader || false;
				yada.ajax(editDef.url, null, handler, null, null, noLoader);
			});
	
			// yadaTableToolbar "edit button"
			var editButton = $table.parents('.yadaTableBlock').find('.yadaTableToolbar a.s_editButton');
			editButton.click(function(e) {
				e.preventDefault();
				var id = yada.getHashValue($table.find("tbody [type='checkbox']:checked").parents('tr').attr('id'));
				var idName = editDef.idName || "id";
				if (editDef.noAjax==true) {
					const targetUrl = yada.addOrUpdateUrlParameter(editDef.url, idName, id);
					window.location.href = targetUrl;
					return;
				}
				// The handlert enables ajax forms on the loaded response, and adds a handler to redraw the table on modal close
				var handler = function(responseText, responseHtml) {
					yada.datatableDrawOnModalClose(dataTable);
					recursiveEnableAjaxForm(responseText, responseHtml);
				};
				var requestData = {};
				requestData[idName] = id;
				var noLoader = editDef.noLoader || false;
				yada.ajax(editDef.url, requestData, handler, null, null, noLoader);
			});
		}
		
		// yadaTableToolbar "delete button"
		if (deleteDef!=null) {
			var deleteButton = $table.parents('.yadaTableBlock').find('.yadaTableToolbar a.s_deleteButton');
			deleteButton.click(function(e) {
				e.preventDefault();
				var $checks = $table.find("tbody [type='checkbox']:checked");
				var totElements = $checks.length;
				var ids = $checks.map(function() {
					var id = $(this).parents('tr').attr('id');
					if (id==null) {
						alert('Internal Error-ID missing in row: did you forget "DT_RowId" in the Model?');
					}
					return yada.getHashValue(id);
				}).get();
		
				var confirmTitle = deleteDef.confirmTitle || null;
				var confirmMessage = deleteDef.confirmManyMessage || "Do you want to delete {0} elements?";
				confirmMessage = confirmMessage.replace("{0}", totElements);
				var confirmButtonText = deleteDef.confirmButtonText || "Delete";
				var abortButtonText = deleteDef.abortButtonText || "Cancel";
				var noLoader = deleteDef.noLoader || false;
				yada.confirm(confirmTitle, confirmMessage, function(result) {
					if (result==true) {
						var idName = deleteDef.idName || "id";
						var requestData = {};
						requestData[idName] = ids;
						var handler = function() {
							dataTable.draw(false);
						};
						handler.executeAnyway=true;
						yada.ajax(deleteDef.url, requestData, handler, null, null, noLoader);
					}
				}, confirmButtonText + ' ' + totElements, abortButtonText);
			});
		}
		
		// yadaTableToolbar: aggiunta extraButtons
		if (extraButtons!=null) {
			makeToolbarExtraButtons(extraButtons, dataTable, $table);
		}
			  
		return dataTable;
	};
	
	yada.datatableDrawOnModalClose = function(dataTable) {
		// At this time the modal has not been inserted in page yet, so we need to set
		// this handler after the current method ends. We do this with a 0 timeout.
		setTimeout(function() {
			$('.modal.yadaAjaxModal').on('hide.bs.modal', function () {
				dataTable.draw(false);
				$('.modal.yadaAjaxModal').unbind('hide.bs.modal');
			});
		}, 0);
	}
	
	function makeToolbarExtraButtons(extraButtons, dataTable, $table) {
		var sortedExtraButtons = extraButtons.sort(function (a, b) { return Math.sign(a.toolbarPosition-b.toolbarPosition) });
		for (var i=0; i' +
				btndef.icon /*.replace('fa ', 'fa fa-lg ')*/ + ' '+btndef.toolbarText+'' +
				' ';
				var pos = btndef.toolbarPosition;
				var $yadaTableToolbar = $table.parents('.yadaTableBlock').find('.yadaTableToolbar');
				var $existing = $('a.btn', $yadaTableToolbar);
				if (pos==null || $existing.length<=pos) {
					$yadaTableToolbar.append(buttonHtml);
				} else {
					$existing.eq(pos).before(buttonHtml);
				}
				makeExtraButtonHandler(btndef, $('.s_toolbarExtraButton' + i, $yadaTableToolbar), dataTable, $table);
			}
		}
	}
	
	function makeExtraButtonHandler(extraButtonDef, $button, dataTable, $table) {
		$button.click(function(e) {
			e.preventDefault();
			var isRowIcon = $(this).hasClass("yadaRowCommandButton");
			var buttonUrl = extraButtonDef.url;
			var ids = [];
			var id = yada.getHashValue($(this).attr('href'));
			var totElements = 1;
			if (!isRowIcon) {
				// Toolbar button
				var $checks = $table.find("tbody [type='checkbox']:checked");
				totElements = $checks.length;
				ids = $checks.map(function() {
					var id = $(this).parents('tr').attr('id');
					if (id==null) {
						alert('Internal Error-ID missing in row: did you forget "DT_RowId" in the Model?');
					}
					return yada.getHashValue(id);
				}).get();
			} else {
				ids = [id];
			}
			var noLoader = extraButtonDef.noLoader || false;
			if (typeof extraButtonDef.url == "function") {
				if (isRowIcon) {
					// Row button
					var rowData = dataTable.row(this.parentElement).data();
					buttonUrl = buttonUrl(rowData);
				} else {
					// Toolbar button
					// TODO to be tested
					var rowData = dataTable.rows();
					buttonUrl = buttonUrl(rowData, ids);
				}
			}
			var idName = extraButtonDef.idName==null ? "id" : extraButtonDef.idName;
			var param = (ids.length>1?ids:ids[0]); // Either send one id or all of them
			if (extraButtonDef.ajax === false) {
				if (typeof extraButtonDef.url != "function") {
					buttonUrl = yada.addOrUpdateUrlParameter(buttonUrl, idName, param);
				}
				if (extraButtonDef.windowName!=null) {
					window.open(buttonUrl, extraButtonDef.windowName, extraButtonDef.windowFeatures);
				} else {
					window.location.replace(buttonUrl);
				}
				return;
			}
			var requestData = {};
			if (idName!="") {
				requestData[idName] = param;
			}
			var handler = function(responseText, responseHtml) {
				dataTable.draw(false); // Always reload table content on return from ajax call (there could be no modal)
				yada.datatableDrawOnModalClose(dataTable);
				recursiveEnableAjaxForm(responseText, responseHtml);
			};
			if (extraButtonDef.confirm!=true) {
				yada.ajax(buttonUrl, requestData, handler, null, null, noLoader);
			} else {
				// Confirm modal
				const confirmTitle = extraButtonDef.confirmTitle || null;
				var confirmMessage = null;
				if (totElements<2) {
					var rowIndex = dataTable.row(this.parentElement).index();
					if (!isRowIcon) {
						rowIndex = dataTable.row($table.find("tbody [type='checkbox']:checked").parent()).index();
					}
					var nameColumn = extraButtonDef.confirmNameColumn || 3; // We assume that column 1 is the select, column 2 is the id and column 3 is the name or similar
					const rowName = dataTable.cell(rowIndex, nameColumn).data(); 
					confirmMessage = extraButtonDef.confirmOneMessage || "Do you want to delete {0}?";
					confirmMessage = confirmMessage.replace("{0}", rowName);
				} else {
					confirmMessage = extraButtonDef.confirmManyMessage || `Do you want to delete ${totElements} elements?`;
				}
				yada.confirm(confirmTitle, confirmMessage, function(result) {
						if (result==true) {
							yada.ajax(buttonUrl, requestData, handler, null, null, noLoader);
						}
					}, extraButtonDef.confirmButtonText, extraButtonDef.abortButtonText
				);
				
			}			
		});
	}
	
	function recursiveEnableAjaxForm(responseText, responseHtml) {
		yada.enableAjaxForm($('form.yadaAjaxForm', responseHtml), recursiveEnableAjaxForm);
		// Legacy
		yada.enableAjaxForm($('form.s_ajaxForm', responseHtml), recursiveEnableAjaxForm);
	};

	
}( window.yada = window.yada || {} ));






© 2015 - 2024 Weber Informatics LLC | Privacy Policy