From 1a55589d07dd3a27c9b785702f28a0c7c3ca0d29 Mon Sep 17 00:00:00 2001 From: AP Date: Fri, 27 Aug 2021 21:05:02 +0200 Subject: [PATCH 1/2] fix #3, #4 and #5 --- jquery-editable-table.js | 102 +++++++++++++++++------------------ jquery-editable-table.min.js | 2 +- 2 files changed, 51 insertions(+), 53 deletions(-) diff --git a/jquery-editable-table.js b/jquery-editable-table.js index dc1c245..bf78045 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) { @@ -156,7 +153,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 +172,9 @@ $.fn.editableTable = function (options) { } }); - element.find('td').prop('tabindex', 1); + element.find('td').not('.no-editor').prop('tabindex', 1); - $(window).on('resize', function () { + $(window).on('resize', function() { if (editor.is(':visible')) { editor.offset(activeCell.offset()) .width(activeCell.width()) @@ -190,15 +187,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 +208,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 +218,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); @@ -253,7 +253,7 @@ $.fn.editableTable = function (options) { }, // Add a new row with JSON - addRow: function (row) { + addRow: function(row) { let newRow = $(``); if (row !== undefined && row !== null) { @@ -271,41 +271,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 +313,28 @@ $.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) { if (data) { this.clear(); - data.forEach(datum => { - this.addRow(datum); + data.forEach(entry => { + this.addRow(entry); }); + 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 From d9d6ab649d50b4c2afde230a5b357b0b5dd0d8cc Mon Sep 17 00:00:00 2001 From: AP Date: Fri, 10 Sep 2021 15:04:54 +0200 Subject: [PATCH 2/2] fix #8 --- jquery-editable-table.js | 92 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/jquery-editable-table.js b/jquery-editable-table.js index bf78045..ae44d24 100644 --- a/jquery-editable-table.js +++ b/jquery-editable-table.js @@ -152,7 +152,6 @@ $.fn.editableTable = function(options) { // On table clicking, move around cells element.on('click keypress dblclick', showEditor) - .css('cursor', 'pointer') .keydown(function(e) { let prevent = true, possibleMove = handleMovement($(e.target), e.which); @@ -172,7 +171,11 @@ $.fn.editableTable = function(options) { } }); - element.find('td').not('.no-editor').prop('tabindex', 1); + element + .find('td') + .not('.no-editor') + .prop('tabindex', 1) + .css('cursor', 'pointer'); $(window).on('resize', function() { if (editor.is(':visible')) { @@ -252,6 +255,84 @@ $.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) { let newRow = $(``); @@ -326,13 +407,18 @@ $.fn.editableTable = function(options) { // Set the table's data with JSON setData: function(data, afterLoad) { + this.addHeaders(); if (data) { this.clear(); data.forEach(entry => { this.addRow(entry); }); - if (typeof afterLoad == 'function') afterLoad(); } + this.addFooters(); + + setTimeout(function() { + if (typeof afterLoad == 'function') afterLoad(); + }); } };