diff --git a/jquery-editable-table.js b/jquery-editable-table.js
index dc1c245..ae44d24 100644
--- a/jquery-editable-table.js
+++ b/jquery-editable-table.js
@@ -1,9 +1,10 @@
-$.fn.editableTable = function (options) {
+$.fn.editableTable = function(options) {
// Default options
let defaultOptions = {
cloneProperties: ['padding', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right',
'text-align', 'font', 'font-size', 'font-family', 'font-weight',
- 'border', 'border-top', 'border-bottom', 'border-left', 'border-right', 'color', 'background-color', 'border-radius'],
+ 'border', 'border-top', 'border-bottom', 'border-left', 'border-right', 'color', 'background-color', 'border-radius'
+ ],
columns: []
}
@@ -33,21 +34,20 @@ $.fn.editableTable = function (options) {
// The table element
let element = $(this);
-
+
// Show all columns and then hide any hidden ones
element.find('th').show();
- options.columns.forEach((col, i)=>{
- if(col.isHidden !== undefined && col.isHidden) element.find('th').eq(i).hide();
+ options.columns.forEach((col, i) => {
+ if (col.isHidden !== undefined && col.isHidden) element.find('th').eq(i).hide();
});
-
+
// The textbox allowing user input. Only add if there's not already an editor input control around
let editor;
let existingEditor = element.parent().find(`input[${identifierAttribute}]`);
if (existingEditor.length) {
editor = existingEditor.first();
- }
- else {
+ } else {
editor = $(' ');
}
@@ -66,14 +66,14 @@ $.fn.editableTable = function (options) {
activeCell = element.find('td:focus');
if (activeCell.length) {
// Prepare
- editor.val(activeCell.text()) // Throw the value in
- .removeClass(errorClass) // remove any error classes
- .show() // show it
- .offset(activeCell.offset()) // position it
- .css(activeCell.css(options.cloneProperties)) // make it look similar by cloning properties
- .width(activeCell.width()) // size it
- .height(activeCell.height()) // size it
- .focus(); // focu user input into it
+ editor.val(activeCell.text()) // Throw the value in
+ .removeClass(errorClass) // remove any error classes
+ .show() // show it
+ .offset(activeCell.offset()) // position it
+ .css(activeCell.css(options.cloneProperties)) // make it look similar by cloning properties
+ .width(activeCell.width()) // size it
+ .height(activeCell.height()) // size it
+ .focus(); // focus user input into it
if (select) {
editor.select();
}
@@ -109,25 +109,22 @@ $.fn.editableTable = function (options) {
};
// On the editor losing focus, hide the input
- editor.blur(function () {
+ editor.blur(function() {
setActiveText();
editor.hide();
});
// Handle typing into the input
- editor.keydown(function (e) {
+ editor.keydown(function(e) {
if (e.which === ENTER) {
setActiveText();
editor.hide();
- activeCell.focus();
e.preventDefault();
e.stopPropagation();
} else if (e.which === ESC) {
- editor.val(activeCell.text());
e.preventDefault();
e.stopPropagation();
editor.hide();
- activeCell.focus();
} else if (e.which === TAB) {
activeCell.focus();
} else if (this.selectionEnd - this.selectionStart === this.value.length) {
@@ -141,7 +138,7 @@ $.fn.editableTable = function (options) {
});
// Validate cell input on typing or pasting
- editor.on('input paste', function () {
+ editor.on('input paste', function() {
let evt = $.Event('validate');
activeCell.trigger(evt, editor.val());
if (evt.result !== undefined) {
@@ -155,8 +152,7 @@ $.fn.editableTable = function (options) {
// On table clicking, move around cells
element.on('click keypress dblclick', showEditor)
- .css('cursor', 'pointer')
- .keydown(function (e) {
+ .keydown(function(e) {
let prevent = true,
possibleMove = handleMovement($(e.target), e.which);
if (possibleMove.length > 0) {
@@ -175,9 +171,13 @@ $.fn.editableTable = function (options) {
}
});
- element.find('td').prop('tabindex', 1);
+ element
+ .find('td')
+ .not('.no-editor')
+ .prop('tabindex', 1)
+ .css('cursor', 'pointer');
- $(window).on('resize', function () {
+ $(window).on('resize', function() {
if (editor.is(':visible')) {
editor.offset(activeCell.offset())
.width(activeCell.width())
@@ -190,15 +190,17 @@ $.fn.editableTable = function (options) {
}
// Validate based on options
- $('table td').on('validate', function (evt, newValue) {
+ $('table td').on('validate', function(evt, newValue) {
let currentColIndex = $(evt.currentTarget).index();
let columnDef = options.columns[currentColIndex];
- let currentData = _instance.getData({ convert: false }); // current data to allow user to validate based on existing data
+ let currentData = _instance.getData({
+ convert: false
+ }); // current data to allow user to validate based on existing data
let isValid = columnDef.isValid && columnDef.isValid(newValue, currentData);
return isValid;
});
- $('table td').on('change', function (evt, newValue) {
+ $('table td').on('change', function(evt, newValue) {
let td = $(this);
let currentColIndex = $(evt.currentTarget).index();
let columnDef = options.columns[currentColIndex];
@@ -209,7 +211,8 @@ $.fn.editableTable = function (options) {
// Bind user-specified events if they exist
if (typeof columnDef.afterChange == 'function') {
- columnDef.afterChange(newValue, td);
+ let updatedValue = columnDef.afterChange(newValue, td);
+ if (updatedValue) td.text(updatedValue);
}
return true;
@@ -218,7 +221,7 @@ $.fn.editableTable = function (options) {
// Set up the instance reference
_instance = {
// Get table back out as JSON
- getData: function (opts) {
+ getData: function(opts) {
opts = $.extend({}, {
convert: true
}, opts);
@@ -252,8 +255,86 @@ $.fn.editableTable = function (options) {
return rowData;
},
+ addHeaders: function() {
+ let newRow = $(`
`);
+ options.columns.sort((a, b) => a.order - b.order).forEach((columnDef, index) => {
+ let newCell;
+ if (columnDef.header !== null) newCell = $(`${columnDef.header} `);
+ else newCell = $(` `);
+
+ // Apply any classes
+ if (columnDef.headerClasses !== undefined && columnDef.headerClasses.length) {
+ columnDef.headerClasses.forEach(classToAdd => newCell.addClass(classToAdd));
+ }
+
+ // Apply any style
+ if (columnDef.headerStyle !== undefined && columnDef.headerStyle.length) {
+ newCell.attr("style", newCell.attr("style") + "; " + columnDef.headerStyle);
+ }
+
+ // Hide if hidden
+ if (columnDef.isHidden !== undefined && columnDef.isHidden) {
+ newCell.hide();
+ }
+
+ // Trigger any events
+ if (typeof columnDef.afterHeaderCellAdd == 'function') {
+ columnDef.afterHeaderCellAdd(columnDef.value, newCell);
+ }
+
+ // Add to the column
+ newRow.append(newCell);
+ });
+
+ // Add the new row
+ let lastRow = element.find('thead tr:last');
+ if (lastRow.length > 0) lastRow.after(newRow);
+ else element.find('thead').append(newRow);
+
+ refresh();
+ },
+
+ addFooters: function() {
+ let newRow = $(` `);
+ options.columns.sort((a, b) => a.order - b.order).forEach((columnDef, index) => {
+ let newCell;
+ if (columnDef.footer !== null) newCell = $(`${columnDef.footer} `);
+ else newCell = $(` `);
+
+ // Apply any classes
+ if (columnDef.footerClasses !== undefined && columnDef.footerClasses.length) {
+ columnDef.footerClasses.forEach(classToAdd => newCell.addClass(classToAdd));
+ }
+
+ // Apply any style
+ if (columnDef.footerStyle !== undefined && columnDef.footerStyle.length) {
+ newCell.attr("style", newCell.attr("style") + "; " + columnDef.footerStyle);
+ }
+
+ // Hide if hidden
+ if (columnDef.isHidden !== undefined && columnDef.isHidden) {
+ newCell.hide();
+ }
+
+ // Trigger any events
+ if (typeof columnDef.afterFooterCellAdd == 'function') {
+ columnDef.afterFooterCellAdd(columnDef.value, newCell);
+ }
+
+ // Add to the column
+ newRow.append(newCell);
+ });
+
+ // Add the new row
+ let lastRow = element.find('tfoot tr:last');
+ if (lastRow.length > 0) lastRow.after(newRow);
+ else element.find('tfoot').append(newRow);
+
+ refresh();
+ },
+
// Add a new row with JSON
- addRow: function (row) {
+ addRow: function(row) {
let newRow = $(` `);
if (row !== undefined && row !== null) {
@@ -271,41 +352,40 @@ $.fn.editableTable = function (options) {
def: columnDef
});
}
- })
+ });
+
columnsToAdd.sort((a, b) => a.order - b.order).forEach((colToAdd, index) => {
let newCell;
if (colToAdd.value !== null)
newCell = $(`${colToAdd.value} `);
else
newCell = $(` `);
-
- // Apply any classes
+
+ // Apply any classes
if (colToAdd.def.classes !== undefined && colToAdd.def.classes.length) {
colToAdd.def.classes.forEach(classToAdd => newCell.addClass(classToAdd));
}
- // Apply any style
+ // Apply any style
if (colToAdd.def.style !== undefined && colToAdd.def.style.length) {
newCell.attr("style", newCell.attr("style") + "; " + colToAdd.def.style);
}
-
+
// Hide if hidden
if (colToAdd.def.isHidden !== undefined && colToAdd.def.isHidden) {
newCell.hide();
- }
-
- // Add to the column
- newRow.append(newCell);
+ }
// Trigger any events
let columnDef = options.columns.filter(col => col.name === colToAdd.prop)[0];
if (typeof columnDef.afterAdd == 'function') {
columnDef.afterAdd(colToAdd.value, newCell);
}
- });
- }
- else {
+ // Add to the column
+ newRow.append(newCell);
+ });
+ } else {
newRow = $(` `);
activeOptions.columns.forEach(x => {
newRow.append(` `);
@@ -314,29 +394,33 @@ $.fn.editableTable = function (options) {
// Add the new row
let lastRow = element.find('tbody tr:last');
- if (lastRow.length > 0)
- lastRow.after(newRow);
- else
- element.find('tbody').append(newRow);
+ if (lastRow.length > 0) lastRow.after(newRow);
+ else element.find('tbody').append(newRow);
refresh();
},
// Clear the table
- clear: function () {
+ clear: function() {
element.find('tbody tr').remove();
},
// Set the table's data with JSON
- setData: function (data) {
+ setData: function(data, afterLoad) {
+ this.addHeaders();
if (data) {
this.clear();
- data.forEach(datum => {
- this.addRow(datum);
+ data.forEach(entry => {
+ this.addRow(entry);
});
}
+ this.addFooters();
+
+ setTimeout(function() {
+ if (typeof afterLoad == 'function') afterLoad();
+ });
}
};
return _instance;
-};
+};
\ No newline at end of file
diff --git a/jquery-editable-table.min.js b/jquery-editable-table.min.js
index f72c806..87ca5c4 100644
--- a/jquery-editable-table.min.js
+++ b/jquery-editable-table.min.js
@@ -1 +1 @@
-$.fn.editableTable=function(t){let e;t=$.extend({},{cloneProperties:["padding","padding-top","padding-bottom","padding-left","padding-right","text-align","font","font-size","font-family","font-weight","border","border-top","border-bottom","border-left","border-right","color","background-color","border-radius"],columns:[]},t);let n,i="error",o=37,r=38,d=39,l=40,a=$(this);a.find("th").show(),t.columns.forEach((t,e)=>{void 0!==t.isHidden&&t.isHidden&&a.find("th").eq(e).hide()});let s,f=a.parent().find("input[table-editor-input]");function c(e){(s=a.find("td:focus")).length&&(n.val(s.text()).removeClass(i).show().offset(s.offset()).css(s.css(t.cloneProperties)).width(s.width()).height(s.height()).focus(),e&&n.select())}function h(){let t,e=n.val(),o=$.Event("change");if(s.text()===e||n.hasClass(i))return!0;t=s.html(),s.text(e).trigger(o,e),!1===o.result&&s.html(t)}function u(t,e){return e===d?t.next("td"):e===o?t.prev("td"):e===r?t.parent().prev().children().eq(t.index()):e===l?t.parent().next().children().eq(t.index()):[]}return(n=f.length?f.first():$(" ")).attr("table-editor-input","").css("position","absolute").hide().appendTo(a.parent()),n.blur(function(){h(),n.hide()}),n.keydown(function(t){if(13===t.which)h(),n.hide(),s.focus(),t.preventDefault(),t.stopPropagation();else if(27===t.which)n.val(s.text()),t.preventDefault(),t.stopPropagation(),n.hide(),s.focus();else if(9===t.which)s.focus();else if(this.selectionEnd-this.selectionStart===this.value.length){let e=u(s,t.which);e.length>0&&(e.focus(),t.preventDefault(),t.stopPropagation())}}),n.on("input paste",function(){let t=$.Event("validate");s.trigger(t,n.val()),void 0!==t.result&&(!1===t.result?n.addClass(i):n.removeClass(i))}),a.on("click keypress dblclick",c).css("cursor","pointer").keydown(function(t){let e=!0,n=u($(t.target),t.which);n.length>0?n.focus():13===t.which?c(!1):17===t.which||91===t.which||93===t.which?(c(!0),e=!1):e=!1,e&&(t.stopPropagation(),t.preventDefault())}),a.find("td").prop("tabindex",1),$(window).on("resize",function(){n.is(":visible")&&n.offset(s.offset()).width(s.width()).height(s.height())}),$("table td").on("validate",function(n,i){let o=$(n.currentTarget).index(),r=t.columns[o],d=e.getData({convert:!1});return r.isValid&&r.isValid(i,d)}),$("table td").on("change",function(e,n){let i=$(this),o=$(e.currentTarget).index(),r=t.columns[o];return r.removeRowIfCleared&&""==n&&i.parent("tr").remove(),"function"==typeof r.afterChange&&r.afterChange(n,i),!0}),e={getData:function(e){e=$.extend({},{convert:!0},e);let n=[];return a.find("tbody tr").toArray().forEach(i=>{let o={};$(i).find("td").toArray().forEach(n=>{let i=t.columns[$(n).index()],r=$(n).text(),d=$(n).attr("data-is-null");void 0!==d&&!1!==d&&(r=null),e.convert&&"function"==typeof i.convertOut&&(r=i.convertOut(r)),o[i.name]=r}),n.push(o)}),n},addRow:function(e){let n=$(" ");if(null!=e){let i=Object.keys(e),o=[];i.forEach(n=>{let i=t.columns.filter(t=>t.name===n);i.length&&(i=i[0],o.push({order:i.index,value:e[n],prop:n,def:i}))}),o.sort((t,e)=>t.order-e.order).forEach((e,i)=>{let o;o=null!==e.value?$(`${e.value} `):$(" "),void 0!==e.def.classes&&e.def.classes.length&&e.def.classes.forEach(t=>o.addClass(t)),void 0!==e.def.style&&e.def.style.length&&o.attr("style",o.attr("style")+"; "+e.def.style),void 0!==e.def.isHidden&&e.def.isHidden&&o.hide(),n.append(o);let r=t.columns.filter(t=>t.name===e.prop)[0];"function"==typeof r.afterAdd&&r.afterAdd(e.value,o)})}else n=$(" "),activeOptions.columns.forEach(t=>{n.append(" ")});let i=a.find("tbody tr:last");i.length>0?i.after(n):a.find("tbody").append(n),$(a).editableTable(t)},clear:function(){a.find("tbody tr").remove()},setData:function(t){t&&(this.clear(),t.forEach(t=>{this.addRow(t)}))}}};
+$.fn.editableTable=function(t){let e;t=$.extend({},{cloneProperties:["padding","padding-top","padding-bottom","padding-left","padding-right","text-align","font","font-size","font-family","font-weight","border","border-top","border-bottom","border-left","border-right","color","background-color","border-radius"],columns:[]},t);let n,i="error",o=37,r=38,d=39,l=40,a=$(this);a.find("th").show(),t.columns.forEach((t,e)=>{void 0!==t.isHidden&&t.isHidden&&a.find("th").eq(e).hide()});let s,f=a.parent().find("input[table-editor-input]");function c(e){(s=a.find("td:focus")).length&&(n.val(s.text()).removeClass(i).show().offset(s.offset()).css(s.css(t.cloneProperties)).width(s.width()).height(s.height()).focus(),e&&n.select())}function h(){let t,e=n.val(),o=$.Event("change");if(s.text()===e||n.hasClass(i))return!0;t=s.html(),s.text(e).trigger(o,e),!1===o.result&&s.html(t)}function u(t,e){return e===d?t.next("td"):e===o?t.prev("td"):e===r?t.parent().prev().children().eq(t.index()):e===l?t.parent().next().children().eq(t.index()):[]}return(n=f.length?f.first():$(" ")).attr("table-editor-input","").css("position","absolute").hide().appendTo(a.parent()),n.blur(function(){h(),n.hide()}),n.keydown(function(t){if(13===t.which)h(),n.hide(),t.preventDefault(),t.stopPropagation();else if(27===t.which)t.preventDefault(),t.stopPropagation(),n.hide();else if(9===t.which)s.focus();else if(this.selectionEnd-this.selectionStart===this.value.length){let e=u(s,t.which);e.length>0&&(e.focus(),t.preventDefault(),t.stopPropagation())}}),n.on("input paste",function(){let t=$.Event("validate");s.trigger(t,n.val()),void 0!==t.result&&(!1===t.result?n.addClass(i):n.removeClass(i))}),a.on("click keypress dblclick",c).css("cursor","pointer").keydown(function(t){let e=!0,n=u($(t.target),t.which);n.length>0?n.focus():13===t.which?c(!1):17===t.which||91===t.which||93===t.which?(c(!0),e=!1):e=!1,e&&(t.stopPropagation(),t.preventDefault())}),a.find("td").not(".no-editor").prop("tabindex",1),$(window).on("resize",function(){n.is(":visible")&&n.offset(s.offset()).width(s.width()).height(s.height())}),$("table td").on("validate",function(n,i){let o=$(n.currentTarget).index(),r=t.columns[o],d=e.getData({convert:!1});return r.isValid&&r.isValid(i,d)}),$("table td").on("change",function(e,n){let i=$(this),o=$(e.currentTarget).index(),r=t.columns[o];if(r.removeRowIfCleared&&""==n&&i.parent("tr").remove(),"function"==typeof r.afterChange){let t=r.afterChange(n,i);t&&i.text(t)}return!0}),e={getData:function(e){e=$.extend({},{convert:!0},e);let n=[];return a.find("tbody tr").toArray().forEach(i=>{let o={};$(i).find("td").toArray().forEach(n=>{let i=t.columns[$(n).index()],r=$(n).text(),d=$(n).attr("data-is-null");void 0!==d&&!1!==d&&(r=null),e.convert&&"function"==typeof i.convertOut&&(r=i.convertOut(r)),o[i.name]=r}),n.push(o)}),n},addRow:function(e){let n=$(" ");if(null!=e){let i=Object.keys(e),o=[];i.forEach(n=>{let i=t.columns.filter(t=>t.name===n);i.length&&(i=i[0],o.push({order:i.index,value:e[n],prop:n,def:i}))}),o.sort((t,e)=>t.order-e.order).forEach((e,i)=>{let o;o=null!==e.value?$(`${e.value} `):$(" "),void 0!==e.def.classes&&e.def.classes.length&&e.def.classes.forEach(t=>o.addClass(t)),void 0!==e.def.style&&e.def.style.length&&o.attr("style",o.attr("style")+"; "+e.def.style),void 0!==e.def.isHidden&&e.def.isHidden&&o.hide();let r=t.columns.filter(t=>t.name===e.prop)[0];"function"==typeof r.afterAdd&&r.afterAdd(e.value,o),n.append(o)})}else n=$(" "),activeOptions.columns.forEach(t=>{n.append(" ")});let i=a.find("tbody tr:last");i.length>0?i.after(n):a.find("tbody").append(n),$(a).editableTable(t)},clear:function(){a.find("tbody tr").remove()},setData:function(t,e){t&&(this.clear(),t.forEach(t=>{this.addRow(t)}),"function"==typeof e&&e())}}};
\ No newline at end of file