diff options
-rw-r--r-- | example1-simple.html | 2 | ||||
-rw-r--r-- | example2-formatters.html | 2 | ||||
-rw-r--r-- | example3-editing.html | 2 | ||||
-rw-r--r-- | example4-model.html | 49 | ||||
-rw-r--r-- | grid.html | 12 | ||||
-rw-r--r-- | slick.editors.js | 1 | ||||
-rw-r--r-- | slick.globaleditorlock.js (renamed from slick.globaleditorstate.js) | 20 | ||||
-rw-r--r-- | slick.grid.js | 96 | ||||
-rw-r--r-- | slick.model.js | 28 |
9 files changed, 127 insertions, 85 deletions
diff --git a/example1-simple.html b/example1-simple.html index 380e809..1327b77 100644 --- a/example1-simple.html +++ b/example1-simple.html @@ -18,7 +18,7 @@ <script language="JavaScript" src="slick.editors.js"></script>
<script language="JavaScript" src="slick.grid.js"></script>
- <script language="JavaScript" src="slick.globaleditorstate.js"></script>
+ <script language="JavaScript" src="slick.globaleditorlock.js"></script>
<table width="100%">
diff --git a/example2-formatters.html b/example2-formatters.html index 5ce6350..bfe3b64 100644 --- a/example2-formatters.html +++ b/example2-formatters.html @@ -25,7 +25,7 @@ <script language="JavaScript" src="slick.editors.js"></script>
<script language="JavaScript" src="slick.grid.js"></script>
- <script language="JavaScript" src="slick.globaleditorstate.js"></script>
+ <script language="JavaScript" src="slick.globaleditorlock.js"></script>
<table width="100%">
diff --git a/example3-editing.html b/example3-editing.html index 4a29d88..1f4a963 100644 --- a/example3-editing.html +++ b/example3-editing.html @@ -25,7 +25,7 @@ <script language="JavaScript" src="slick.editors.js"></script>
<script language="JavaScript" src="slick.grid.js"></script>
- <script language="JavaScript" src="slick.globaleditorstate.js"></script>
+ <script language="JavaScript" src="slick.globaleditorlock.js"></script>
<table width="100%">
diff --git a/example4-model.html b/example4-model.html index 16bb318..73911ee 100644 --- a/example4-model.html +++ b/example4-model.html @@ -25,7 +25,7 @@ <script language="JavaScript" src="slick.editors.js"></script>
<script language="JavaScript" src="slick.grid.js"></script>
- <script language="JavaScript" src="slick.globaleditorstate.js"></script>
+ <script language="JavaScript" src="slick.globaleditorlock.js"></script>
<script language="JavaScript" src="slick.model.js"></script>
@@ -61,6 +61,8 @@ <li>a filtered Model (DataView) as a data source instead of a simple array</li>
<li>grid reacting to model events (onRowCountChanged, onRowsChanged)</li>
<li><b>fast real-time</b> grid updating in response to data changes</li>
+ <li>adding new rows</li>
+ <li>column options: setValueHandler, cannotTriggerInsert</li>
</ul>
</td>
@@ -84,17 +86,17 @@ var data = [];
var columns = [
- {id:"title", name:"Title", field:"title", width:120, cssClass:"cell-title", editor:TextCellEditor, validator:requiredFieldValidator},
- {id:"duration", name:"Duration", field:"duration", editor:TextCellEditor},
- {id:"%", name:"% Complete", field:"percentComplete", width:80, resizable:false, formatter:GraphicalPercentCompleteCellFormatter, editor:PercentCompleteCellEditor},
- {id:"start", name:"Start", field:"start", minWidth:60, editor:DateCellEditor},
- {id:"finish", name:"Finish", field:"finish", minWidth:60, editor:DateCellEditor},
- {id:"effort-driven", name:"Effort Driven", width:80, minWidth:20, maxWidth:80, cssClass:"cell-effort-driven", field:"effortDriven", formatter:BoolCellFormatter, editor:YesNoCheckboxCellEditor}
+ {id:"title", name:"Title", field:"title", width:120, cssClass:"cell-title", editor:TextCellEditor, validator:requiredFieldValidator, setValueHandler:updateItem},
+ {id:"duration", name:"Duration", field:"duration", editor:TextCellEditor, setValueHandler:updateItem},
+ {id:"%", name:"% Complete", field:"percentComplete", width:80, resizable:false, formatter:GraphicalPercentCompleteCellFormatter, editor:PercentCompleteCellEditor, setValueHandler:updateItem},
+ {id:"start", name:"Start", field:"start", minWidth:60, editor:DateCellEditor, setValueHandler:updateItem},
+ {id:"finish", name:"Finish", field:"finish", minWidth:60, editor:DateCellEditor, setValueHandler:updateItem},
+ {id:"effort-driven", name:"Effort Driven", width:80, minWidth:20, maxWidth:80, cssClass:"cell-effort-driven", field:"effortDriven", formatter:BoolCellFormatter, editor:YesNoCheckboxCellEditor, setValueHandler:updateItem, cannotTriggerInsert:true}
];
var options = {
editable: true,
- enableAddRow: false,
+ enableAddRow: true,
enableCellNavigation: true,
asyncEditorLoading: false
};
@@ -118,6 +120,19 @@ }
+
+ function updateItem(value,columnDef,item) {
+ item[columnDef.field] = value;
+ dataView.updateItem(item.id,item);
+ }
+
+ function addItem(columnDef,value) {
+ var item = {"id": "new_" + (Math.round(Math.random()*10000)), "title":"New task", "duration":"1 day", "percentComplete":0, "start":"01/01/2009", "finish":"01/01/2009", "effortDriven":false};
+ item[columnDef.field] = value;
+ dataView.addItem(item);
+ }
+
+
$(function()
{
// prepare the data
@@ -143,9 +158,13 @@ // initialize the grid
grid = new SlickGrid($("#myGrid"), dataView.rows, columns, options);
+ grid.onAddNewRow = addItem;
+
// wire up model events to drive the grid
- dataView.onRowCountChanged.subscribe(function() {
+ dataView.onRowCountChanged.subscribe(function(args) {
+ // remove the last "Add New" row
+ grid.removeRow(args.previous);
grid.resizeCanvas();
});
@@ -162,8 +181,8 @@ $("#pcSlider").slider({
"range": "min",
"slide": function(event,ui) {
- if (GlobalEditorState.isEditing())
- GlobalEditorState.cancelCurrentEdit();
+ if (GlobalEditorLock.isEditing())
+ GlobalEditorLock.cancelCurrentEdit();
percentCompleteThreshold = ui.value;
dataView.refresh();
@@ -173,8 +192,8 @@ // wire up the search textbox to apply the filter to the model
$("#txtSearch").keyup(function(e) {
- if (GlobalEditorState.isEditing())
- GlobalEditorState.cancelCurrentEdit();
+ if (GlobalEditorLock.isEditing())
+ GlobalEditorLock.cancelCurrentEdit();
// clear on Esc
if (e.which == 27)
@@ -185,8 +204,8 @@ })
$("#btnResort").click(function() {
- if (GlobalEditorState.isEditing())
- GlobalEditorState.cancelCurrentEdit();
+ if (GlobalEditorLock.isEditing())
+ GlobalEditorLock.cancelCurrentEdit();
dataView.sort(percentCompleteSort);
});
@@ -243,7 +243,7 @@ function updateModel(id, args) {
- if (GlobalEditorState.isEditing() && !GlobalEditorState.commitCurrentEdit()) return;
+ if (GlobalEditorLock.isEditing() && !GlobalEditorLock.commitCurrentEdit()) return;
for (var i=0; i<model.length; i++)
{
@@ -267,7 +267,7 @@ function enterEdit() {
- GlobalEditorState.enterEditMode({
+ GlobalEditorLock.enterEditMode({
commitCurrentEdit: function() { alert('validation error'); return false },
cancelCurrentEdit: function() {}
});
@@ -277,13 +277,13 @@ function doSomething() {
- if (GlobalEditorState.isEditing() && !GlobalEditorState.commitCurrentEdit()) return;
+ if (GlobalEditorLock.isEditing() && !GlobalEditorLock.commitCurrentEdit()) return;
/*
- if (GlobalEditorState.isEditing())
+ if (GlobalEditorLock.isEditing())
{
if (confirm("Cancel current edit?"))
- GlobalEditorState.cancelCurrentEdit();
+ GlobalEditorLock.cancelCurrentEdit();
else
return;
}
@@ -355,6 +355,6 @@ </script>
- <button onclick="doSomething()">Test GlobalEditorState lock</button>
+ <button onclick="doSomething()">Test GlobalEditorLock lock</button>
</body>
</html>
diff --git a/slick.editors.js b/slick.editors.js index c84a3a2..1c7d46c 100644 --- a/slick.editors.js +++ b/slick.editors.js @@ -312,6 +312,7 @@ var PercentCompleteCellEditor = function($container, columnDef, value, dataConte $picker.find(".editor-percentcomplete-slider").slider({
orientation: "vertical",
+ range: "min",
value: defaultValue,
slide: function(event, ui) {
$input.val(ui.value)
diff --git a/slick.globaleditorstate.js b/slick.globaleditorlock.js index da68f41..222de48 100644 --- a/slick.globaleditorstate.js +++ b/slick.globaleditorlock.js @@ -1,8 +1,8 @@ -
-
-var GlobalEditorState = new function()
+/***
+ * A singleton for controlling access to the editing functionality for multiple components capable of editing the same data.
+ */
+var GlobalEditorLock = new function()
{
-
var currentEditor = null;
this.isEditing = function()
@@ -10,7 +10,6 @@ var GlobalEditorState = new function() return (currentEditor != null);
}
-
this.hasLock = function(editor)
{
return (currentEditor == editor);
@@ -19,27 +18,25 @@ var GlobalEditorState = new function() this.enterEditMode = function(editor)
{
if (currentEditor != null)
- throw "GlobalEditorState : enterEditMode : currentEditor == null";
+ throw "GlobalEditorLock : enterEditMode : currentEditor == null";
if (!editor.commitCurrentEdit)
- throw "GlobalEditorState : enterEditMode : editor must implement .commitCurrentEdit()";
+ throw "GlobalEditorLock : enterEditMode : editor must implement .commitCurrentEdit()";
if (!editor.cancelCurrentEdit)
- throw "GlobalEditorState : enterEditMode : editor must implement .cancelCurrentEdit()";
+ throw "GlobalEditorLock : enterEditMode : editor must implement .cancelCurrentEdit()";
currentEditor = editor;
}
-
this.leaveEditMode = function(editor)
{
if (currentEditor != editor)
- throw "GlobalEditorState : leaveEditMode() : currentEditor != editor";
+ throw "GlobalEditorLock : leaveEditMode() : currentEditor != editor";
currentEditor = null;
}
-
this.commitCurrentEdit = function()
{
if (currentEditor)
@@ -48,7 +45,6 @@ var GlobalEditorState = new function() return true;
}
-
this.cancelCurrentEdit = function()
{
if (currentEditor)
diff --git a/slick.grid.js b/slick.grid.js index 437a22b..9a20508 100644 --- a/slick.grid.js +++ b/slick.grid.js @@ -8,6 +8,7 @@ * - frozen columns
* - built-in row reorder
* - add custom editor options
+ * - consistent events (EventHelper? jQuery events?)
*
* KNOWN ISSUES:
* - keyboard navigation doesn't "jump" over unselectable cells for now
@@ -19,13 +20,13 @@ * editable - If false, no cells will be switched into edit mode.
* editOnDoubleClick - Cell will not automatically go into edit mode without being double-clicked.
* enableCellNavigation - If false, no cells will be selectable.
- * defaultColumnWidth - Default column width in pixels (if model[cell].width is not specified).
+ * defaultColumnWidth - Default column width in pixels (if columns[cell].width is not specified).
* enableColumnReorder - Allows the user to reorder columns.
* asyncEditorLoading - Makes cell editors load asynchronously after a small delay.
* This greatly increases keyboard navigation speed.
*
*
- * COLUMN DEFINITION (MODEL) OPTIONS:
+ * COLUMN DEFINITION (columns) OPTIONS:
* id - Column ID.
* name - Column name to put in the header.
* field - Property of the data context to bind to.
@@ -53,11 +54,11 @@ *
* @param {jQuery} $container Container object to create the grid in.
* @param {Array} data An array of objects for databinding.
- * @param {Array} model An array of column definitions.
+ * @param {Array} columns An array of column definitions.
* @param {Object} options Grid options.
*
*/
-function SlickGrid($container,data,model,options)
+function SlickGrid($container,data,columns,options)
{
// settings
var defaults = {
@@ -132,9 +133,9 @@ function SlickGrid($container,data,model,options) viewportW = $divMainScroller.innerWidth();
viewportH = $divMainScroller.innerHeight();
- for (var i = 0; i < model.length; i++)
+ for (var i = 0; i < columns.length; i++)
{
- var m = model[i];
+ var m = columns[i];
columnsById[m.id] = i;
@@ -156,7 +157,7 @@ function SlickGrid($container,data,model,options) $divHeaders.find(".h").each(function() {
var cell = parseInt($(this).attr("cell"));
- var m = model[cell];
+ var m = columns[cell];
if (m.resizable === false) return;
@@ -167,12 +168,12 @@ function SlickGrid($container,data,model,options) stop: function(e, ui) {
var cellId = $(this).attr("id");
var cell = columnsById[cellId];
- model[cell].width = $(this).width();
- $.rule("." + uid + " .grid-canvas .c" + cell, "style").css("width", model[cell].width + "px");
+ columns[cell].width = $(this).width();
+ $.rule("." + uid + " .grid-canvas .c" + cell, "style").css("width", columns[cell].width + "px");
resizeCanvas();
// todo: rerender single column instead of everything
- if (model[cell].rerenderOnResize) {
+ if (columns[cell].rerenderOnResize) {
removeAllRows();
renderViewport();
}
@@ -193,15 +194,15 @@ function SlickGrid($container,data,model,options) var newOrder = $divHeaders.sortable("toArray");
var lookup = {};
- for (var i=0; i<model.length; i++)
+ for (var i=0; i<columns.length; i++)
{
- lookup[model[i].id] = model[i];
+ lookup[columns[i].id] = columns[i];
}
for (var i=0; i<newOrder.length; i++)
{
columnsById[newOrder[i]] = i;
- model[i] = lookup[newOrder[i]];
+ columns[i] = lookup[newOrder[i]];
}
removeAllRows();
@@ -238,14 +239,14 @@ function SlickGrid($container,data,model,options) }
function createCssRules() {
- for (var i = 0; i < model.length; i++)
+ for (var i = 0; i < columns.length; i++)
{
- $.rule("." + uid + " .grid-canvas .c" + i + " { width:" + model[i].width + "px }").appendTo("style");
+ $.rule("." + uid + " .grid-canvas .c" + i + " { width:" + columns[i].width + "px }").appendTo("style");
}
}
function removeCssRules() {
- for (var i = 0; i < model.length; i++)
+ for (var i = 0; i < columns.length; i++)
{
$.rule("." + uid + " .grid-canvas .c" + i, "style").remove();
}
@@ -276,7 +277,7 @@ function SlickGrid($container,data,model,options) }
function setSelectedRows(rows) {
- if (GlobalEditorState.isEditing() && !GlobalEditorState.hasLock(self))
+ if (GlobalEditorLock.isEditing() && !GlobalEditorLock.hasLock(self))
throw "Grid : setSelectedRows : cannot set selected rows when somebody else has an edit lock";
var lookup = {};
@@ -318,9 +319,9 @@ function SlickGrid($container,data,model,options) stringArray.push("<div class='" + css + "' row='" + row + "' style='top:" + (ROW_HEIGHT*row) + "px'>");
- for (var j=0; j<model.length; j++)
+ for (var j=0; j<columns.length; j++)
{
- var m = model[j];
+ var m = columns[j];
stringArray.push("<div " + (m.unselectable ? "" : "hideFocus tabIndex=0 ") + "class='c c" + j + (m.cssClass ? " " + m.cssClass : "") + "' cell=" + j + ">");
@@ -364,7 +365,7 @@ function SlickGrid($container,data,model,options) var $cell = $(rowsCache[row]).find(".c[cell=" + cell + "]");
if ($cell.length == 0) return;
- var m = model[cell];
+ var m = columns[cell];
if (currentEditor && currentRow == row && currentCell == cell)
currentEditor.setValue(data[currentRow][m.field]);
@@ -379,7 +380,7 @@ function SlickGrid($container,data,model,options) // todo: perf: iterate over direct children?
$(rowsCache[row]).find(".c").each(function(i) {
- var m = model[i];
+ var m = columns[i];
if (row == currentRow && i == currentCell && currentEditor)
currentEditor.setValue(data[currentRow][m.field]);
@@ -401,9 +402,9 @@ function SlickGrid($container,data,model,options) viewportH = $divMainScroller.innerHeight();
var totalWidth = 0;
- for (var i=0; i<model.length; i++)
+ for (var i=0; i<columns.length; i++)
{
- totalWidth += (model[i].width + 5);
+ totalWidth += (columns[i].width + 5);
}
$divMain.width(totalWidth);
@@ -536,7 +537,7 @@ function SlickGrid($container,data,model,options) function onKeyDown(e) {
switch (e.which) {
case 27: // esc
- if (GlobalEditorState.isEditing() && GlobalEditorState.hasLock(self))
+ if (GlobalEditorLock.isEditing() && GlobalEditorLock.hasLock(self))
self.cancelCurrentEdit(self);
if (currentCellNode)
@@ -627,7 +628,7 @@ function SlickGrid($container,data,model,options) }
- if (options.enableCellNavigation && !model[cell].unselectable)
+ if (options.enableCellNavigation && !columns[cell].unselectable)
{
// commit current edit before proceeding
if (validated == true || (validated == null && self.commitCurrentEdit()))
@@ -653,9 +654,9 @@ function SlickGrid($container,data,model,options) var cell = 0;
var w = 0;
- for (var i=0; i<model.length && w<y; i++)
+ for (var i=0; i<columns.length && w<y; i++)
{
- w += model[i].width;
+ w += columns[i].width;
cell++;
}
@@ -734,11 +735,11 @@ function SlickGrid($container,data,model,options) return false;
// are we in the Add New row? can we create new from this cell?
- if (model[cell].cannotTriggerInsert && row >= data.length)
+ if (columns[cell].cannotTriggerInsert && row >= data.length)
return false;
// does this cell have an editor?
- if (!model[cell].editor)
+ if (!columns[cell].editor)
return false;
return true;
@@ -752,7 +753,7 @@ function SlickGrid($container,data,model,options) if (data[currentRow])
- currentCellNode.innerHTML = model[currentCell].formatter(currentRow, currentCell, data[currentRow][model[currentCell].field], model[currentCell], data[currentRow]);
+ currentCellNode.innerHTML = columns[currentCell].formatter(currentRow, currentCell, data[currentRow][columns[currentCell].field], columns[currentCell], data[currentRow]);
currentEditor = null;
@@ -760,7 +761,7 @@ function SlickGrid($container,data,model,options) // IE can't set focus to anything else correctly
if ($.browser.msie) clearTextSelection();
- GlobalEditorState.leaveEditMode(self);
+ GlobalEditorLock.leaveEditMode(self);
}
function makeSelectedCellEditable()
@@ -776,7 +777,7 @@ function SlickGrid($container,data,model,options) if (!isCellPotentiallyEditable(currentRow,currentCell))
return;
- GlobalEditorState.enterEditMode(self);
+ GlobalEditorLock.enterEditMode(self);
$(currentCellNode).addClass("editable");
@@ -784,11 +785,11 @@ function SlickGrid($container,data,model,options) // if there is a corresponding row
if (data[currentRow])
- value = data[currentRow][model[currentCell].field];
+ value = data[currentRow][columns[currentCell].field];
currentCellNode.innerHTML = "";
- currentEditor = new model[currentCell].editor($(currentCellNode), model[currentCell], value, data[currentRow]);
+ currentEditor = new columns[currentCell].editor($(currentCellNode), columns[currentCell], value, data[currentRow]);
}
function scrollSelectedCellIntoView() {
@@ -816,7 +817,7 @@ function SlickGrid($container,data,model,options) {
if (!currentCellNode) return;
if (!options.enableCellNavigation) return;
- if (!GlobalEditorState.commitCurrentEdit()) return;
+ if (!GlobalEditorLock.commitCurrentEdit()) return;
var nextRow = rowsCache[currentRow + dy];
var nextCell = nextRow ? $(nextRow).find(".c[cell=" + (currentCell + dx) + "][tabIndex=0]") : null;
@@ -854,10 +855,10 @@ function SlickGrid($container,data,model,options) function gotoCell(row,cell)
{
- if (row > data.length || row < 0 || cell >= model.length || cell < 0) return;
- if (!options.enableCellNavigation || model[cell].unselectable) return;
+ if (row > data.length || row < 0 || cell >= columns.length || cell < 0) return;
+ if (!options.enableCellNavigation || columns[cell].unselectable) return;
- if (!GlobalEditorState.commitCurrentEdit()) return;
+ if (!GlobalEditorLock.commitCurrentEdit()) return;
if (!rowsCache[row])
renderRows(row,row);
@@ -873,7 +874,7 @@ function SlickGrid($container,data,model,options) //////////////////////////////////////////////////////////////////////////////////////////////
- // IEditor implementation for GlobalEditorState
+ // IEditor implementation for GlobalEditorLock
this.commitCurrentEdit = function() {
if (currentEditor)
@@ -884,18 +885,19 @@ function SlickGrid($container,data,model,options) if (validationResults.valid)
{
+ var value = currentEditor.getValue();
+
+ makeSelectedCellNormal();
+
if (currentRow < data.length)
{
- if (model[currentCell].setValueHandler)
- model[currentCell].setValueHandler(currentEditor.getValue(), model[currentCell], data[currentRow]);
+ if (columns[currentCell].setValueHandler)
+ columns[currentCell].setValueHandler(value, columns[currentCell], data[currentRow]);
else
- data[currentRow][model[currentCell].field] = currentEditor.getValue();
+ data[currentRow][columns[currentCell].field] = value;
}
else if (self.onAddNewRow)
- self.onAddNewRow(model[currentCell], currentEditor.getValue());
-
-
- makeSelectedCellNormal();
+ self.onAddNewRow(columns[currentCell], value);
return true;
}
@@ -905,7 +907,7 @@ function SlickGrid($container,data,model,options) $(currentCellNode).stop(true,true).effect("highlight", {color:"red"}, 300);
if (self.onValidationError)
- self.onValidationError(currentCellNode, validationResults, currentRow, currentCell, model[currentCell]);
+ self.onValidationError(currentCellNode, validationResults, currentRow, currentCell, columns[currentCell]);
currentEditor.focus();
return false;
diff --git a/slick.model.js b/slick.model.js index 7838d78..4dc54bb 100644 --- a/slick.model.js +++ b/slick.model.js @@ -61,6 +61,26 @@ function DataView() { return items[idxById[id]];
}
+ function updateItem(id,item) {
+ items[idxById[id]] = item;
+ refresh();
+ }
+
+ function insertItem(insertBefore,item) {
+ items.splice(insertBefore,0,item);
+ refresh();
+ }
+
+ function addItem(item) {
+ items.push(item);
+ refresh();
+ }
+
+ function deleteItem(id) {
+ items.splice(idxById[id],1);
+ refresh();
+ }
+
function getDiff(arrayA, arrayB) {
var diff = [];
@@ -126,7 +146,7 @@ function DataView() { diff = $.unique(diff);
- if (countBefore != rows.length) onRowCountChanged.notify(null);
+ if (countBefore != rows.length) onRowCountChanged.notify({previous:countBefore, current:rows.length});
if (diff.length > 0) onRowsChanged.notify(diff);
updated = [];
@@ -135,12 +155,16 @@ function DataView() { return {
- "rows": rows,
+ "rows": rows, // note: neither the array or the data in it should really be modified directly
"setItems": setItems,
"setFilter": setFilter,
"sort": sort,
"getItemById": getItemById,
"refresh": refresh,
+ "updateItem": updateItem,
+ "insertItem": insertItem,
+ "addItem": addItem,
+ "deleteItem": deleteItem,
"onRowCountChanged": onRowCountChanged,
"onRowsChanged": onRowsChanged
};
|