From 45cb86ed57286be0dc21fb808dd94a127b33c8f7 Mon Sep 17 00:00:00 2001 From: Mottie Date: Sun, 26 Apr 2015 09:35:06 -0500 Subject: [PATCH] Editable: Fix selectAll & change tbody mouseleave to thead mouseenter. Fixes #848 --- dist/js/widgets/widget-editable.min.js | 2 +- docs/example-widget-editable.html | 8 ++++++ js/widgets/widget-editable.js | 34 +++++++++++++++++--------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/dist/js/widgets/widget-editable.min.js b/dist/js/widgets/widget-editable.min.js index ec189775..10af726d 100644 --- a/dist/js/widgets/widget-editable.min.js +++ b/dist/js/widgets/widget-editable.min.js @@ -1,2 +1,2 @@ /*! Widget: editable - updated 2/9/2015 (v2.19.1) */ -!function(a){"use strict";var b=a.tablesorter.editable={editComplete:function(a,b,c,d){c.removeClass("tseditable-last-edited-cell").trigger(b.editable_editComplete,[a]),d&&setTimeout(function(){c.focus()},50)},selectAll:function(a){setTimeout(function(){var b,c=document.createRange();c.selectNodeContents(a),b=window.getSelection(),b.removeAllRanges(),b.addRange(c)},100)},update:function(b,c){var d,e,f,g=[],h=[];if(!c.editable_columnsArray&&"string"===a.type(c.editable_columns)&&c.editable_columns.indexOf("-")>=0)for(e=c.editable_columns.split(/\s*-\s*/),d=parseInt(e[0],10)||0,e=parseInt(e[1],10)||b.columns-1,e>b.columns&&(e=b.columns-1);e>=d;d++)g.push(d),h.push("td:nth-child("+(d+1)+")");else a.isArray(c.editable_columns)&&a.each(c.editable_columnsArray||c.editable_columns,function(a,c){c").wrapInner(c.editable_wrapContent).children().length||a.isFunction(c.editable_wrapContent),b.$tbodies.find(h.join(",")).not("."+c.editable_noEdit).each(function(){f=a(this),e&&0===f.children().length&&f.wrapInner(c.editable_wrapContent),f.children().length?f.children().not("."+c.editable_noEdit).each(function(){var b=a(this);c.editable_trimContent&&b.html(function(b,c){return a.trim(c)}),b.prop("contenteditable",!0)}):(c.editable_trimContent&&f.html(function(b,c){return a.trim(c)}),f.prop("contenteditable",!0))})},bindEvents:function(c,d){c.$table.off("updateComplete pagerComplete ".split(" ").join(".tseditable ").replace(/\s+/g," ")).on("updateComplete pagerComplete ".split(" ").join(".tseditable "),function(){b.update(c,c.widgetOptions)}),c.$tbodies.off("mouseleave focus blur focusout keydown ".split(" ").join(".tseditable ").replace(/\s+/g," ")).on("mouseleave.tseditable",function(){c.$table.data("contentFocused")&&(c.$table.data("contentFocused",!0),a(":focus").trigger("focusout"))}).on("focus.tseditable","[contenteditable]",function(e){clearTimeout(a(this).data("timer")),c.$table.data("contentFocused",e.target);var f=a(this),g=d.editable_selectAll,h=f.closest("td").index(),i=f.html();d.editable_trimContent&&(i=a.trim(i)),f.off("keydown.tseditable").on("keydown.tseditable",function(a){d.editable_enterToAccept&&13===a.which&&a.preventDefault()}),f.data({before:i,original:i}),"function"==typeof d.editable_focused&&d.editable_focused(i,h,f),g&&("function"==typeof g?g(i,h,f)&&b.selectAll(f[0]):b.selectAll(f[0]))}).on("blur focusout keydown ".split(" ").join(".tseditable "),"[contenteditable]",function(e){if(c.$table.data("contentFocused")){var f,g,h=!1,i=a(e.target),j=i.html(),k=i.closest("td").index();if(d.editable_trimContent&&(j=a.trim(j)),27===e.which)return i.html(i.data("original")).trigger("blur.tseditable"),c.$table.data("contentFocused",!1),!1;if(f=13===e.which&&(d.editable_enterToAccept||e.altKey)||d.editable_autoAccept&&"keydown"!==e.type,f&&i.data("before")!==j){if(g=d.editable_validate,h=j,"function"==typeof g?h=g(j,i.data("original"),k,i):"function"==typeof(g=a.tablesorter.getColumnData(c.table,g,k))&&(h=g(j,i.data("original"),k,i)),f&&h!==!1)return c.$table.find(".tseditable-last-edited-cell").removeClass("tseditable-last-edited-cell"),i.addClass("tseditable-last-edited-cell").html(h).data("before",h).data("original",h).trigger("change"),c.$table.trigger("updateCell",[i.closest("td"),!1,function(){d.editable_autoResort?setTimeout(function(){c.$table.trigger("sorton",[c.sortList,function(){b.editComplete(c,d,c.$table.find(".tseditable-last-edited-cell"),!0)},!0])},10):b.editComplete(c,d,c.$table.find(".tseditable-last-edited-cell"))}]),!1}else h||"keydown"===e.type||(clearTimeout(i.data("timer")),i.data("timer",setTimeout(function(){a.isFunction(d.editable_blur)&&(j=i.html(),d.editable_blur(d.editable_trimContent?a.trim(j):j,k,i))},100)),i.html(i.data("original")))}})}};a.tablesorter.addWidget({id:"editable",options:{editable_columns:[],editable_enterToAccept:!0,editable_autoAccept:!0,editable_autoResort:!1,editable_wrapContent:"
",editable_trimContent:!0,editable_validate:null,editable_focused:null,editable_blur:null,editable_selectAll:!1,editable_noEdit:"no-edit",editable_editComplete:"editComplete"},init:function(a,c,d,e){e.editable_columns.length&&(b.update(d,e),b.bindEvents(d,e))}})}(jQuery); \ No newline at end of file +!function(a){"use strict";var b=a.tablesorter.editable={editComplete:function(a,b,c,d){c.removeClass("tseditable-last-edited-cell").trigger(b.editable_editComplete,[a]),d&&setTimeout(function(){c.focus()},50)},selectAll:function(a){setTimeout(function(){var b,c;document.body.createTextRange?(b=document.body.createTextRange(),b.moveToElementText(a),b.select()):window.getSelection&&(c=window.getSelection(),b=document.createRange(),b.selectNodeContents(a),c.removeAllRanges(),c.addRange(b))},100)},update:function(b,c){var d,e,f,g=[],h=[];if(!c.editable_columnsArray&&"string"===a.type(c.editable_columns)&&c.editable_columns.indexOf("-")>=0)for(e=c.editable_columns.split(/\s*-\s*/),d=parseInt(e[0],10)||0,e=parseInt(e[1],10)||b.columns-1,e>b.columns&&(e=b.columns-1);e>=d;d++)g.push(d),h.push("td:nth-child("+(d+1)+")");else a.isArray(c.editable_columns)&&a.each(c.editable_columnsArray||c.editable_columns,function(a,c){c").wrapInner(c.editable_wrapContent).children().length||a.isFunction(c.editable_wrapContent),b.$tbodies.find(h.join(",")).not("."+c.editable_noEdit).each(function(){f=a(this),e&&0===f.children().length&&f.wrapInner(c.editable_wrapContent),f.children().length?f.children().not("."+c.editable_noEdit).each(function(){var b=a(this);c.editable_trimContent&&b.html(function(b,c){return a.trim(c)}),b.prop("contenteditable",!0)}):(c.editable_trimContent&&f.html(function(b,c){return a.trim(c)}),f.prop("contenteditable",!0))})},bindEvents:function(c,d){c.$table.off("updateComplete pagerComplete ".split(" ").join(".tseditable ").replace(/\s+/g," ")).on("updateComplete pagerComplete ".split(" ").join(".tseditable "),function(){b.update(c,c.widgetOptions)}).children("thead").add(a(c.namespace+"_extra_table").children("thead")).off("mouseenter.tseditable").on("mouseenter.tseditable",function(){c.$table.data("contentFocused")&&(c.$table.data("contentFocused",!0),a(":focus").trigger("focusout"))}),c.$tbodies.off("focus blur focusout keydown ".split(" ").join(".tseditable ").replace(/\s+/g," ")).on("focus.tseditable","[contenteditable]",function(e){clearTimeout(a(this).data("timer")),c.$table.data("contentFocused",e.target);var f=a(this),g=d.editable_selectAll,h=f.closest("td").index(),i=f.html();d.editable_trimContent&&(i=a.trim(i)),f.off("keydown.tseditable").on("keydown.tseditable",function(a){d.editable_enterToAccept&&13===a.which&&a.preventDefault()}),f.data({before:i,original:i}),"function"==typeof d.editable_focused&&d.editable_focused(i,h,f),g&&("function"==typeof g?g(i,h,f)&&b.selectAll(f[0]):b.selectAll(f[0]))}).on("blur focusout keydown ".split(" ").join(".tseditable "),"[contenteditable]",function(e){if(c.$table.data("contentFocused")){var f,g,h=!1,i=a(e.target),j=i.html(),k=i.closest("td").index();if(d.editable_trimContent&&(j=a.trim(j)),27===e.which)return i.html(i.data("original")).trigger("blur.tseditable"),c.$table.data("contentFocused",!1),!1;if(f=13===e.which&&(d.editable_enterToAccept||e.altKey)||d.editable_autoAccept&&"keydown"!==e.type,f&&i.data("before")!==j){if(g=d.editable_validate,h=j,"function"==typeof g?h=g(j,i.data("original"),k,i):"function"==typeof(g=a.tablesorter.getColumnData(c.table,g,k))&&(h=g(j,i.data("original"),k,i)),f&&h!==!1)return c.$table.find(".tseditable-last-edited-cell").removeClass("tseditable-last-edited-cell"),i.addClass("tseditable-last-edited-cell").html(h).data("before",h).data("original",h).trigger("change"),c.$table.trigger("updateCell",[i.closest("td"),!1,function(){d.editable_autoResort?setTimeout(function(){c.$table.trigger("sorton",[c.sortList,function(){b.editComplete(c,d,c.$table.find(".tseditable-last-edited-cell"),!0)},!0])},10):b.editComplete(c,d,c.$table.find(".tseditable-last-edited-cell"))}]),!1}else h||"keydown"===e.type||(clearTimeout(i.data("timer")),i.data("timer",setTimeout(function(){a.isFunction(d.editable_blur)&&(j=i.html(),d.editable_blur(d.editable_trimContent?a.trim(j):j,k,i))},100)),i.html(i.data("original")))}})}};a.tablesorter.addWidget({id:"editable",options:{editable_columns:[],editable_enterToAccept:!0,editable_autoAccept:!0,editable_autoResort:!1,editable_wrapContent:"
",editable_trimContent:!0,editable_validate:null,editable_focused:null,editable_blur:null,editable_selectAll:!1,editable_noEdit:"no-edit",editable_editComplete:"editComplete"},init:function(a,c,d,e){e.editable_columns.length&&(b.update(d,e),b.bindEvents(d,e))}})}(jQuery); \ No newline at end of file diff --git a/docs/example-widget-editable.html b/docs/example-widget-editable.html index 3a1ffc10..c9e1e706 100644 --- a/docs/example-widget-editable.html +++ b/docs/example-widget-editable.html @@ -113,6 +113,14 @@ td.no-edit, span.no-edit {
  • This widget can not be applied to the original plugin and requires jQuery 1.7+ and a browser that supports contenteditable attributes (almost all modern browsers).
  • Important: In Internet Explorer, please wrap the cell content with a DIV or SPAN as it is not possible to make table cells directly contenteditable. Wrapping the content in the markup is much more efficient than using javascript to do it for you (especially in IE).

  • +
  • In v2.21.6, +
      +
    • The cell content now only automatically updates when the user hovers over the table header. Prior to this version, the automatic update would occur when the mouse left the tbody of the table. The reason this is necessary is because initiating a sort would change the row indexing set prior to the cell content being updated, so the cache would end up not matching the table content.
    • +
    • Modified the editable_trimContent option to only trim content when set.
    • +
    • The widget now works with the contenteditable html (using jQuery's .html()); previously, the widget would only manipulate the text (using jQuery .text()), so any HTML would get stripped out.
      + *Note* Because of this change, if the user presses Enter, a <div> will be automatically inserted by the browser (not the widget) and any content entered will be added inside this "new line" div. If this is undesirable, use the editable_blur callback to modify the content.
    • +
    +
  • Updated v2.17.6,
    • Fixed the editable_enterToAccept option to do what it was meant to do, accept when the user presses enter.
    • diff --git a/js/widgets/widget-editable.js b/js/widgets/widget-editable.js index a1808ff4..bfff9114 100644 --- a/js/widgets/widget-editable.js +++ b/js/widgets/widget-editable.js @@ -25,11 +25,18 @@ var tse = $.tablesorter.editable = { setTimeout( function() { // select all text in contenteditable // see http://stackoverflow.com/a/6150060/145346 - var sel, range = document.createRange(); - range.selectNodeContents( cell ); - sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange( range ); + var range, selection; + if ( document.body.createTextRange ) { + range = document.body.createTextRange(); + range.moveToElementText( cell ); + range.select(); + } else if ( window.getSelection ) { + selection = window.getSelection(); + range = document.createRange(); + range.selectNodeContents( cell ); + selection.removeAllRanges(); + selection.addRange( range ); + } }, 100 ); }, @@ -98,17 +105,22 @@ var tse = $.tablesorter.editable = { .off( ( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable ' ) ).replace( /\s+/g, ' ' ) ) .on( 'updateComplete pagerComplete '.split( ' ' ).join( '.tseditable ' ), function() { tse.update( c, c.widgetOptions ); - }); - - c.$tbodies - .off( ( 'mouseleave focus blur focusout keydown '.split( ' ' ).join( '.tseditable ' ) ).replace( /\s+/g, ' ' ) ) - .on( 'mouseleave.tseditable', function() { + }) + // prevent sort initialized by user click on the header from changing the row indexing before + // updateCell can finish processing the change + .children( 'thead' ) + .add( $( c.namespace + '_extra_table' ).children( 'thead' ) ) + .off( 'mouseenter.tseditable' ) + .on( 'mouseenter.tseditable', function() { if ( c.$table.data( 'contentFocused' ) ) { // change to 'true' instead of element to allow focusout to process c.$table.data( 'contentFocused', true ); $( ':focus' ).trigger( 'focusout' ); } - }) + }); + + c.$tbodies + .off( ( 'focus blur focusout keydown '.split( ' ' ).join( '.tseditable ' ) ).replace( /\s+/g, ' ' ) ) .on( 'focus.tseditable', '[contenteditable]', function( e ) { clearTimeout( $( this ).data( 'timer' ) ); c.$table.data( 'contentFocused', e.target );