-
Todor Kondic authored
* shiny-ui-base (celledit_values, dt_drop_callback, editcell_script, dropdown_dt): New functions. (simple_style_dt): Updated. (rf_get_inp_datafiles): Removed. (datatab-edit): New observer. <other observers>: Modified so they work with rv_dfiles, rv_datafiles and dropdowns. <renderDT>: Output renders updated. www: cellEdit javascript and css app: Updated controls.
Todor Kondic authored* shiny-ui-base (celledit_values, dt_drop_callback, editcell_script, dropdown_dt): New functions. (simple_style_dt): Updated. (rf_get_inp_datafiles): Removed. (datatab-edit): New observer. <other observers>: Modified so they work with rv_dfiles, rv_datafiles and dropdowns. <renderDT>: Output renders updated. www: cellEdit javascript and css app: Updated controls.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
dataTables.cellEdit.js 12.71 KiB
/*! CellEdit 1.0.19
* ©2016 Elliott Beaty - datatables.net/license
*/
/**
* @summary CellEdit
* @description Make a cell editable when clicked upon
* @version 1.0.19
* @file dataTables.editCell.js
* @author Elliott Beaty
* @contact elliott@elliottbeaty.com
* @copyright Copyright 2016 Elliott Beaty
*
* This source file is free software, available under the following license:
* MIT license - http://datatables.net/license/mit
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
*
* For details please refer to: http://www.datatables.net
*/
jQuery.fn.dataTable.Api.register('MakeCellsEditable()', function (settings) {
var table = this.table();
jQuery.fn.extend({
// UPDATE
updateEditableCell: function (callingElement) {
// Need to redeclare table here for situations where we have more than one datatable on the page. See issue6 on github
var table = $(callingElement).closest("table").DataTable().table();
var row = table.row($(callingElement).parents('tr'));
var cell = table.cell($(callingElement).parents('td, th'));
var columnIndex = cell.index().column;
var inputField =getInputField(callingElement);
// Update
var newValue = inputField.val();
if (!newValue && ((settings.allowNulls) && settings.allowNulls != true)) {
// If columns specified
if (settings.allowNulls.columns) {
// If current column allows nulls
if (settings.allowNulls.columns.indexOf(columnIndex) > -1) {
_update(newValue);
} else {
_addValidationCss();
}
// No columns allow null
} else if (!newValue) {
_addValidationCss();
}
//All columns allow null
} else if (newValue && settings.onValidate) {
if (settings.onValidate(cell, row, newValue)) {
_update(newValue);
} else {
_addValidationCss();
}
}
else {
_update(newValue);
}
function _addValidationCss() {
// Show validation error
if (settings.allowNulls.errorClass) {
$(inputField).addClass(settings.allowNulls.errorClass);
} else {
$(inputField).css({ "border": "red solid 1px" });
}
}
function _update(newValue) {
var oldValue = cell.data();
cell.data(newValue);
//Return cell & row.
settings.onUpdate(cell, row, oldValue);
}
// Get current page
var currentPageIndex = table.page.info().page;
//Redraw table
table.page(currentPageIndex).draw(false);
},
// CANCEL
cancelEditableCell: function (callingElement) {
var table = $(callingElement.closest("table")).DataTable().table();
var cell = table.cell($(callingElement).parents('td, th'));
// Set cell to it's original value
cell.data(cell.data());
// Redraw table
table.draw();
}
});
// Destroy
if (settings === "destroy") {
$(table.body()).off("click", "td");
table = null;
}
if (table != null) {
// On cell click
$(table.body()).on('click', 'td', function () {
var currentColumnIndex = table.cell(this).index().column;
// DETERMINE WHAT COLUMNS CAN BE EDITED
if ((settings.columns && settings.columns.indexOf(currentColumnIndex) > -1) || (!settings.columns)) {
var row = table.row($(this).parents('tr'));
editableCellsRow = row;
var cell = table.cell(this).node();
var oldValue = table.cell(this).data();
// Sanitize value
oldValue = sanitizeCellValue(oldValue);
// Show input
if (!$(cell).find('input').length && !$(cell).find('select').length && !$(cell).find('textarea').length) {
// Input CSS
var input = getInputHtml(currentColumnIndex, settings, oldValue);
$(cell).html(input.html);
if (input.focus) {
$('#ejbeatycelledit').focus();
}
}
}
});
}
});
function getInputHtml(currentColumnIndex, settings, oldValue) {
var inputSetting, inputType, input, inputCss, confirmCss, cancelCss, startWrapperHtml = '', endWrapperHtml = '', listenToKeys = false;
input = {"focus":true,"html":null};
if(settings.inputTypes){
$.each(settings.inputTypes, function (index, setting) {
if (setting.column == currentColumnIndex) {
inputSetting = setting;
inputType = inputSetting.type.toLowerCase();
}
});
}
if (settings.inputCss) { inputCss = settings.inputCss; }
if (settings.wrapperHtml) {
var elements = settings.wrapperHtml.split('{content}');
if (elements.length === 2) {
startWrapperHtml = elements[0];
endWrapperHtml = elements[1];
}
}
if (settings.confirmationButton) {
if (settings.confirmationButton.listenToKeys) { listenToKeys = settings.confirmationButton.listenToKeys; }
confirmCss = settings.confirmationButton.confirmCss;
cancelCss = settings.confirmationButton.cancelCss;
inputType = inputType + "-confirm";
}
switch (inputType) {
case "list":
input.html = startWrapperHtml + "<select class='" + inputCss + "' onchange='$(this).updateEditableCell(this);'>";
$.each(inputSetting.options, function (index, option) {
if (oldValue == option.value) {
input.html = input.html + "<option value='" + option.value + "' selected>" + option.display + "</option>"
} else {
input.html = input.html + "<option value='" + option.value + "' >" + option.display + "</option>"
}
});
input.html = input.html + "</select>" + endWrapperHtml;
input.focus = false;
break;
case "list-confirm": // List w/ confirm
input.html = startWrapperHtml + "<select class='" + inputCss + "'>";
$.each(inputSetting.options, function (index, option) {
if (oldValue == option.value) {
input.html = input.html + "<option value='" + option.value + "' selected>" + option.display + "</option>"
} else {
input.html = input.html + "<option value='" + option.value + "' >" + option.display + "</option>"
}
});
input.html = input.html + "</select> <a href='javascript:void(0);' class='" + confirmCss + "' onclick='$(this).updateEditableCell(this);'>Confirm</a> <a href='javascript:void(0);' class='" + cancelCss + "' onclick='$(this).cancelEditableCell(this)'>Cancel</a>" + endWrapperHtml;
input.focus = false;
break;
case "datepicker": //Both datepicker options work best when confirming the values
case "datepicker-confirm":
// Makesure jQuery UI is loaded on the page
if (typeof jQuery.ui == 'undefined') {
alert("jQuery UI is required for the DatePicker control but it is not loaded on the page!");
break;
}
jQuery(".datepick").datepicker("destroy");
input.html = startWrapperHtml + "<input id='ejbeatycelledit' type='text' name='date' class='datepick " + inputCss + "' value='" + oldValue + "'></input> <a href='javascript:void(0);' class='" + confirmCss + "' onclick='$(this).updateEditableCell(this)'>Confirm</a> <a href='javascript:void(0);' class='" + cancelCss + "' onclick='$(this).cancelEditableCell(this)'>Cancel</a>" + endWrapperHtml;
setTimeout(function () { //Set timeout to allow the script to write the input.html before triggering the datepicker
var icon = "http://jqueryui.com/resources/demos/datepicker/images/calendar.gif";
// Allow the user to provide icon
if (typeof inputSetting.options !== 'undefined' && typeof inputSetting.options.icon !== 'undefined') {
icon = inputSetting.options.icon;
}
var self = jQuery('.datepick').datepicker(
{
showOn: "button",
buttonImage: icon,
buttonImageOnly: true,
buttonText: "Select date"
});
},100);
break;
case "text-confirm": // text input w/ confirm
input.html = startWrapperHtml + "<input id='ejbeatycelledit' class='" + inputCss + "' value='"+oldValue+"'" + (listenToKeys ? " onkeyup='if(event.keyCode==13) {$(this).updateEditableCell(this);} else if (event.keyCode===27) {$(this).cancelEditableCell(this);}'" : "") + "></input> <a href='javascript:void(0);' class='" + confirmCss + "' onclick='$(this).updateEditableCell(this)'>Confirm</a> <a href='javascript:void(0);' class='" + cancelCss + "' onclick='$(this).cancelEditableCell(this)'>Cancel</a>" + endWrapperHtml;
break;
case "undefined-confirm": // text input w/ confirm
input.html = startWrapperHtml + "<input id='ejbeatycelledit' class='" + inputCss + "' value='" + oldValue + "'" + (listenToKeys ? " onkeyup='if(event.keyCode==13) {$(this).updateEditableCell(this);} else if (event.keyCode===27) {$(this).cancelEditableCell(this);}'" : "") + "></input> <a href='javascript:void(0);' class='" + confirmCss + "' onclick='$(this).updateEditableCell(this)'>Confirm</a> <a href='javascript:void(0);' class='" + cancelCss + "' onclick='$(this).cancelEditableCell(this)'>Cancel</a>" + endWrapperHtml;
break;
case "textarea":
input.html = startWrapperHtml + "<textarea id='ejbeatycelledit' class='" + inputCss + "' onfocusout='$(this).updateEditableCell(this)' >"+oldValue+"</textarea>" + endWrapperHtml;
break;
case "textarea-confirm":
input.html = startWrapperHtml + "<textarea id='ejbeatycelledit' class='" + inputCss + "'>"+oldValue+"</textarea><a href='javascript:void(0);' class='" + confirmCss + "' onclick='$(this).updateEditableCell(this)'>Confirm</a> <a href='javascript:void(0);' class='" + cancelCss + "' onclick='$(this).cancelEditableCell(this)'>Cancel</a>" + endWrapperHtml;
break;
case "number-confirm" :
input.html = startWrapperHtml + "<input id='ejbeatycelledit' type='number' class='" + inputCss + "' value='"+oldValue+"'" + (listenToKeys ? " onkeyup='if(event.keyCode==13) {$(this).updateEditableCell(this);} else if (event.keyCode===27) {$(this).cancelEditableCell(this);}'" : "") + "></input> <a href='javascript:void(0);' class='" + confirmCss + "' onclick='$(this).updateEditableCell(this)'>Confirm</a> <a href='javascript:void(0);' class='" + cancelCss + "' onclick='$(this).cancelEditableCell(this)'>Cancel</a>" + endWrapperHtml;
break;
default: // text input
input.html = startWrapperHtml + "<input id='ejbeatycelledit' class='" + inputCss + "' onfocusout='$(this).updateEditableCell(this)' value='" + oldValue + "'></input>" + endWrapperHtml;
break;
}
return input;
}
function getInputField(callingElement) {
// Update datatables cell value
var inputField;
switch ($(callingElement).prop('nodeName').toLowerCase()) {
case 'a': // This means they're using confirmation buttons
if ($(callingElement).siblings('input').length > 0) {
inputField = $(callingElement).siblings('input');
}
if ($(callingElement).siblings('select').length > 0) {
inputField = $(callingElement).siblings('select');
}
if ($(callingElement).siblings('textarea').length > 0) {
inputField = $(callingElement).siblings('textarea');
}
break;
default:
inputField = $(callingElement);
}
return inputField;
}
function sanitizeCellValue(cellValue) {
if (typeof (cellValue) === 'undefined' || cellValue === null || cellValue.length < 1) {
return "";
}
// If not a number
if (isNaN(cellValue)) {
// escape single quote
cellValue = cellValue.replace(/'/g, "'");
}
return cellValue;
}