';
// add modal
$('body').append(modal);
// add Edit Button
if (dt.button('edit:name')) {
dt.button('edit:name').action(function (e, dt, node, config) {
that._openEditModal();
$(`#altEditor-edit-form-${that.random_id}`)
.off('submit')
.on('submit', function (e) {
e.preventDefault();
e.stopPropagation();
that._editRowData();
});
});
}
// add Delete Button
if (dt.button('delete:name')) {
dt.button('delete:name').action(function (e, dt, node, config) {
that._openDeleteModal();
$(`#altEditor-delete-form-${that.random_id}`)
.off('submit')
.on('submit', function (e) {
e.preventDefault();
e.stopPropagation();
that._deleteRow();
});
});
}
// add Add Button
if (dt.button('add:name')) {
dt.button('add:name').action(function (e, dt, node, config) {
that._openAddModal();
$(`#altEditor-add-form-${that.random_id}`)
.off('submit')
.on('submit', function (e) {
e.preventDefault();
e.stopPropagation();
that._addRowData();
});
});
}
// bind 'unique' error messages
$(this.modal_selector).bind('input', '[data-unique]', function(elm) {
if ($(elm.target).attr('data-unique') == null || $(elm.target).attr('data-unique') === 'false') {
return;
}
var target = $(elm.target);
var colData = dt.column("th:contains('" + target.attr("name") + "')").data();
// go through each item in this column
var selectedCellData = null;
if (dt.row({selected: true}).index() != null)
selectedCellData = dt.cell(dt.row({selected: true}).index(), dt.column("th:contains('" + target.attr("name") + "')").index()).data();
elm.target.setCustomValidity('');
for (var j in colData) {
// if the element is in the column and its not the selected one then its not unique
if (target.val() == colData[j] && colData[j] != selectedCellData) {
elm.target.setCustomValidity(that.language.error.unique);
}
}
});
// add Refresh button
if (this.s.dt.button('refresh:name')) {
this.s.dt.button('refresh:name').action(function (e, dt, node, config) {
if (dt.ajax && dt.ajax.url()) {
dt.ajax.reload();
}
});
}
},
/**
* Emit an event on the DataTable for listeners
*
* @param {string}
* name Event name
* @param {array}
* args Event arguments
* @private
*/
_emitEvent: function (name, args) {
this.s.dt.iterator('table', function (ctx, i) {
$(ctx.nTable).triggerHandler(name + '.dt', args);
});
},
/**
* Open Edit Modal for selected row
*
* @private
*/
_openEditModal: function () {
var dt = this.s.dt;
var adata = dt.rows({
selected: true
});
var columnDefs = this.completeColumnDefs();
var data = this.createDialog(columnDefs, this.language.edit.title, this.language.edit.button,
this.language.modalClose, 'editRowBtn', 'altEditor-edit-form');
var selector = this.modal_selector;
for (var j in columnDefs) {
var arrIndex = "['" + columnDefs[j].name.toString().split(".").join("']['") + "']";
var selectedValue = eval("adata.data()[0]" + arrIndex);
var jquerySelector = "#" + columnDefs[j].name.toString().replace(/\./g, "\\.");
$(selector).find(jquerySelector).val(this._quoteattr(selectedValue));
$(selector).find(jquerySelector).trigger("change"); // required by select2
}
$(selector + ' input[0]').focus();
$(selector).trigger("alteditor:some_dialog_opened").trigger("alteditor:edit_dialog_opened");
},
/**
* Callback for "Edit" button
*/
_editRowData: function () {
var that = this;
var dt = this.s.dt;
// Complete new row data
var rowDataArray = {};
var adata = dt.rows({
selected: true
});
// Getting the inputs from the edit-modal
$(`form[name="altEditor-edit-form-${this.random_id}"] *`).filter(':input').each(function (i) {
rowDataArray[$(this).attr('id')] = $(this).val();
});
//Getting the textArea from the modal
$(`form[name="altEditor-add-form-${this.random_id}"] *`).filter('textarea').each(function (i) {
rowDataArray[$(this).attr('id')] = $(this).val();
});
console.log(rowDataArray); //DEBUG
that.onEditRow(that,
rowDataArray,
function(data,b,c,d,e){ that._editRowCallback(data,b,c,d,e); },
function(data){ that._errorCallback(data);
});
},
/**
* Open Delete Modal for selected row
*
* @private
*/
_openDeleteModal: function () {
var that = this;
var dt = this.s.dt;
var adata = dt.rows({
selected: true
});
var columnDefs = this.completeColumnDefs();
const formName = 'altEditor-delete-form-' + this.random_id;
// TODO
// we should use createDialog()
// var data = this.createDialog(columnDefs, this.language.delete.title, this.language.delete.button,
// this.language.modalClose, 'deleteRowBtn', 'altEditor-delete-form');
// Building delete-modal
var data = "";
for (var j in columnDefs) {
if (columnDefs[j].type.indexOf("hidden") >= 0) {
data += "";
}
else {
data += "
"
+ adata.data()[0][columnDefs[j].name]
+ "
";
}
}
var selector = this.modal_selector;
$(selector).on('show.bs.modal', function () {
var btns = '' +
'';
$(selector).find('.modal-title').html(that.language.delete.title);
$(selector).find('.modal-body').html(data);
$(selector).find('.modal-footer').html(btns);
const modalContent = $(selector).find('.modal-content');
if (modalContent.parent().is('form')) {
modalContent.parent().attr('name', formName);
modalContent.parent().attr('id', formName);
} else {
modalContent.wrap("");
}
});
$(selector).modal('show');
$(selector + ' input[0]').focus();
$(selector).trigger("alteditor:some_dialog_opened").trigger("alteditor:delete_dialog_opened");
},
/**
* Callback for "Delete" button
*/
_deleteRow: function () {
var that = this;
var dt = this.s.dt;
var jsonDataArray = {};
var adata = dt.rows({
selected: true
});
// Getting the IDs and Values of the tablerow
for (var i = 0; i < dt.context[0].aoColumns.length; i++) {
// .data is the attribute name, if any; .idx is the column index, so it should always exists
var name = dt.context[0].aoColumns[i].data ? dt.context[0].aoColumns[i].data :
dt.context[0].aoColumns[i].mData ? dt.context[0].aoColumns[i].mData :
dt.context[0].aoColumns[i].idx;
jsonDataArray[name] = adata.data()[0][name];
}
that.onDeleteRow(that,
jsonDataArray,
function(data){ that._deleteRowCallback(data); },
function(data){ that._errorCallback(data);
});
},
/**
* Open Add Modal for selected row
*
* @private
*/
_openAddModal: function () {
var dt = this.s.dt;
var columnDefs = this.completeColumnDefs();
var data = this.createDialog(columnDefs, this.language.add.title, this.language.add.button,
this.language.modalClose, 'addRowBtn', 'altEditor-add-form');
var selector = this.modal_selector;
$(selector + ' input[0]').focus();
$(selector).trigger("alteditor:some_dialog_opened").trigger("alteditor:add_dialog_opened");
},
/**
* Complete DataTable.context[0].aoColumns with default values
*/
completeColumnDefs: function () {
var columnDefs = [];
var dt = this.s.dt;
for (var i in dt.context[0].aoColumns) {
var obj = dt.context[0].aoColumns[i];
columnDefs[i] = {
title: obj.sTitle,
name: (obj.data ? obj.data : obj.mData),
type: (obj.type ? obj.type : 'text'),
rows: (obj.rows ? obj.rows : '5'),
cols: (obj.cols ? obj.cols : '30'),
options: (obj.options ? obj.options : []),
readonly: (obj.readonly ? obj.readonly : false),
disabled: (obj.disabled ? obj.disabled : false),
required: (obj.required ? obj.required : false),
msg: (obj.errorMsg ? obj.errorMsg : ''), // FIXME no more used
hoverMsg: (obj.hoverMsg ? obj.hoverMsg : ''),
pattern: (obj.pattern ? obj.pattern : '.*'),
special: (obj.special ? obj.special : ''),
unique: (obj.unique ? obj.unique : false),
uniqueMsg: (obj.uniqueMsg ? obj.uniqueMsg : ''), // FIXME no more used
maxLength: (obj.maxLength ? obj.maxLength : false),
multiple: (obj.multiple ? obj.multiple : false),
select2: (obj.select2 ? obj.select2 : false),
datepicker: (obj.datepicker ? obj.datepicker : false),
datetimepicker: (obj.datetimepicker ? obj.datetimepicker : false),
editorOnChange: (obj.editorOnChange ? obj.editorOnChange : null)
}
}
return columnDefs;
},
/**
* Create both Edit and Add dialogs
* @param columnDefs as returned by completeColumnDefs()
*/
createDialog: function(columnDefs, title, buttonCaption, closeCaption, buttonClass, formName) {
formName = [formName, this.random_id].join('-');
var data = "";
for (var j in columnDefs) {
//handle hidden fields
if (columnDefs[j].type.indexOf("hidden") >= 0) {
data += "";
}
else {
// handle fields that are visible to the user
data += "
";
data += "
";
data += "
";
data += "
";
// Adding readonly-fields
if (columnDefs[j].type.indexOf("readonly") >= 0) {
// type=readonly is deprecated, kept for backward compatibility
data += "";
}
// Adding select-fields
else if (columnDefs[j].type.indexOf("select") >= 0) {
var options = "";
var optionsArray = columnDefs[j].options;
if (optionsArray.length > 0) {
// array-style select or select2
for (var i = 0; i < optionsArray.length; i++) {
options += "";
}
} else {
// object-style select or select2
for (var x in optionsArray) {
options += "";
}
}
data += "";
}
//Adding Text Area
else if (columnDefs[j].type.indexOf("textarea") >= 0)
{
data += "";
}
// Adding text-inputs and errorlabels, but also new HTML5 typees (email, color, ...)
else {
data += "";
}
data += "";
data += "
";
}
}
// data += "";
var selector = this.modal_selector;
$(selector).on('show.bs.modal', function () {
var btns = '' +
'';
$(selector).find('.modal-title').html(title);
$(selector).find('.modal-body').html(data);
$(selector).find('.modal-footer').html(btns);
const modalContent = $(selector).find('.modal-content');
if (modalContent.parent().is('form')) {
modalContent.parent().attr('name', formName);
modalContent.parent().attr('id', formName);
} else {
modalContent.wrap("");
}
});
$(selector).modal('show');
$(selector + ' input[0]').focus();
var that = this;
// enable select 2 items, datepicker, datetimepickerm
for (var j in columnDefs) {
if (columnDefs[j].select2) {
// Require select2 plugin
$(selector).find("select#" + columnDefs[j].name).select2(columnDefs[j].select2);
} else if (columnDefs[j].datepicker) {
// Require jquery-ui
$(selector).find("#" + columnDefs[j].name).datepicker(columnDefs[j].datepicker);
} else if (columnDefs[j].datetimepicker) {
// Require datetimepicker plugin
$(selector).find("#" + columnDefs[j].name).datetimepicker(columnDefs[j].datetimepicker);
}
// custom onchange triggers
if (columnDefs[j].editorOnChange) {
var f = columnDefs[j].editorOnChange; // FIXME what if more than 1 editorOnChange ?
$(selector).find("#" + columnDefs[j].name).on('change', function(elm) {
f(elm, that);
});
}
}
},
/**
* Callback for "Add" button
*/
_addRowData: function () {
var that = this;
var dt = this.s.dt;
var rowDataArray = {};
// Getting the inputs from the modal
$(`form[name="altEditor-add-form-${this.random_id}"] *`).filter(':input').each(function (i) {
rowDataArray[$(this).attr('id')] = $(this).val();
});
//Getting the textArea from the modal
$(`form[name="altEditor-add-form-${this.random_id}"] *`).filter('textarea').each(function (i) {
rowDataArray[$(this).attr('id')] = $(this).val();
});
//console.log(rowDataArray); //DEBUG
that.onAddRow(that,
rowDataArray,
function(data){ that._addRowCallback(data); },
function(data){ that._errorCallback(data);
});
},
/**
* Called after a row has been deleted on server
*/
_deleteRowCallback: function (response, status, more) {
var selector = this.modal_selector;
$(selector + ' .modal-body .alert').remove();
var message = '
' +
'' + this.language.success + '' +
'
';
$(selector + ' .modal-body').append(message);
this.s.dt.row({
selected : true
}).remove();
this.s.dt.draw('page');
// Disabling submit button
$("div"+selector).find("button#addRowBtn").prop('disabled', true);
$("div"+selector).find("button#editRowBtn").prop('disabled', true);
$("div"+selector).find("button#deleteRowBtn").prop('disabled', true);
},
/**
* Called after a row has been inserted on server
*/
_addRowCallback: function (response, status, more) {
//TODO should honor dt.ajax().dataSrc
var data = (typeof response === "string") ? JSON.parse(response) : response;
var selector = this.modal_selector;
$(selector + ' .modal-body .alert').remove();
var message = '
' +
'' + this.language.success + '' +
'
';
$(selector + ' .modal-body').append(message);
this.s.dt.row.add(data).draw(false);
// Disabling submit button
$("div" + selector).find("button#addRowBtn").prop('disabled', true);
$("div" + selector).find("button#editRowBtn").prop('disabled', true);
$("div" + selector).find("button#deleteRowBtn").prop('disabled', true);
},
/**
* Called after a row has been updated on server
*/
_editRowCallback: function (response, status, more) {
//TODO should honor dt.ajax().dataSrc
var data = (typeof response === "string") ? JSON.parse(response) : response;
var selector = this.modal_selector;
$(selector + ' .modal-body .alert').remove();
var message = '
' +
'' + this.language.success + '' +
'
';
$(selector + ' .modal-body').append(message);
this.s.dt.row({
selected : true
}).data(data);
this.s.dt.draw('page');
// Disabling submit button
$("div" + selector).find("button#addRowBtn").prop('disabled', true);
$("div" + selector).find("button#editRowBtn").prop('disabled', true);
$("div" + selector).find("button#deleteRowBtn").prop('disabled', true);
},
/**
* Called after AJAX server returned an error
*/
_errorCallback: function (response, status, more) {
var error = response;
var selector = this.modal_selector;
$(selector + ' .modal-body .alert').remove();
var errstr = this.language.error.message;
if (error.responseJSON && error.responseJSON.errors) {
errstr = "";
for (var key in error.responseJSON.errors) {
errstr += error.responseJSON.errors[key][0];
}
}
var message = '
';
$(selector + ' .modal-body').append(message);
},
/**
* Default callback for insertion: mock webservice, always success.
*/
onAddRow: function(dt, rowdata, success, error) {
console.log("Missing AJAX configuration for INSERT");
success(rowdata);
},
/**
* Default callback for editing: mock webservice, always success.
*/
onEditRow: function(dt, rowdata, success, error) {
console.log("Missing AJAX configuration for UPDATE");
success(rowdata);
},
/**
* Default callback for deletion: mock webservice, always success.
*/
onDeleteRow: function(dt, rowdata, success, error) {
console.log("Missing AJAX configuration for DELETE");
success(rowdata);
},
/**
* Dinamically reload options in SELECT menu
*/
reloadOptions: function($select, options) {
var oldValue = $select.val();
$select.empty(); // remove old options
if (options.length > 0) {
// array-style select or select2
$.each(options, function(key, value) {
$select.append($("")
.attr("value", value).text(value));
});
} else {
// object-style select or select2
$.each(options, function(key, value) {
$select.append($("")
.attr("value", value).text(key));
});
}
$select.val(oldValue); // if still present, of course
$select.trigger('change');
},
/**
* Sanitizes input for use in HTML
* @param s
* @param preserveCR
* @returns {string}
* @private
*/
_quoteattr: function (s, preserveCR) {
if (s == null)
return "";
preserveCR = preserveCR ? '
' : '\n';
if (Array.isArray(s)) {
// for MULTIPLE SELECT
var newArray = [];
var x;
for (x in s) newArray.push(s[x]);
return newArray;
}
return ('' + s) /* Forces the conversion to string. */
.replace(/&/g, '&') /* This MUST be the 1st replacement. */
.replace(/'/g, ''') /* The 4 other predefined entities, required. */
.replace(/"/g, '"')
.replace(//g, '>')
.replace(/\r\n/g, preserveCR) /* Must be before the next replacement. */
.replace(/[\r\n]/g, preserveCR);
},
});
/**
* altEditor version
*
* @static
* @type String
*/
altEditor.version = '2.0';
/**
* altEditor defaults
*
* @namespace
*/
altEditor.defaults = {
/**
* @type {Boolean} Ask user what they want to do, even for a single
* option
*/
alwaysAsk: false,
/** @type {string|null} What will trigger a focus */
focus: null, // focus, click, hover
/** @type {column-selector} Columns to provide auto fill for */
columns: '', // all
/** @type {boolean|null} Update the cells after a drag */
update: null, // false is editor given, true otherwise
/** @type {DataTable.Editor} Editor instance for automatic submission */
editor: null
};
/**
* Classes used by altEditor that are configurable
*
* @namespace
*/
altEditor.classes = {
/** @type {String} Class used by the selection button */
btn: 'btn'
};
// Attach a listener to the document which listens for DataTables
// initialisation
// events so we can automatically initialise
$(document).on('preInit.dt.altEditor', function (e, settings, json) {
if (e.namespace !== 'dt') {
return;
}
var init = settings.oInit.altEditor;
var defaults = DataTable.defaults.altEditor;
if (init || defaults) {
var opts = $.extend({}, init, defaults);
if (init !== false) {
var editor = new altEditor(settings, opts);
// e is a jQuery event object
// e.target is the underlying jQuery object, e.g. $('#mytable')
// so that you can retrieve the altEditor object later
e.target.altEditor = editor;
}
}
});
// Alias for access
DataTable.altEditor = altEditor;
return altEditor;
});