Add TWiki Sheet spreadsheet functionality to TWiki tables
Introduction
The TWiki Sheet Plugin turns a TWiki table into a spreadsheet that can be modified right in the browser. TWiki Sheet looks and feels like Excel and Google Sheets. Functions with a familiar syntax such as =SUM(A2:A6) can be added to cells. A cell range can be selected, copied and pasted between TWiki Sheet, Excel and Google Sheets. Changes to cells are saved automatically in the background, e.g. there is no explicit save step. Concurrent editing can be enabled, e.g. changes by others will magically show up in TWiki Sheet.
Related Plugins
1. The pre-installed SpreadSheetPlugin also offers spreadsheet functions for TWiki tables, such as %CALC{$SUM($ABOVE())}%. The syntax is TWiki specific, and the function are evaluated server side. We recommend using the SpreadSheetPlugin for TWiki applications that deliver ready-made tables.
2. The pre-installed EditTablePlugin offers table editing for TWiki tables using a conventional edit, modify, save sequence. This is done with HTML forms, e.g. has the look and feel of a web application. The EditTablePlugin does not offer spreadsheet functions, however, it is possible to add SpreadSheetPlugin functions.
We recommend using TWiki Sheet if you want to easily work with spreadsheets in TWiki, as you would in Excel and Google Sheets.
Add %TWIKISHEET{ }% before a TWiki table to turn that table into a TWiki Sheet, as can be seen to the right. Multiple tables in a TWiki topic can be changed into TWiki Sheets.
A TWiki Sheet can be in edit mode by default (as in Excel or Google Sheets), or can be set to toggle between view mode and edit mode.
The user interface of TWiki Sheet is done client side with a Javascript widget; for details see the technical detail section below.
TWIKISHEET Variable
The %TWIKISHEET{ }% variable supports the following parameters:
Mode of operation: • mode="classic" - regular TWiki table and an edit button; once pressed, the table switches into spreadsheet edit mode. • mode="toggle" - spreadsheet in read-only mode and an edit button; once pressed, the table switches into spreadsheet edit mode. • mode="toggle-edit" - like "toggle" but initial state is spreadsheet edit mode. • mode="edit" - the table is always in spreadsheet edit mode.
Concurrent editing. If enabled, multiple people can edit TWiki Sheet and see each other's changes. This includes editing cells, pasting a range of cells, drag-filling cells, adding/removing rows, adding/removing columns, and undo. • concurrent="0" - disable concurrent editing; changes by others will be shown after a page reload. • concurrent="1" - enable concurrent editing; changes by others will show up while editing TWiki Sheet.
Optionally disable save; useful to demo the plugin
save="0"
save="1"
width
Table width in pixels; a horizontal scrollbar is added if needed
width="500"
(full window width)
height
Table height in pixels; a vertical scrollbar is added if needed
height="300"
(full table height)
colHeaders
Set to "false" to disable the default column headers (A, B, C); set to a function for custom headers, such as: colHeaders="function(index) { return String.fromCharCode(65+index) + ' (' + (index + 1) + ')'; }", which will show headers A (1), B (2), C (3), ...
colHeaders="false"
colHeaders="true"
rowHeaders
Set to "false" to disable the default row headers (1, 2, 3)
rowHeaders="false"
rowHeaders="true"
contextMenu
Defines the right-click context menu; set to "false" to disable; set to array of available strings, such as: contextMenu="['row_above', 'row_below', 'col_left', 'col_right', 'remove_row', 'remove_col', '---------', 'undo', 'redo']"
contextMenu="false"
contextMenu="true"
fixedRowsTop
Fixed number of rows shown on top; takes effect if height parameter is used
fixedRowsTop="1"
(none)
fixedColumnsLeft
Fixed number of columns shown on the left; takes effect if width parameter is used
fixedColumnsLeft="2"
(none)
formulas
Formula support; set to "false" to disable spreadsheet calculations in table cells, such as: =SUM(A1:A8)
formulas="false"
formulas="true"
maxCols
Maximum number of columns
maxCols="10"
(unlimited)
maxRows
Maximum number of rows
maxRows="1000"
(unlimited)
minSpareCols
When set to 1 (or more), automatically add a new column at the right if there are no more empty columns
minSpareCols="1"
minSpareCols="0"
minSpareRows
When set to 1 (or more), automatically add a new row at the bottom if there are no more empty rows
minSpareRows="1"
minSpareRows="0"
wordWrap
Word wrap; set to "false" to disable cell content wrapping if it does not fit in the fixed column width
wordWrap="false"
wordWrap="true"
more...
Additional Handsontable options can be used. Notes on types of values: • Number value: Specify the number, such as width="500" • String value: Enclose the string in single quotes, such as preventOverflow="'horizontal'" • Boolean value: Specify "true" or "false", such as manualRowResize="true" • Array value: Specify the array, such as manualRowResize="[40, 50]" • Object value: Specify the object, such as columnSorting="{ column: 2, sortOrder: true }" • Function: Specify the JavaScript function, such as: cells="function( row, col, prop ) { var cp = {}; if( row===0 ) { cp.readOnly = true; } return cp; }"
TWiki Sheet Editing
Double-click on a cell to change the text
Put the focus on a cell and enter text to replace the current text
Select cells, spanning multiple rows and columns if needed, and copy to another place in the sheet, or another TWiki Sheet, Excel or Google Sheets
Pasting a cell range that does not fit into the current sheet will expand the sheet automatically to the right or bottom
To add/delete a row or cell, right-click on a cell
A cell starting with an = equal sign indicates a formula cell, such as =SUM(B2:B10)
Formulas
Formulas can be added to a cell. Start with an = equal sign and add a formula like you would in Excel or Google Sheets.
Many functions are available, see http://handsontable.github.io/ruleJS/
Formulas are considered alpha at this time; for example, cell ranges are not adjusted on copy & paste.
Modes of Operation
You can chose from these modes of operation, controlled by the mode="" parameter:
mode="classic" - classic TWiki mode:
The table is rendered as a regular TWiki table.
Press the "Edit" button to switch into TWiki Sheet mode, e.g. spreadsheet edit mode.
Press the "Done" button to switch back to the TWiki table.
There is no "Save" because the table is saved back to the TWiki server on each cell change.
TWiki variables are expanded properly in the in the regular TWiki table, but not in TWiki Sheet.
mode="toggle" - toggle mode:
The table is rendered as a read-only TWiki Sheet.
Press the "Edit" button to switch into TWiki Sheet edit mode.
Press the "Done" button to switch back to the read-only mode.
There is no "Save" because the table is saved back to the TWiki server on each cell change.
mode="toggle-edit" - toggle-edit mode:
Like "toggle" mode, but initial state is TWiki Sheet edit mode.
mode="edit" - always on mode:
The table is always in TWiki Sheet edit mode.
There is no "Save" because the table is saved back to the TWiki server on each cell change.
Notes:
TWiki variables such as %WIKINAME% are not expanded in TWiki Sheet. That this, they are preserved properly, but you can't see the expanded value unless mode="classic" is used.
The default mode of operation can be set with the {Plugins}{TWikiSheetPlugin}{Mode} configure setting, which is initially set to "classic".
Concurrent Editing
If enabled, multiple people can edit TWiki Sheet and see each other's changes. This includes editing cells, pasting a range of cells, drag-filling cells, adding/removing rows, adding/removing columns, and undo. Concurrent editing is enabled by the concurrent="" parameter:
concurrent="0" - disable concurrent editing; changes by others will be shown after a page reload.
concurrent="1" - enable concurrent editing; changes by others will show up while editing TWiki Sheet.
Notes:
The default concurrent editing mode can be set with the {Plugins}{TWikiSheetPlugin}{ConcurrentEdit} configure setting, which is initially set to "0".
Administrators can set the refresh rate for concurrent editing with the {Plugins}{TWikiSheetPlugin}{ConcurrentEditRefresh} configure setting, which is initially set to "10" seconds.
Even if enabled, users have to be authenticated in order to see other people's changes.
1. TWiki variables in TWiki Sheets are not expanded unless mode="classic" is used. That this, they are preserved as is, but that means they do not show the actual value.
2. Cell span and row span are not supported.
3. Formulas are considered alpha at this time. For example, cell ranges are not adjusted on copy & paste.
Technical Detail
This section is for developers who would like to learn how TWiki Sheets work.
The TWiki Sheet user interface is done client side using the Handsontable JavaScript widget. Handsontable is a data grid component with an Excel-like appearance that integrates with any data source and comes with many features like data validation, sorting, grouping, data binding or column ordering.
The Handsontable is initialized with an array-of-an-array object representing the table, such as:
A %TWIKISHEET{}% followed by a TWiki table is converted to an array-of-an-array JavaScript object, which is used to initialize a Handsontable table.
On each cell change, an Ajax POST is initiated that calls the REST API of the TWikiSheetPlugin on the TWiki server. Here is the code snippet that does the Ajax call:
function twSheetAfterChange( n, changes, source ) {
if( changes ) {
var tws = twSheet[n];
if( $authenticated && tws.save ) {
var sendData = {
action: 'change',
webTopic: tws.webTopic,
tableNumber: n,
tableData: JSON.stringify(tws.data),
changes: JSON.stringify(changes)
}
var jqxhr = $.ajax({
url: '/do/rest/TWikiSheetPlugin/save',
method: 'POST',
data: sendData
})
.done(function( result ) {
console.log( '- save ok: ' + JSON.stringify( result, null, ' ') );
})
.fail(function() {
alert( 'TWiki Sheet Error: Failed to save changes' );
});
}
}
}
The rest/TWikiSheetPlugin/save API takes the table data, and updates the TWiki topic if the user has permission.
Note to plugin maintainer: The formula code has a bug that prevents the fill-handle from functioning properly. Patch to fix:
--- pub/TWiki/TWikiSheetPlugin/handsontable-ruleJS/src/handsontable.formula.js (revision 30103)
+++ pub/TWiki/TWikiSheetPlugin/handsontable-ruleJS/src/handsontable.formula.js (working copy)
@@ -130,7 +130,7 @@
var cellId = instance.plugin.utils.translateCellCoords({row: row, col: col});
// if changed value, all references cells should be recalculated
- if (value[0] !== '=' || prevValue !== value) {
+ if (value && (value[0] !== '=' || prevValue !== value)) {
instance.plugin.matrix.removeItem(cellId);
// get referenced cells
@@ -155,13 +155,20 @@
var instance = this;
var r = index.row,
- c = index.col,
- value = data[r][c],
+ c = index.col;
+ if( !data || !data[r] || !data[r][c]) {
+ return {
+ value: value,
+ iterators: iterators
+ };
+ }
+
+ var value = data[r][c],
delta = 0,
rlength = data.length, // rows
clength = data ? data[0].length : 0; //cols
- if (value[0] === '=') { // formula
+ if (value && value[0] === '=') { // formula
if (['down', 'up'].indexOf(direction) !== -1) {
delta = rlength * iterators.row;
<--/twistyPlugin-->
Plugin Installation & Configuration
You do not need to install anything on the browser to use this plugin. These instructions are for the administrator who installs the plugin on the TWiki server.
Run the configure script and enable the plugin in the Plugins section.
Test if the configuration is successful:
See example above. Note that this example does not save changes back to the server
Create a topic in the Sandbox web, add a table, prefixed with %TWIKISHEET{}%. Change cells, then reload the page to verify that the changes were saved.
<--/twistyPlugin-->
Plugin Info
Set SHORTDESCRIPTION = Add TWiki Sheet spreadsheet functionality to TWiki tables
TWikibug:Item7737: The same user can now concurrent-edit the same TWiki Sheet in multiple windows
2016-04-14:
TWikibug:Item7737: Concurrent editing support - see each others changes while editing TWiki Sheet
2016-04-09:
TWikibug:Item7737: Aggregate changes to a moving time window of 500ms - this is to prevent saving changes out of sync due to network timing issues, which would cause corrupted tables; fix another formula.js bug to prevent a crash on undo
2016-04-06:
TWikibug:Item7737: Support Handsontable options to customize the TWiki Sheet; fix VBAR and BR issue
2016-04-02:
TWikibug:Item7737: Add modes of operation: "classic", "toggle", "toggle-edit" and "edit"; preserve TWiki variables; support TWiki Sheets in included topics; fix formula.js bug that prevented fill-handle from functioning properly
2016-03-30:
TWikibug:Item7737: Protect VBAR and BR by converting them to vertical bar and \n