Added content editable widget

This commit is contained in:
Mottie 2013-04-12 20:39:07 -05:00
parent f1f82b31db
commit cf46109b6c
3 changed files with 247 additions and 19 deletions

View File

@ -0,0 +1,159 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>jQuery plugin: Tablesorter 2.0 - Content Editable</title>
<!-- jQuery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
<!-- Demo stuff -->
<link rel="stylesheet" href="css/jq.css">
<link href="css/prettify.css" rel="stylesheet">
<script src="js/prettify.js"></script>
<script src="js/docs.js"></script>
<!-- Tablesorter: required -->
<link rel="stylesheet" href="../css/theme.blue.css">
<script src="../js/jquery.tablesorter.js"></script>
<script src="../js/widgets/widget-editable.js"></script>
<style id="css">.tablesorter tbody > tr > td[contenteditable=true]:focus {
outline: #08f 1px solid;
background: #eee;
resize: none;
}
td.no-edit, span.no-edit {
background-color: rgba(230,191,153,0.5);
}</style>
<script id="js">$(function() {
// call the tablesorter plugin
$("table").tablesorter({
theme : 'blue',
widgets: ['editable'],
widgetOptions: {
editable_columns : [0,1,2], // point to the columns to make editable (zero-based index)
editable_enterToAccept : true, // press enter to accept content, or click outside if false
editable_autoResort : false, // auto resort after the content has changed.
editable_noEdit : 'no-edit' // class name of cell that is no editable
}
});
});</script>
</head>
<body>
<div id="banner">
<h1>table<em>sorter</em></h1>
<h2>Content Editable</h2>
<h3>Flexible client-side table sorting</h3>
<a href="index.html">Back to documentation</a>
</div>
<div id="main">
<p class="tip">
<em>NOTE!</em>
<ul>
<li>This widget can not be applied to the original plugin and requires jQuery 1.7+ and a browser that supports <a href="http://caniuse.com/#feat=contenteditable"><code>contenteditable</code> attributes</a> (almost all modern browsers).</li>
<li>Additional CSS is needed to highlight a focused editable table cell. See the CSS block below.</li>
<li>Editable widget options include (defaults in parenthesis):
<ul>
<li><code>editable_column</code> (<code>[]</code>) - Contains an array of columns numbers you want to have editable content (zero-based index). <code>contenteditable="true"</code> is added to cells within these columns.</li>
<li><code>editable_enterToAccept</code> (<code>true</code>) - Makes the user press enter to accept the content within the editable table cell; if <code>false</code>, clicking outside the cell will accept the content.</li>
<li><code>editable_autoResort</code> (<code>false</code>) - If <code>true</code> the column will resort (only if already sorted) after the content has been changed.</li>
<li><code>editable_noEdit</code> (<code>'no-edit'</code>) - Class name on table cells to search for that are not to become editable. The search is only done within the columns set by the <code>editable_column</code> option.</li>
</ul>
</li>
<li>Pressing escape while editing will cancel any changes.</li>
<li>In the demo below, click in any of the first three columns to edit the content, except for the cell containing <span class="no-edit">"Peter"</span>.</li>
<li>To prevent a table cell from becoming editable, add the class name <code>"no-edit"</code> to the cell.</li>
<li>Edited content will be accepted in the following circumstances:
<ul>
<li>Pressing enter when the <code>editable_enterToAccept</code> option is <code>true</code>.</li>
<li>Clicking outside of the current editable content.</li>
<li>Moving the mouse outside of the current tbody. This is done because if the content editable is still active when the user clicks on the header to sort the column, all sorts of bad things happen.</li>
</ul>
</li>
<li>Edited content will not be accepted in the following circumstances:
<ul>
<li>Pressing Escape within the editable content.</li>
</ul>
</li>
</ul>
</p>
<h1>Demo</h1>
<div id="demo"><table class="tablesorter">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Age</th>
<th>Total</th>
<th>Discount</th>
<th>Date</th>
</tr>
</thead>
<tbody>
<tr>
<td class="no-edit">Peter</td>
<td>Parker</td>
<td>28</td>
<td>$9.99</td>
<td>20%</td>
<td>Jul 6, 2006 8:14 AM</td>
</tr>
<tr>
<td>John</td>
<td>Hood</td>
<td>33</td>
<td>$19.99</td>
<td>25%</td>
<td>Dec 10, 2002 5:14 AM</td>
</tr>
<tr>
<td>Clark</td>
<td>Kent</td>
<td>18</td>
<td>$15.89</td>
<td>44%</td>
<td>Jan 12, 2003 11:14 AM</td>
</tr>
<tr>
<td>Bruce</td>
<td>Almighty</td>
<td>45</td>
<td>$153.19</td>
<td>44%</td>
<td>Jan 18, 2001 9:12 AM</td>
</tr>
<tr>
<td>Bruce</td>
<td>Evans</td>
<td>22</td>
<td>$13.19</td>
<td>11%</td>
<td>Jan 18, 2007 9:12 AM</td>
</tr>
</tbody>
</table></div>
<h1>Javascript</h1>
<div id="javascript">
<pre class="prettyprint lang-javascript"></pre>
</div>
<h1>CSS</h1>
<div id="css">
<pre class="prettyprint lang-css"></pre>
</div>
<h1>HTML</h1>
<div id="html">
<pre class="prettyprint lang-html"></pre>
</div>
</div>
</body>
</html>

View File

@ -294,6 +294,7 @@
<li><a href="example-pager.html">Pager plugin</a></li>
<br>
<li><a href="example-widget-columns.html">Columns widget</a> (v2.0.17)</li>
<li><a href="example-widget-editable.html">Content Editable widget</a> <span class="tip"><em>New</em></span> v2.9.</li>
<li>Filter Widget:
<ul>
<li><a href="example-widget-filter.html">basic</a> (v2.0.18)</li>
@ -301,8 +302,9 @@
<li>formatter (<a href="example-widget-filter-formatter-1.html">jQuery UI widgets</a> and <a href="">HTML5 Elements</a>) (v2.7.7).</li>
</ul>
</li>
<li><a href="example-widget-grouping.html">Grouping rows Widget</a> <span class="tip"><em>New</em></span> v2.8.</li>
<li><a href="example-widget-resizable.html">Resizable Columns widget</a> (v2.0.23.1; <span class="tip"><em>Updated</em></span> v2.8.3)</li>
<li><a href="example-widget-grouping.html">Grouping rows Widget</a> <span class="tip old"><em>New</em></span> v2.8.</li>
<li><a href="example-widgets.html">Repeat Headers widget</a> (v2.0.5; <span class="tip"><em>Updated</em></span> v2.9)</li>
<li><a href="example-widget-resizable.html">Resizable Columns widget</a> (v2.0.23.1; <span class="tip old"><em>Updated</em></span> v2.8.3)</li>
<li><a href="example-widget-savesort.html">Save sort widget</a> (v2.0.27)</li>
<li><a href="example-widget-scroller.html">Scroller widget</a> <span class="tip"><em>New</em></span> v2.9.</li>
<li><a href="example-widget-sticky-header.html">Sticky header widget</a> (v2.0.21.1)</li>
@ -314,11 +316,11 @@
</li>
<li><a href="example-widget-zebra.html">Zebra stripe widget</a></li>
<br>
<li><a href="example-parsers-dates.html">Assorted date parsers</a> <span class="tip"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-ignore-articles.html">Ignore leading articles parser</a> (Ignore "A", "An" and "The" in titles) <span class="tip"><em>New</em></span> v2.8.</li>
<li><a href="example-widget-grouping.html">Input/select parsers</a> (used by Grouping rows widget) <span class="tip"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-metric.html">Metric parser</a> <span class="tip"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-feet-inch-fraction.html">Feet-inch-fraction parser</a> <span class="tip"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-dates.html">Assorted date parsers</a> <span class="tip old"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-ignore-articles.html">Ignore leading articles parser</a> (Ignore "A", "An" and "The" in titles) <span class="tip old"><em>New</em></span> v2.8.</li>
<li><a href="example-widget-grouping.html">Input/select parsers</a> (used by Grouping rows widget) <span class="tip old"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-metric.html">Metric parser</a> <span class="tip old"><em>New</em></span> v2.8.</li>
<li><a href="example-parsers-feet-inch-fraction.html">Feet-inch-fraction parser</a> <span class="tip old"><em>New</em></span> v2.8.</li>
</ul>
</div>
@ -346,7 +348,7 @@
<li><a href="example-empty-table.html">Initializing tablesorter on a empty table</a></li>
<li><a href="example-ajax.html">Appending table data with ajax</a></li>
<li><a href="example-add-rows.html">Adding a table row</a> (v2.0.16)</li>
<li><a href="example-update-all.html">Update an entire table column (<code>thead</code> and <code>tbody</code>)</a> <span class="tip"><em>New!</em></span> v2.8</li>
<li><a href="example-update-all.html">Update an entire table column (<code>thead</code> and <code>tbody</code>)</a> <span class="tip old"><em>New!</em></span> v2.8</li>
<li><a href="example-update-cell.html">Update the table after cell content has changed</a></li>
<li><a href="example-pager.html">Pager plugin</a> - examples of how to add and remove rows</li>
</ul>
@ -2018,7 +2020,7 @@ $('table').trigger('search', false);</pre></div>
<td>Boolean</td>
<td>false</td>
<td>
Resizable widget: If this option is set to <code>true</code>, a resizing anchor will be included in the last column of the table <span class="tip"><em>New!</em></span> v2.8.3.
Resizable widget: If this option is set to <code>true</code>, a resizing anchor will be included in the last column of the table <span class="tip old"><em>New!</em></span> v2.8.3.
<div class="collapsible">
<br>
If an anchor was included and the table is full width, the column would resize in the opposite direction which my not be intuitive to the user. So set this option as desired, but please be mindful of the user experience.<br>
@ -2218,18 +2220,18 @@ $.extend($.tablesorter.themes.jui, {
</thead>
<tbody>
<tr><td><code>{page}</code></td><td>Zero-based index of the current pager page</td></tr>
<tr><td><code>{page+1}</code></td><td>One-based index of the current pager page (replace "+1" with any number) (e.g. <code>{page+3}</code>). <span class="tip"><em>New!</em></span> v2.9</td></tr>
<tr><td><code>{page+1}</code></td><td>One-based index of the current pager page (replace "+1" with any number) (e.g. <code>{page+3}</code>) <span class="tip"><em>New!</em></span> v2.9.</td></tr>
<tr><td><code>{size}</code></td><td>Number of rows showing, or number of rows to get from the server</td></tr>
<tr>
<td><code>{sortList:col}</code></td>
<td><code>{sortList:col}</code> or <code>{sort:col}</code></td>
<td>Adds the current sort to the ajax url string into a "col" array, so your server-side code knows how to sort the data (v2.4.5).<br>
The <code>col</code> portion of the <code>{sortList:col}</code> tag can be any name string (no spaces) to indicate the name of the variable to apply. So if your current sortList is <code>[[2,0],[3,0]]</code>, it becomes <code>"&sort[2]=0&sort[3]=0"</code> in the url.
The <code>col</code> portion of the <code>{sortList:col}</code> tag can be any name string (no spaces) to indicate the name of the variable to apply. So if your current sortList is <code>[[2,0],[3,0]]</code>, it becomes <code>"&sort[2]=0&sort[3]=0"</code> in the url. <code>{sort:col}</code> shortened tag also works <span class="tip"><em>Updated</em></span> v2.9.
</td>
</tr>
<tr>
<td><code>{filterList:fcol}</code></td>
<td><code>{filterList:fcol}</code> or <code>{filter:fcol}</code></td>
<td>Adds the value of the current filters to the ajax url string into a "fcol" array, so your server-side code knows how to filter the data (v2.6).<br>
The <code>fcol</code> portion of the <code>{filterList:fcol}</code> tag can be any name string (no spaces) to indicate the name of the variable to apply. So if your current filters are <code>['','Blue',13]</code>, it becomes <code>"&fcol[2]=Blue&fcol[3]=13"</code> in the url.
The <code>fcol</code> portion of the <code>{filterList:fcol}</code> tag can be any name string (no spaces) to indicate the name of the variable to apply. So if your current filters are <code>['','Blue',13]</code>, it becomes <code>"&fcol[2]=Blue&fcol[3]=13"</code> in the url. <code>{filter:col}</code> shortened tag also works <span class="tip"><em>Updated</em></span> v2.9.
</td>
</tr>
</tbody>
@ -2243,7 +2245,7 @@ $.extend($.tablesorter.themes.jui, {
<td>function</td>
<td>function(table, url) { return url; }</td>
<td>
This callback function allows you to modify the processed URL as desired. <span class="tip"><em>New!</em></span> v2.8.1.
This callback function allows you to modify the processed URL as desired. <span class="tip old"><em>New!</em></span> v2.8.1.
<div class="collapsible">
<br>
The <code>customAjaxUrl</code> function has two parameters, the table DOM element and the processed url string (all tags within the <code>ajaxUrl</code> have been replaced with their appropriate values).
@ -2292,7 +2294,7 @@ $.extend($.tablesorter.themes.jui, {
]</pre>Here is some example JSON (comments added, but not allowed in JSON) which is contained in the <a href="https://github.com/Mottie/tablesorter/blob/master/docs/assets/City0.json">City0.json</a> file:
<pre class="prettyprint lang-javascript">{
// total rows
"total_rows": "80",
"total_rows": 80,
// headers
"cols" : [
"ID", "Name", "Country Code", "District", "Population"
@ -2337,7 +2339,7 @@ $.extend($.tablesorter.themes.jui, {
}
rows.push(row); // add new row array to rows array
}
return [ total, rows, headers ];
return [ total, rows, headers ]; // or return [ rows, total, headers ] in v2.9+
}
}
});
@ -2528,7 +2530,7 @@ $.extend($.tablesorter.themes.jui, {
<td>This option contains the class name that is applied to disabled pager controls.
<div class="collapsible">
<br>
More explicitly, this class is applied to the pager arrows when they are at either extreme of pages. When the pager has been disabled, this class is applied to all controls.<br>
More explicitly, this class is applied to the pager arrows when they are at either extreme of pages and the <code>updateArrows</code> option is <code>true</code>. When the pager has been disabled, this class is applied to all controls.<br>
<br>
Note there is no period "." in front of this class name (it is not a selector).
</div></td>
@ -2661,7 +2663,7 @@ $("table").trigger("sorton", [sorting]);</pre></div>
<tr id="updateall">
<td><a href="#" class="toggle2">updateAll</a></td>
<td>Update a column of cells (<code>thead</code> and <code>tbody</code>) <span class="tip"><em>New!</em></span> v2.8.
<td>Update a column of cells (<code>thead</code> and <code>tbody</code>) <span class="tip old"><em>New!</em></span> v2.8.
<div class="collapsible">
<pre class="prettyprint lang-javascript">// Change thead & tbody column of cells
// remember, "eq()" is zero based & "nth-child()" is 1 based

View File

@ -0,0 +1,67 @@
/*! tablesorter Editable Content widget - updated 4/12/2013
* Requires tablesorter v2.8+ and jQuery 1.7+
* by Rob Garrison
*/
/*global jQuery: false */
;(function($){
"use strict";
$.tablesorter.addWidget({
id: 'editable',
options : {
editable_columns : [],
editable_enterToAccept : true,
editable_autoResort : false,
editable_noEdit : 'no-edit'
},
init: function(table, thisWidget, c, wo){
if (!wo.editable_columns.length) { return; }
var cols = [];
$.each(wo.editable_columns, function(i, col){
cols.push('td:nth-child(' + (col + 1) + ')');
});
c.$tbodies.find( cols.join(',') ).not('.' + wo.editable_noEdit).prop('contenteditable', true);
c.$tbodies
.on('mouseleave.tseditable', function(){
if (c.$table.data('contentFocused')) {
$(':focus').trigger('blur');
}
})
.on('focus.tseditable', '[contenteditable]', function(){
c.$table.data('contentFocused', true);
var $this = $(this), v = $this.html();
if (wo.editable_enterToAccept) {
// prevent enter from adding into the content
$this.on('keydown.tseditable', function(e){
if (e.which === 13) {
e.preventDefault();
}
});
}
$this.data({ before : v, original: v });
})
.on('blur focusout keyup '.split(' ').join('.tseditable '), '[contenteditable]', function(e){
if (!c.$table.data('contentFocused')) { return; }
var $this = $(e.target), t;
if (e.which === 27) {
// user cancelled
$this.html( $this.data('original') ).trigger('blur.tseditable');
c.$table.data('contentFocused', false);
return false;
}
t = e.type !== 'keyup' || (wo.editable_enterToAccept && e.which === 13);
// change if new or user hits enter (if option set)
if ($this.data('before') !== $this.html() || t) {
$this.data('before', $this.html()).trigger('change');
if (t) {
c.$table
.data('contentFocused', false)
.trigger('updateCell', [ $this, wo.editable_autoResort ]);
$this.trigger('blur.tseditable');
}
}
});
}
});
})(jQuery);