summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/example1-simple.html4
-rw-r--r--examples/example10-async-post-render.html2
-rw-r--r--examples/example2-formatters.html9
-rw-r--r--examples/example3-editing.html2
-rw-r--r--examples/example4-model.html16
-rw-r--r--examples/example5-collapsing.html20
-rw-r--r--examples/example6-ajax-loading.html14
-rw-r--r--examples/example7-events.html2
-rw-r--r--examples/example8-alternative-display.html2
-rw-r--r--examples/example9-row-reordering.html4
-rw-r--r--examples/grid.html361
-rw-r--r--examples/simpledropdown.css83
-rw-r--r--slick.columnpicker.js116
-rw-r--r--slick.globaleditorlock.js112
-rw-r--r--slick.grid.css1
-rw-r--r--slick.grid.js2305
-rw-r--r--slick.model.js391
-rw-r--r--slick.pager.js248
-rw-r--r--slick.remotemodel.js276
-rw-r--r--tests/model benchmarks.html4
-rw-r--r--tests/scrolling benchmarks.html4
21 files changed, 1757 insertions, 2219 deletions
diff --git a/examples/example1-simple.html b/examples/example1-simple.html
index 2c1f93f..adbc4d4 100644
--- a/examples/example1-simple.html
+++ b/examples/example1-simple.html
@@ -76,9 +76,7 @@
d["effortDriven"] = (i % 5 == 0);
}
-
-
- grid = new SlickGrid($("#myGrid"), data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
$("#myGrid").resizable();
})
diff --git a/examples/example10-async-post-render.html b/examples/example10-async-post-render.html
index 2d072e0..1e7d9f6 100644
--- a/examples/example10-async-post-render.html
+++ b/examples/example10-async-post-render.html
@@ -112,7 +112,7 @@
}
- grid = new SlickGrid($("#myGrid"), data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
grid.onPostProcessRowNode = function(rowNode, row, dataContext) {
diff --git a/examples/example2-formatters.html b/examples/example2-formatters.html
index 10c3538..037e877 100644
--- a/examples/example2-formatters.html
+++ b/examples/example2-formatters.html
@@ -70,7 +70,6 @@
};
-
$(function()
{
for (var i=0; i<500; i++) {
@@ -84,13 +83,7 @@
d["effortDriven"] = (i % 5 == 0);
}
-
- grid = new SlickGrid($("#myGrid"), data, columns, options);
-
- grid.onHeaderContextMenu = function() {
- console.log(1)
-
- }
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
})
</script>
diff --git a/examples/example3-editing.html b/examples/example3-editing.html
index 298a6fc..0de321d 100644
--- a/examples/example3-editing.html
+++ b/examples/example3-editing.html
@@ -94,7 +94,7 @@
}
- grid = new SlickGrid($("#myGrid"), data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
})
</script>
diff --git a/examples/example4-model.html b/examples/example4-model.html
index a97db68..63936a4 100644
--- a/examples/example4-model.html
+++ b/examples/example4-model.html
@@ -163,10 +163,10 @@
}
- dataView = new DataView();
- grid = new SlickGrid($("#myGrid"), dataView.rows, columns, options);
- var pager = new SlickGridPager(dataView, grid, $("#pager"));
- var columnpicker = new SlickColumnPicker(columns, grid);
+ dataView = new Slick.Data.DataView();
+ grid = new Slick.Grid($("#myGrid"), dataView.rows, columns, options);
+ var pager = new Slick.Controls.Pager(dataView, grid, $("#pager"));
+ var columnpicker = new Slick.Controls.ColumnPicker(columns, grid);
grid.onAddNewRow = addItem;
@@ -240,8 +240,8 @@
$("#pcSlider").slider({
"range": "min",
"slide": function(event,ui) {
- if (GlobalEditorLock.isEditing())
- GlobalEditorLock.cancelCurrentEdit();
+ if (Slick.GlobalEditorLock.isEditing())
+ Slick.GlobalEditorLock.cancelCurrentEdit();
if (percentCompleteThreshold != ui.value)
{
@@ -255,8 +255,8 @@
// wire up the search textbox to apply the filter to the model
$("#txtSearch").keyup(function(e) {
- if (GlobalEditorLock.isEditing())
- GlobalEditorLock.cancelCurrentEdit();
+ if (Slick.GlobalEditorLock.isEditing())
+ Slick.GlobalEditorLock.cancelCurrentEdit();
// clear on Esc
if (e.which == 27)
diff --git a/examples/example5-collapsing.html b/examples/example5-collapsing.html
index 4c820a7..1572cec 100644
--- a/examples/example5-collapsing.html
+++ b/examples/example5-collapsing.html
@@ -15,14 +15,6 @@
text-align: center;
}
- .sort-asc {
- background: silver url('../images/sort-asc.png') no-repeat right center !important;
- }
-
- .sort-desc {
- background: silver url('../images/sort-desc.png') no-repeat right center !important;
- }
-
.toggle {
height: 9px;
width: 9px;
@@ -212,7 +204,7 @@
// initialize the model
- dataView = new DataView();
+ dataView = new Slick.Data.DataView();
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(myFilter);
@@ -220,7 +212,7 @@
// initialize the grid
- grid = new SlickGrid($("#myGrid"), dataView.rows, columns, options);
+ grid = new Slick.Grid($("#myGrid"), dataView.rows, columns, options);
grid.onAddNewRow = addItem;
@@ -261,8 +253,8 @@
$("#pcSlider").slider({
"range": "min",
"slide": function(event,ui) {
- if (GlobalEditorLock.isEditing())
- GlobalEditorLock.cancelCurrentEdit();
+ if (Slick.GlobalEditorLock.isEditing())
+ Slick.GlobalEditorLock.cancelCurrentEdit();
if (percentCompleteThreshold != ui.value)
{
@@ -276,8 +268,8 @@
// wire up the search textbox to apply the filter to the model
$("#txtSearch").keyup(function(e) {
- if (GlobalEditorLock.isEditing())
- GlobalEditorLock.cancelCurrentEdit();
+ if (Slick.GlobalEditorLock.isEditing())
+ Slick.GlobalEditorLock.cancelCurrentEdit();
// clear on Esc
if (e.which == 27)
diff --git a/examples/example6-ajax-loading.html b/examples/example6-ajax-loading.html
index 217e394..78bbb07 100644
--- a/examples/example6-ajax-loading.html
+++ b/examples/example6-ajax-loading.html
@@ -10,15 +10,7 @@
.cell-story {
white-space: normal!important;
}
-
- .sort-asc {
- background: silver url('../images/sort-asc.png') no-repeat right center !important;
- }
-
- .sort-desc {
- background: silver url('../images/sort-desc.png') no-repeat right center !important;
- }
-
+
.loading-indicator {
display: inline-block;
padding: 12px;
@@ -78,7 +70,7 @@
<script>
var grid;
var data = [];
- var loader = new RemoteModel();
+ var loader = new Slick.Data.RemoteModel();
var storyTitleFormatter = function(row, cell, value, columnDef, dataContext) {
return "<b><a href='" + dataContext["link"] + "' target=_blank>" + dataContext["title"] + "</a></b><br/>" + dataContext["description"];
@@ -104,7 +96,7 @@
$(function()
{
- grid = new SlickGrid($("#myGrid"), loader.data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), loader.data, columns, options);
grid.onViewportChanged = function() {
var vp = grid.getViewport();
diff --git a/examples/example7-events.html b/examples/example7-events.html
index 3660cc2..e268861 100644
--- a/examples/example7-events.html
+++ b/examples/example7-events.html
@@ -112,7 +112,7 @@
}
- grid = new SlickGrid($("#myGrid"), data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
grid.onContextMenu = function (e, row, cell)
{
diff --git a/examples/example8-alternative-display.html b/examples/example8-alternative-display.html
index fdd44dd..9694391 100644
--- a/examples/example8-alternative-display.html
+++ b/examples/example8-alternative-display.html
@@ -170,7 +170,7 @@
}
- grid = new SlickGrid($("#myGrid"), data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
})
</script>
diff --git a/examples/example9-row-reordering.html b/examples/example9-row-reordering.html
index a245f94..bc08bbf 100644
--- a/examples/example9-row-reordering.html
+++ b/examples/example9-row-reordering.html
@@ -62,7 +62,6 @@
width: 40,
behavior: "move",
unselectable: true,
- sortable: false,
resizable: false,
cssClass: "cell-reorder"
}, {
@@ -76,7 +75,6 @@
}, {
id: "complete",
name: "Complete",
- sortable: false,
width: 60,
cssClass: "cell-effort-driven",
field: "complete",
@@ -109,7 +107,7 @@
{ name: "Find out who's nice", complete: false}
];
- grid = new SlickGrid($("#myGrid"), data, columns, options);
+ grid = new Slick.Grid($("#myGrid"), data, columns, options);
grid.onAddNewRow = function addItem(columnDef,value) {
var item = {name:"New task", complete: false};
diff --git a/examples/grid.html b/examples/grid.html
deleted file mode 100644
index 4bf45d2..0000000
--- a/examples/grid.html
+++ /dev/null
@@ -1,361 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
- <title>Spreadsheet prototype</title>
- <link rel="stylesheet" href="simpledropdown.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="../slick.grid.css" type="text/css" media="screen" charset="utf-8" />
- <link rel="stylesheet" href="../css/custom-theme/jquery-ui-1.7.2.custom.css" type="text/css" media="screen" charset="utf-8" />
- <style>
- *
- {
- font-family: arial;
- font-size: 8pt;
- }
-
- hr {
- height: 1px;
- border: 0;
- background: silver;
- }
-
- #grid {
- background: white;
- outline: 0px;
- }
-
- ul {
- padding: 0px;
- cursor: default;
- }
-
- li {
- background: url("../images/arrow_right_spearmint.png") no-repeat 0px center;
- padding-left: 12px;
- list-style: none;
- margin: 0px;
- }
-
- li:hover {
- background: url("../images/arrow_right_peppermint.png") no-repeat 0px center;
- }
-
- .listview-header {
- height: 24px;
- line-height: 24px;
- width: 100%;
- background: url("../images/listview.gif") no-repeat top left;
- }
-
- .listview-header .r {
- float:right;
- text-align: right;
- width: 50%;
- height: 24px;
- background: white url("../images/listview.gif") no-repeat top right;
- line-height: 24px;
- }
-
- .listview-header input {
- border: 1px solid silver;
- }
- .listview-footer {
- height: 24px;
- line-height: 24px;
- width: 100%;
- background: url("../images/listview.gif") no-repeat left -24px;
- }
-
- .listview-footer .r {
- float:right;
- text-align: right;
- width: 50%;
- height: 24px;
- background: white url("../images/listview.gif") no-repeat right -24px;
- line-height: 24px;
- }
- </style>
- </head>
- <body>
- <script language="JavaScript" src="../lib/firebugx.js"></script>
- <script language="JavaScript" src="../lib/jquery-1.3.2.min.js"></script>
- <script language="JavaScript" src="../lib/jquery-ui-1.7.2.custom.min.js"></script>
- <script language="JavaScript" src="../lib/jquery.getScrollbarWidth.js"></script>
- <script language="JavaScript" src="../lib/jquery.rule-1.0.1-min.js"></script>
- <script language="JavaScript" src="../lib/jquery.event.drag.custom.js"></script>
-
- <script language="JavaScript" src="../slick.editors.js"></script>
- <script language="JavaScript" src="../slick.grid.js"></script>
- <script language="JavaScript" src="../slick.globaleditorlock.js"></script>
-
-
- <div class="listview-header">
- <div style="float:left;padding-left:14px;">
-
- <span class="simple-dropdown">
- <em>Reload grid</em>
- <div>
- <a href="javascript:reinitGrid(10)">Load 10 rows</a>
- <a href="javascript:reinitGrid(100)">Load 100 rows</a>
- <a href="javascript:reinitGrid(500)">Load 500 rows</a>
- <a href="javascript:reinitGrid(1000)">Load 1'000 rows</a>
- <a href="javascript:reinitGrid(5000)">Load 5'000 rows</a>
- <a href="javascript:reinitGrid(50000)">Load 50'000 rows</a>
- </div>
- </span>
-
- <span class="simple-dropdown">
- <em>Change column styles</em>
- <div>
- <a href="javascript:updateModel('%', {formatter:PercentCompleteCellFormatter, cssClass:'task-percent'})">Render <b>% Complete</b> as text</a>
- <a href="javascript:updateModel('%', {formatter:GraphicalPercentCompleteCellFormatter, cssClass:null})">Render <b>% Complete</b> as graph</a>
- </div>
- </span>
-
- <span class="simple-dropdown">
- <em>Select rows</em>
- <div>
- <a href="javascript:grid.setSelectedRows([0,1,2,3,4])">0 - 5</a>
- </div>
- </span>
-
- <span class="simple-dropdown">
- <em>Options</em>
- <div>
- <a href="javascript:grid.setOptions({enableAddRow:true})">enableAddRow = true</a>
- <a href="javascript:grid.setOptions({enableAddRow:false})">enableAddRow = false</a>
- <hr/>
- <a href="javascript:grid.setOptions({editable:true})">editable = true</a>
- <a href="javascript:grid.setOptions({editable:false})">editable = false</a>
- <hr/>
- <a href="javascript:grid.setOptions({editOnDoubleClick:true})">editOnDoubleClick = true</a>
- <a href="javascript:grid.setOptions({editOnDoubleClick:false})">editOnDoubleClick = false</a>
- <hr/>
- <a href="javascript:grid.setOptions({enableCellNavigation:true})">enableCellNavigation = true</a>
- <a href="javascript:grid.setOptions({enableCellNavigation:false})">enableCellNavigation = false</a>
- <hr/>
- <a href="javascript:grid.setOptions({asyncEditorLoading:true})">asyncEditorLoading = true</a>
- <a href="javascript:grid.setOptions({asyncEditorLoading:false})">asyncEditorLoading = false</a>
- </div>
- </span>
-
- <span class="simple-dropdown">
- <em>Debug</em>
- <div>
- <a href="javascript:grid.benchmarkFn('removeAllRows')">benchmark removeAllRows</a>
- <a href="javascript:grid.benchmarkFn('render')">benchmark render</a>
- <a href="javascript:grid.benchmarkFn('benchmark_render_200')">benchmark render 200</a>
- <hr/>
- <a href="javascript:grid.stressTest()">stress test (infinite render/clear cycle)</a>
- <hr/>
- <a href="javascript:grid.debug()">internal state</a>
- </div>
- </span>
-
- <span class="simple-dropdown">
- <em style="padding-left:16px;background:url('../images/info.gif') no-repeat center left;">Quick info</em>
- <div style="max-width:600px">
-
- This page demonstrate the use of a SlickGrid control.
- <br><br>
- <b>Key features:</b>
- <ul>
- <li>Virtual rendering/scrolling (hundreds of thousands of rows)</li>
- <li>Extremely fast rendering speed</li>
- <li>Support for a Model data source</li>
- <li>Support for Ajax-loaded data</li>
- <li>Multiple row selection</li>
- <li>Edit and add new rows</li>
- <li>Keyboard navigation for cell selection</li>
- <li>Custom renderers for cells with conditional formatting</li>
- <li>Formatters adaptive to column width</li>
- <li>Custom editors for cells</li>
- <li>Resizable and reorderable columns</li>
- <li>Highly customizable & configurable</li>
- <li>Built-in validators</li>
- <li>Callbacks for events</li>
- <li>Much much more...</li>
- </ul>
-
- </div>
- </span>
-
- </div>
-
- <div class="r">
- <div style="padding-right:14px;">
- <label>Filter:</label> <input type=text>
- &nbsp;
- </div>
- </div>
- </div>
- <div id="myGrid" style="width:100%;height:500px;"></div>
- <div class="listview-footer">
- <div style="float:left;padding-left:14px;">
- </div>
-
- <div class="r">
- <div style="padding-right:14px;">
- </div>
- </div>
- </div>
-
- <br/>
-
- <script>
-
- $(".simple-dropdown a").click(function(e) {
- var dd = $(this).closest(".simple-dropdown > div");
-
- dd.css("display", "none");
- window.setTimeout(function () { dd.css("display", ""); }, 10);
- });
-
-
- function nonEmptyValidator(value) {
- if (value == null || value == undefined || !value.length)
- return {valid:false, msg:"This is a required field"};
- else
- return {valid:true, msg:null};
- }
-
- function setTaskResources(resourcesNamesArray, cellInfo, dataContext)
- {
- dataContext["resources"] = resourcesNamesArray.length > 0 ? resourcesNamesArray.concat() : null;
- }
-
- var data = [];
- var grid;
- var model = [
- {id:"#", name:"#", cssClass:"cell-move-handle", width:60, resizable:false, unselectable:true, formatter:SelectorCellFormatter},
- {id:"title", name:"Title", field:"title", formatter:TaskNameFormatter, width:300, editor:TextCellEditor, validator:nonEmptyValidator},
- {id:"star", name:"<img src='../images/bullet_star.png' align='absmiddle'>", field:"starred", formatter:StarFormatter, editor:StarCellEditor, width:16, resizable:false, cannotTriggerInsert:true},
- {id:"duration", name:"Duration", field:"duration", width:80, editor:TextCellEditor},
- {id:"%", name:"% Complete", field:"percentComplete", formatter:GraphicalPercentCompleteCellFormatter, width:60, editor:PercentCompleteCellEditor},
- {id:"start", name:"Start", field:"start", width:100, editor:DateCellEditor},
- {id:"finish", name:"Finish", field:"finish", width:100, editor:DateCellEditor},
- {id:"resources", name:"Resources <img src='../images/help.png' align='absmiddle' title='This column has an adaptive formatter. Resize to a smaller size to see alternative data representation.'>", formatter:ResourcesFormatter, rerenderOnResize:true, width:200, editor:ResourcesCellEditor, setValueHandler:setTaskResources, cannotTriggerInsert:true, minWidth:16, maxWidth:200},
- {id:"preds", name:"Predecessors", width:100, editor:TextCellEditor, cannotTriggerInsert:true}
- ,
- {id:"e", name:"Deliverable", field:4, formatter:YesNoCellFormatter, width:60, editor:YesNoSelectCellEditor, cannotTriggerInsert:true},
- {id:"f", name:"Effort-driven", field:5, formatter:YesNoCellFormatter, width:50, editor:YesNoCheckboxCellEditor, cannotTriggerInsert:true}
- ];
-
-
-
- function updateModel(id, args) {
- if (GlobalEditorLock.isEditing() && !GlobalEditorLock.commitCurrentEdit()) return;
-
- for (var i=0; i<model.length; i++)
- {
- if (model[i].id == id) {
- model[i] = $.extend(model[i], args);
- grid.removeAllRows();
- grid.render();
- return;
- }
- }
- }
-
-
- $(function()
- {
- $("#myGrid")[0].unselectable = true;
-
- reinitGrid(10);
- })
-
-
- function enterEdit() {
-
- GlobalEditorLock.enterEditMode({
- commitCurrentEdit: function() { alert('validation error'); return false },
- cancelCurrentEdit: function() {}
- });
-
- }
-
-
- function doSomething() {
-
- if (GlobalEditorLock.isEditing() && !GlobalEditorLock.commitCurrentEdit()) return;
-
-/*
- if (GlobalEditorLock.isEditing())
- {
- if (confirm("Cancel current edit?"))
- GlobalEditorLock.cancelCurrentEdit();
- else
- return;
- }
-*/
-
- alert("Editor lock acquired")
-
- }
-
-
- function reinitGrid(loadedRows,totalRows) {
-
- data = [];
-
- for (var i = 0; i < loadedRows; i++)
- {
- var d = (data[i] = {});
-
- d["title"] = "Task " + i;
- d["duration"] = "5 days";
- d["percentComplete"] = Math.round(Math.random() * 100);
- d["start"] = "01/01/2009";
- d["finish"] = "01/05/2009";
- d["indent"] = i % 5;
- d["resources"] = (i % 7 == 0) ? ["Boris The Blade", "Bullet Tooth"] : (i % 11 == 0 ? ["Bricktop"] : null);
- }
-
-
- if (grid) grid.destroy();
-
-
- grid = new SlickGrid($("#myGrid"), data, model, {});
-
- grid.onValidationError = function(elem, validationResults, row, cell, cellInfo) {
- console.warn(validationResults.msg);
- }
-
- grid.onAddNewRow = function(cellInfo, value) {
- var item = {title:"New task", indent:0, duration:"1 day", percentComplete:0, start:"01/01/2009", finish:"01/01/2009"};
-
- item[cellInfo.field] = value;
-
- data[data.length] = item;
-
- grid.updateRowCount();
- grid.render();
- grid.updateRow(data.length-1);
- }
-
- grid.onClick = function(e, row, cell) {
- // toggle expand/collapse icon
- if (model[cell].id == "title" && $(e.target).is("img"))
- {
- $(e.target).attr("src", $(e.target).attr("src") != "../images/collapse.gif" ? "../images/collapse.gif" : "../images/expand.gif");
- return true;
- }
-
- if (model[cell].id == "#")
- {
- grid.setSelectedRows([row]);
- }
-
- // pass the event through
- return false;
- }
- }
-
-
- </script>
-
-
- <button onclick="doSomething()">Test GlobalEditorLock lock</button>
- </body>
-</html>
diff --git a/examples/simpledropdown.css b/examples/simpledropdown.css
deleted file mode 100644
index ffd71f7..0000000
--- a/examples/simpledropdown.css
+++ /dev/null
@@ -1,83 +0,0 @@
-.simple-dropdown {
- z-index: 100;
- overflow: visible;
- display: inline-block;
- line-height: normal;
-
- border: 1px solid silver;
- background: #eee url("images/down.gif") no-repeat center right;
- padding: 2px;
- padding-left: 8px;
- padding-right: 20px;
- margin: 2px;
-
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
-}
-
-.simple-dropdown > em {
- display: block;
-
- text-decoration: none;
- font-style: normal;
- cursor: default;
-}
-
-.simple-dropdown:hover {
- background-color: #777;
- color: white;
- border-color: gray;
-}
-
-.simple-dropdown:hover > div {
- -display: block;
- visibility: visible;
-
- opacity: 1;
- -webkit-transition: opacity 0.5s;
-}
-
-.simple-dropdown > div {
- z-index: 100;
- -display: none;
- visibility: hidden;
- position: absolute;
- margin-left: -9px;
- min-width: 120px;
- max-width: 200px;
-
- color: black;
- text-align: left;
- padding: 4px;
- background: #fafafa;
- border: 1px solid gray;
-
- -moz-border-radius: 5px;
- -webkit-border-radius: 5px;
- -moz-border-radius-topleft: 0px;
- -webkit-border-top-left-radius: 0px;
- -moz-box-shadow: 2px 2px 2px silver;
- -webkit-box-shadow: 2px 2px 2px silver;
-
- opacity: 0;
-}
-
-.simple-dropdown > div a {
- display: block;
- padding: 2px;
- outline: 0px;
- text-decoration: none;
- color: black;
- cursor: default;
- zbackground: #fafafa url("images/arrow_right_spearmint.png") no-repeat center left;
- padding-left: 12px;
- padding-right: 6px;
-}
-
-
-.simple-dropdown > div a:hover {
- background: skyblue url("images/arrow_right_peppermint.png") no-repeat center left;
-
- -moz-border-radius: 3px;
- -webkit-border-radius: 3px;
-} \ No newline at end of file
diff --git a/slick.columnpicker.js b/slick.columnpicker.js
index 012394c..476c66b 100644
--- a/slick.columnpicker.js
+++ b/slick.columnpicker.js
@@ -1,71 +1,75 @@
-function SlickColumnPicker(columns,grid)
-{
- var $menu;
-
- function init() {
- grid.onHeaderContextMenu = displayContextMenu;
-
- $menu = $("<span class='slick-columnpicker' style='display:none;position:absolute;z-index:20;' />").appendTo(document.body);
-
- $menu.bind("mouseleave", function(e) { $(this).fadeOut() });
- $menu.bind("click", updateColumn);
-
- }
-
- function displayContextMenu(e)
+(function() {
+ function SlickColumnPicker(columns,grid)
{
- $menu.empty();
+ var $menu;
- for (var i=0; i<columns.length; i++) {
- var $li = $("<li />").appendTo($menu);
+ function init() {
+ grid.onHeaderContextMenu = displayContextMenu;
- var $input = $("<input type='checkbox' />")
- .attr("id", "columnpicker_" + i)
- .data("id", columns[i].id)
- .appendTo($li)
+ $menu = $("<span class='slick-columnpicker' style='display:none;position:absolute;z-index:20;' />").appendTo(document.body);
- if (!columns[i].hidden)
- $input.attr("checked","checked");
+ $menu.bind("mouseleave", function(e) { $(this).fadeOut() });
+ $menu.bind("click", updateColumn);
- $("<label for='columnpicker_" + i + "' />")
- .text(columns[i].name)
- .appendTo($li);
}
- $("<hr/><li><a id='autoresize'>Autosize</a></li>").appendTo($menu);
-
- $menu
- .css("top", e.pageY - 10)
- .css("left", e.pageX - 10)
- .fadeIn();
- }
-
- function updateColumn(e)
- {
- if ($(e.target).is("a")) {
- grid.autosizeColumns();
- $menu.fadeOut();
- return;
+ function displayContextMenu(e)
+ {
+ $menu.empty();
+
+ for (var i=0; i<columns.length; i++) {
+ var $li = $("<li />").appendTo($menu);
+
+ var $input = $("<input type='checkbox' />")
+ .attr("id", "columnpicker_" + i)
+ .data("id", columns[i].id)
+ .appendTo($li)
+
+ if (!columns[i].hidden)
+ $input.attr("checked","checked");
+
+ $("<label for='columnpicker_" + i + "' />")
+ .text(columns[i].name)
+ .appendTo($li);
+ }
+
+ $("<hr/><li><a id='autoresize'>Autosize</a></li>").appendTo($menu);
+
+ $menu
+ .css("top", e.pageY - 10)
+ .css("left", e.pageX - 10)
+ .fadeIn();
}
- if ($(e.target).is(":checkbox")) {
- if ($menu.find(":checkbox:checked").length == 0) {
- $(e.target).attr("checked","checked");
- return;
+ function updateColumn(e)
+ {
+ if ($(e.target).is("a")) {
+ grid.autosizeColumns();
+ $menu.fadeOut();
+ return;
}
- var id =$(e.target).data("id");
- for (var i=0; i<columns.length; i++) {
- if (columns[i].id == id) {
- columns[i].hidden = !$(e.target).is(":checked");
- grid.setColumnVisibility(columns[i], $(e.target).is(":checked"));
- return;
+ if ($(e.target).is(":checkbox")) {
+ if ($menu.find(":checkbox:checked").length == 0) {
+ $(e.target).attr("checked","checked");
+ return;
}
- }
+
+ var id =$(e.target).data("id");
+ for (var i=0; i<columns.length; i++) {
+ if (columns[i].id == id) {
+ columns[i].hidden = !$(e.target).is(":checked");
+ grid.setColumnVisibility(columns[i], $(e.target).is(":checked"));
+ return;
+ }
+ }
+ }
}
+
+
+ init();
}
-
- init();
-}
-
+ // Slick.Controls.ColumnPicker
+ $.extend(true, window, { Slick: { Controls: { ColumnPicker: SlickColumnPicker }}});
+})(); \ No newline at end of file
diff --git a/slick.globaleditorlock.js b/slick.globaleditorlock.js
index de6bc26..da64a0e 100644
--- a/slick.globaleditorlock.js
+++ b/slick.globaleditorlock.js
@@ -1,54 +1,58 @@
-/***
- * 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()
- {
- return (currentEditor != null);
- }
-
- this.hasLock = function(editor)
- {
- return (currentEditor == editor);
- }
-
- this.enterEditMode = function(editor)
- {
- if (currentEditor != null)
- throw "GlobalEditorLock : enterEditMode : currentEditor == null";
-
- if (!editor.commitCurrentEdit)
- throw "GlobalEditorLock : enterEditMode : editor must implement .commitCurrentEdit()";
-
- if (!editor.cancelCurrentEdit)
- throw "GlobalEditorLock : enterEditMode : editor must implement .cancelCurrentEdit()";
-
- currentEditor = editor;
- }
-
- this.leaveEditMode = function(editor)
- {
- if (currentEditor != editor)
- throw "GlobalEditorLock : leaveEditMode() : currentEditor != editor";
-
- currentEditor = null;
- }
-
- this.commitCurrentEdit = function()
- {
- if (currentEditor)
- return currentEditor.commitCurrentEdit();
-
- return true;
- }
-
- this.cancelCurrentEdit = function()
- {
- if (currentEditor)
- currentEditor.cancelCurrentEdit();
- }
-};
-
+(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()
+ {
+ return (currentEditor != null);
+ }
+
+ this.hasLock = function(editor)
+ {
+ return (currentEditor == editor);
+ }
+
+ this.enterEditMode = function(editor)
+ {
+ if (currentEditor != null)
+ throw "GlobalEditorLock : enterEditMode : currentEditor == null";
+
+ if (!editor.commitCurrentEdit)
+ throw "GlobalEditorLock : enterEditMode : editor must implement .commitCurrentEdit()";
+
+ if (!editor.cancelCurrentEdit)
+ throw "GlobalEditorLock : enterEditMode : editor must implement .cancelCurrentEdit()";
+
+ currentEditor = editor;
+ }
+
+ this.leaveEditMode = function(editor)
+ {
+ if (currentEditor != editor)
+ throw "GlobalEditorLock : leaveEditMode() : currentEditor != editor";
+
+ currentEditor = null;
+ }
+
+ this.commitCurrentEdit = function()
+ {
+ if (currentEditor)
+ return currentEditor.commitCurrentEdit();
+
+ return true;
+ }
+
+ this.cancelCurrentEdit = function()
+ {
+ if (currentEditor)
+ currentEditor.cancelCurrentEdit();
+ }
+ };
+
+ // Slick.GlobalEditorLock
+ $.extend(true, window, { Slick: { GlobalEditorLock: GlobalEditorLock }});
+})();
diff --git a/slick.grid.css b/slick.grid.css
index 0df061a..5b5a683 100644
--- a/slick.grid.css
+++ b/slick.grid.css
@@ -126,6 +126,7 @@
padding: 2px;
padding-top: 1px;
padding-left: 1px;
+ white-space: nowrap;
}
.grid-canvas .r .c.editable {
diff --git a/slick.grid.js b/slick.grid.js
index 29bf468..e92ee02 100644
--- a/slick.grid.js
+++ b/slick.grid.js
@@ -11,7 +11,7 @@
*
* KNOWN ISSUES:
* - keyboard navigation doesn't "jump" over unselectable cells for now
-*
+ *
*
* OPTIONS:
* rowHeight - Row height in pixels.
@@ -65,1299 +65,1286 @@
* @param {Object} options Grid options.
*
*/
-function SlickGrid($container,data,columns,options)
-{
- // settings
- var defaults = {
- rowHeight: 25,
- defaultColumnWidth: 80,
- enableAddRow: false,
- leaveSpaceForNewRows: false,
- manualScrolling: false,
- editable: false,
- editOnDoubleClick: false,
- enableCellNavigation: true,
- enableColumnReorder: true,
- asyncEditorLoading: false,
- forceFitColumns: false
- };
-
- var columnDefaults = {
- resizable: true,
- sortable: false,
- formatter: defaultFormatter
- }
-
- // consts
- var CAPACITY = 50;
- var MIN_BUFFER = 5;
- var BUFFER = MIN_BUFFER; // will be set to equal one page
- var POSTPROCESSING_DELAY = 50;
-
- // private
- var uid = "slickgrid_" + Math.round(1000000 * Math.random());
- var self = this;
- var $divHeadersScroller;
- var $divHeaders;
- var $divMainScroller;
- var $divMain;
- var viewportH, viewportW;
- var headerColumnWidthDiff, headerColumnHeightDiff, cellWidthDiff, cellHeightDiff; // padding+border
-
- var currentRow, currentCell;
- var currentCellNode = null;
- var currentEditor = null;
-
- var rowsCache = {};
- var renderedRows = 0;
- var numVisibleRows;
- var lastRenderedScrollTop = 0;
- var currentScrollTop = 0;
- var currentScrollLeft = 0;
- var scrollDir = 1;
- var avgRowRenderTime = 10;
-
- var selectedRows = [];
- var selectedRowsLookup = {};
- var columnsById = {};
-
- // async call handles
- var h_editorLoader = null;
- var h_render = null;
- var h_postrender = null;
- var postProcessedRows = {};
- var rowsToPostProcess = [];
-
- // perf counters
- var counter_rows_rendered = 0;
- var counter_rows_removed = 0;
-
-
- function init() {
- options = $.extend({},defaults,options);
- columnDefaults.width = options.defaultColumnWidth;
-
- $container
- .empty()
- .attr("tabIndex",0)
- .attr("hideFocus",true)
- .css("overflow","hidden")
- .css("outline",0)
- .css("position","relative")
- .addClass(uid);
-
- $divHeadersScroller = $("<div class='slick-header' style='overflow:hidden;position:relative;' />").appendTo($container);
- $divHeaders = $("<div class='slick-header-columns' style='width:100000px' />").appendTo($divHeadersScroller);
- $divMainScroller = $("<div tabIndex='0' hideFocus style='width:100%;overflow-x:auto;overflow-y:scroll;outline:0;position:relative;outline:0px;'>").appendTo($container);
- $divMain = $("<div class='grid-canvas' tabIndex='0' hideFocus />").appendTo($divMainScroller);
-
- // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?)
- // calculate the diff so we can set consistent sizes
- measureCellPaddingAndBorder();
-
- $divMainScroller.height($container.innerHeight() - $divHeadersScroller.outerHeight());
-
- if ($.browser.msie)
- $divMainScroller[0].onselectstart = function() {
- if (event.srcElement.tagName != "INPUT" && event.srcElement.tagName != "TEXTAREA")
- return false;
- };
-
- $divHeaders.disableSelection();
-
- createColumnHeaders();
- setupMoveEvents();
- createCssRules();
- resizeCanvas();
- if (options.forceFitColumns)
- autosizeColumns();
- render();
-
- if (!options.manualScrolling)
- $divMainScroller.bind("scroll", handleScroll);
-
- $container.bind("resize", resizeCanvas);
+(function() {
+ function SlickGrid($container,data,columns,options)
+ {
+ // settings
+ var defaults = {
+ rowHeight: 25,
+ defaultColumnWidth: 80,
+ enableAddRow: false,
+ leaveSpaceForNewRows: false,
+ manualScrolling: false,
+ editable: false,
+ editOnDoubleClick: false,
+ enableCellNavigation: true,
+ enableColumnReorder: true,
+ asyncEditorLoading: false,
+ forceFitColumns: false
+ };
+
+ var columnDefaults = {
+ resizable: true,
+ sortable: false,
+ formatter: defaultFormatter
+ }
- $divMain.bind("keydown", handleKeyDown);
- $divMain.bind("click", handleClick);
- $divMain.bind("dblclick", handleDblClick);
- $divMain.bind("contextmenu", handleContextMenu)
- $divHeadersScroller.bind("contextmenu", handleHeaderContextMenu);
- }
+ // consts
+ var CAPACITY = 50;
+ var MIN_BUFFER = 5;
+ var BUFFER = MIN_BUFFER; // will be set to equal one page
+ var POSTPROCESSING_DELAY = 50, EDITOR_LOAD_DELAY = 100;
+
+ // private
+ var uid = "slickgrid_" + Math.round(1000000 * Math.random());
+ var self = this;
+ var $divHeadersScroller;
+ var $divHeaders;
+ var $divMainScroller;
+ var $divMain;
+ var viewportH, viewportW;
+ var headerColumnWidthDiff, headerColumnHeightDiff, cellWidthDiff, cellHeightDiff; // padding+border
+
+ var currentRow, currentCell;
+ var currentCellNode = null;
+ var currentEditor = null;
+
+ var rowsCache = {};
+ var renderedRows = 0;
+ var numVisibleRows;
+ var lastRenderedScrollTop = 0;
+ var currentScrollTop = 0;
+ var currentScrollLeft = 0;
+ var scrollDir = 1;
+ var avgRowRenderTime = 10;
+
+ var selectedRows = [];
+ var selectedRowsLookup = {};
+ var columnsById = {};
+
+ // async call handles
+ var h_editorLoader = null;
+ var h_render = null;
+ var h_postrender = null;
+ var postProcessedRows = {};
+ var rowsToPostProcess = [];
+
+ // perf counters
+ var counter_rows_rendered = 0;
+ var counter_rows_removed = 0;
+
+
+ function init() {
+ options = $.extend({},defaults,options);
+ columnDefaults.width = options.defaultColumnWidth;
+
+ $container
+ .empty()
+ .attr("tabIndex",0)
+ .attr("hideFocus",true)
+ .css("overflow","hidden")
+ .css("outline",0)
+ .css("position","relative")
+ .addClass(uid);
+
+ $divHeadersScroller = $("<div class='slick-header' style='overflow:hidden;position:relative;' />").appendTo($container);
+ $divHeaders = $("<div class='slick-header-columns' style='width:100000px' />").appendTo($divHeadersScroller);
+ $divMainScroller = $("<div tabIndex='0' hideFocus style='width:100%;overflow-x:auto;overflow-y:scroll;outline:0;position:relative;outline:0px;'>").appendTo($container);
+ $divMain = $("<div class='grid-canvas' tabIndex='0' hideFocus />").appendTo($divMainScroller);
+
+ // header columns and cells may have different padding/border skewing width calculations (box-sizing, hello?)
+ // calculate the diff so we can set consistent sizes
+ measureCellPaddingAndBorder();
+
+ $divMainScroller.height($container.innerHeight() - $divHeadersScroller.outerHeight());
+
+ if ($.browser.msie)
+ $divMainScroller[0].onselectstart = function() {
+ if (event.srcElement.tagName != "INPUT" && event.srcElement.tagName != "TEXTAREA")
+ return false;
+ };
+
+ $divHeaders.disableSelection();
- function createColumnHeaders() {
- for (var i = 0; i < columns.length; i++) {
- var m = columns[i] = $.extend({},columnDefaults,columns[i]);
- columnsById[m.id] = i;
-
- var header = $("<div class='slick-header-column' cell=" + i + " id='" + m.id + "' />")
- .html(m.name)
- .width(m.width - headerColumnWidthDiff)
- .appendTo($divHeaders);
-
- if (m.sortable) header.append("<span class='slick-sort-indicator' />")
- if (m.resizable) header.append("<div class='slick-resizable-handle' />");
+ createColumnHeaders();
+ setupMoveEvents();
+ createCssRules();
+ resizeCanvas();
+ if (options.forceFitColumns)
+ autosizeColumns();
+ render();
+
+ if (!options.manualScrolling)
+ $divMainScroller.bind("scroll", handleScroll);
+
+ $container.bind("resize", resizeCanvas);
+
+ $divMain.bind("keydown", handleKeyDown);
+ $divMain.bind("click", handleClick);
+ $divMain.bind("dblclick", handleDblClick);
+ $divMain.bind("contextmenu", handleContextMenu)
+ $divHeadersScroller.bind("contextmenu", handleHeaderContextMenu);
}
- setupColumnSort();
- setupColumnResizeEvents();
- if (options.enableColumnReorder)
- setupColumnReorderEvents();
- }
-
- function setupColumnSort() {
- $divHeaders.click(function(e) {
- var $col = $(e.target);
- if (!$col.hasClass("slick-header-column") || !columns[columnsById[$col.attr("id")]].sortable)
- return;
-
- if (currentEditor && !commitCurrentEdit()) return;
-
- if ($col.is(".slick-header-column-sorted"))
- {
- $col.find(".slick-sort-indicator").toggleClass("slick-sort-indicator-asc").toggleClass("slick-sort-indicator-desc");
- }
- else
- {
- $divHeaders.children().removeClass("slick-header-column-sorted");
- $divHeaders.find(".slick-sort-indicator").removeClass("slick-sort-indicator-asc slick-sort-indicator-desc");
- $col.addClass("slick-header-column-sorted");
- $col.find(".slick-sort-indicator").addClass("slick-sort-indicator-asc");
- }
-
- if (self.onSort)
- self.onSort(columns[columnsById[$col.attr("id")]], $col.find(".slick-sort-indicator").hasClass("slick-sort-indicator-asc"));
- })
- }
-
- function setupColumnReorderEvents() {
- $divHeaders.sortable({
- axis: "x",
- cursor: "default",
- tolerance: "intersect",
- helper: "clone",
- placeholder: "slick-sortable-placeholder slick-header-column",
- forcePlaceholderSize: true,
- start: function(e, ui) { $(ui.helper).addClass("slick-header-column-active") },
- beforeStop: function(e, ui) { $(ui.helper).removeClass("slick-header-column-active") },
- stop: function(e, ui) {
- if (currentEditor && !commitCurrentEdit()) {
- $(this).sortable("cancel");
- return;
- }
+ function createColumnHeaders() {
+ for (var i = 0; i < columns.length; i++) {
+ var m = columns[i] = $.extend({},columnDefaults,columns[i]);
+ columnsById[m.id] = i;
- var newOrder = $divHeaders.sortable("toArray"), lookup = {};
- for (var i=0; i<columns.length; i++) {
- lookup[columns[i].id] = columns[i];
- }
-
- for (var i=0; i<newOrder.length; i++) {
- columnsById[newOrder[i]] = i;
- columns[i] = lookup[newOrder[i]];
- }
+ var header = $("<div class='slick-header-column' cell=" + i + " id='" + m.id + "' />")
+ .html(m.name)
+ .width(m.width - headerColumnWidthDiff)
+ .appendTo($divHeaders);
- removeAllRows();
- removeCssRules();
- createCssRules();
- render();
+ if (m.sortable) header.append("<span class='slick-sort-indicator' />")
+ if (m.resizable) header.append("<div class='slick-resizable-handle' />");
+ }
+
+ setupColumnSort();
+ setupColumnResizeEvents();
+ if (options.enableColumnReorder)
+ setupColumnReorderEvents();
+ }
+
+ function setupColumnSort() {
+ $divHeaders.click(function(e) {
+ var $col = $(e.target);
+ if (!$col.hasClass("slick-header-column") || !columns[columnsById[$col.attr("id")]].sortable)
+ return;
- if (self.onColumnsReordered)
- self.onColumnsReordered();
-
- e.stopPropagation();
- }
- })
- }
+ if (currentEditor && !commitCurrentEdit()) return;
- function setupColumnResizeEvents() {
- $divHeaders
- .find(".slick-resizable-handle")
- .bind('dragstart', function(e) {
- var $col = $(this).parent();
- var colId = $col.attr("id");
- if (!columns[columnsById[colId]].resizable) return false;
- if (currentEditor && !commitCurrentEdit()) return false;
-
- $col
- .data("colId", colId)
- .data("width", $col.width())
- .data("pageX", e.pageX)
- .addClass("slick-header-column-active");
- })
- .bind('drag', function(e) {
- var $col = $(this).parent(), w = $col.data("width") - $col.data("pageX") + e.pageX;
- var cell = columnsById[$col.data("colId")];
- var m = columns[cell];
- if (m.minWidth) w = Math.max(m.minWidth - headerColumnWidthDiff,w);
- if (m.maxWidth) w = Math.min(m.maxWidth - headerColumnWidthDiff,w);
- $col.css({ width: Math.max(0, w) });
- })
- .bind('dragend', function(e) {
- var $col = $(this).parent();
- var cell = columnsById[$col.data("colId")];
- $col.removeClass("slick-header-column-active");
- columns[cell].width = $col.outerWidth();
-
- if (options.forceFitColumns)
- autosizeColumns(columns[cell]);
- else {
- updateColumnWidth(cell, $col.outerWidth());
- resizeCanvas();
- }
-
- if (columns[cell].rerenderOnResize)
- removeAllRows();
-
- render();
- })
- }
-
- function setupMoveEvents() {
- $divMain
- .bind("beforedragstart", function(e) {
- var $cell = $(e.target).closest(".c");
- if ($cell.length == 0) return false;
- if (parseInt($cell.parent().attr("row")) >= data.length) return false;
- var colDef = columns[$cell.attr("cell")];
- if (colDef.behavior != "move") return false;
- })
- .bind("dragstart", function(e) {
- if (currentEditor && !commitCurrentEdit()) return false;
-
- var row = parseInt($(e.target).closest(".r").attr("row"));
+ if ($col.is(".slick-header-column-sorted"))
+ {
+ $col.find(".slick-sort-indicator").toggleClass("slick-sort-indicator-asc").toggleClass("slick-sort-indicator-desc");
+ }
+ else
+ {
+ $divHeaders.children().removeClass("slick-header-column-sorted");
+ $divHeaders.find(".slick-sort-indicator").removeClass("slick-sort-indicator-asc slick-sort-indicator-desc");
+ $col.addClass("slick-header-column-sorted");
+ $col.find(".slick-sort-indicator").addClass("slick-sort-indicator-asc");
+ }
- if (!selectedRowsLookup[row])
- setSelectedRows([row]);
-
- var $selectionProxy = $("<div class='slick-reorder-proxy'/>");
- $selectionProxy
- .css("position", "absolute")
- .css("zIndex", "99999")
- .css("width", $(this).innerWidth())
- .css("height", options.rowHeight*selectedRows.length)
- .appendTo($divMainScroller);
-
- $(this)
- .data("selectionProxy", $selectionProxy)
- .data("insertBefore", -1);
-
- var $guide = $("<div class='slick-reorder-guide'/>");
- $guide
- .css("position", "absolute")
- .css("zIndex", "99998")
- .css("width", $(this).innerWidth())
- .css("top", -1000)
- .appendTo($divMainScroller);
-
- return $guide;
- })
- .bind("drag", function(e) {
- var top = e.clientY - $(this).offset().top;
- $(this).data("selectionProxy").css("top",top-5);
-
- var insertBefore = Math.max(0,Math.min(Math.round(top/options.rowHeight),data.length));
- if (insertBefore != $(this).data("insertBefore")) {
- if (self.onBeforeMoveRows && self.onBeforeMoveRows(selectedRows.concat(),insertBefore) === false)
- $(e.dragProxy).css("top", -1000);
- else
- $(e.dragProxy).css("top",insertBefore*options.rowHeight);
- $(this).data("insertBefore", insertBefore);
- }
- })
- .bind("dragend", function(e) {
- $(e.dragProxy).remove();
- $(this).data("selectionProxy").remove();
- var insertBefore = $(this).data("insertBefore");
- $(this).removeData("selectionProxy").removeData("insertBefore");
- if (self.onMoveRows) self.onMoveRows(selectedRows.concat(),insertBefore);
- })
- }
-
- function measureCellPaddingAndBorder() {
- var tmp = $("<div class='slick-header-column cell='' id='' style='visibility:hidden'>-</div>").appendTo($divHeaders);
- headerColumnWidthDiff = tmp.outerWidth() - tmp.width();
- headerColumnHeightDiff = tmp.outerHeight() - tmp.height();
- tmp.remove();
-
- var r = $("<div class='r' />").appendTo($divMain);
- tmp = $("<div class='c' cell='' id='' style='visibility:hidden'>-</div>").appendTo(r);
- cellWidthDiff = tmp.outerWidth() - tmp.width();
- cellHeightDiff = tmp.outerHeight() - tmp.height();
- r.remove();
- }
-
- function createCssRules() {
- var $style = $("<style type='text/css' rel='stylesheet' lib='slickgrid' />").appendTo($("head"));
- $.rule(".grid-canvas .r .c { height:" + (options.rowHeight - cellHeightDiff) + "px;}").appendTo($style);
-
- for (var i = 0; i < columns.length; i++) {
- $.rule(
- "." + uid + " .grid-canvas .c" + i + " { " +
- "width:" + (columns[i].width - cellWidthDiff) + "px; " +
- "display: " + (columns[i].hidden ? "none" : "block") +
- " }").appendTo($style);
+ if (self.onSort)
+ self.onSort(columns[columnsById[$col.attr("id")]], $col.find(".slick-sort-indicator").hasClass("slick-sort-indicator-asc"));
+ })
}
- }
-
- function removeCssRules() {
- $("style[lib=slickgrid]").remove();
- }
- function destroy() {
- if (currentEditor)
- cancelCurrentEdit();
-
- $divHeaders.sortable("destroy");
- $container.unbind("resize", resizeCanvas);
- removeCssRules();
+ function setupColumnReorderEvents() {
+ $divHeaders.sortable({
+ axis: "x",
+ cursor: "default",
+ tolerance: "intersect",
+ helper: "clone",
+ placeholder: "slick-sortable-placeholder slick-header-column",
+ forcePlaceholderSize: true,
+ start: function(e, ui) { $(ui.helper).addClass("slick-header-column-active") },
+ beforeStop: function(e, ui) { $(ui.helper).removeClass("slick-header-column-active") },
+ stop: function(e, ui) {
+ if (currentEditor && !commitCurrentEdit()) {
+ $(this).sortable("cancel");
+ return;
+ }
+
+ var newOrder = $divHeaders.sortable("toArray"), lookup = {};
+ for (var i=0; i<columns.length; i++) {
+ lookup[columns[i].id] = columns[i];
+ }
+
+ for (var i=0; i<newOrder.length; i++) {
+ columnsById[newOrder[i]] = i;
+ columns[i] = lookup[newOrder[i]];
+ }
+
+ removeAllRows();
+ removeCssRules();
+ createCssRules();
+ render();
+
+ if (self.onColumnsReordered)
+ self.onColumnsReordered();
+
+ e.stopPropagation();
+ }
+ })
+ }
- $container.empty().removeClass(uid);
- }
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // General
+ function setupColumnResizeEvents() {
+ $divHeaders
+ .find(".slick-resizable-handle")
+ .bind('dragstart', function(e) {
+ var $col = $(this).parent();
+ var colId = $col.attr("id");
+ if (!columns[columnsById[colId]].resizable) return false;
+ if (currentEditor && !commitCurrentEdit()) return false;
+
+ $col
+ .data("colId", colId)
+ .data("width", $col.width())
+ .data("pageX", e.pageX)
+ .addClass("slick-header-column-active");
+ })
+ .bind('drag', function(e) {
+ var $col = $(this).parent(), w = $col.data("width") - $col.data("pageX") + e.pageX;
+ var cell = columnsById[$col.data("colId")];
+ var m = columns[cell];
+ if (m.minWidth) w = Math.max(m.minWidth - headerColumnWidthDiff,w);
+ if (m.maxWidth) w = Math.min(m.maxWidth - headerColumnWidthDiff,w);
+ $col.css({ width: Math.max(0, w) });
+ })
+ .bind('dragend', function(e) {
+ var $col = $(this).parent();
+ var cell = columnsById[$col.data("colId")];
+ $col.removeClass("slick-header-column-active");
+ columns[cell].width = $col.outerWidth();
+
+ if (options.forceFitColumns)
+ autosizeColumns(columns[cell]);
+ else {
+ updateColumnWidth(cell, $col.outerWidth());
+ resizeCanvas();
+ }
+
+ if (columns[cell].rerenderOnResize)
+ removeAllRows();
+
+ render();
+ })
+ }
- function getColumnIndex(id) {
- return columnsById[id];
- }
+ function setupMoveEvents() {
+ $divMain
+ .bind("beforedragstart", function(e) {
+ var $cell = $(e.target).closest(".c");
+ if ($cell.length == 0) return false;
+ if (parseInt($cell.parent().attr("row")) >= data.length) return false;
+ var colDef = columns[$cell.attr("cell")];
+ if (colDef.behavior != "move") return false;
+ })
+ .bind("dragstart", function(e) {
+ if (currentEditor && !commitCurrentEdit()) return false;
+
+ var row = parseInt($(e.target).closest(".r").attr("row"));
+
+ if (!selectedRowsLookup[row])
+ setSelectedRows([row]);
+
+ var $selectionProxy = $("<div class='slick-reorder-proxy'/>");
+ $selectionProxy
+ .css("position", "absolute")
+ .css("zIndex", "99999")
+ .css("width", $(this).innerWidth())
+ .css("height", options.rowHeight*selectedRows.length)
+ .appendTo($divMainScroller);
- function autosizeColumns(columnToHold) {
- var availWidth = viewportW-$.getScrollbarWidth();
- var total = 0;
- var existingTotal = 0;
- var minWidth = Math.max(headerColumnWidthDiff,cellWidthDiff);
-
- for (var i = 0; i < columns.length; i++) {
- if (!columns[i].hidden)
- existingTotal += columns[i].width;
+ $(this)
+ .data("selectionProxy", $selectionProxy)
+ .data("insertBefore", -1);
+
+ var $guide = $("<div class='slick-reorder-guide'/>");
+ $guide
+ .css("position", "absolute")
+ .css("zIndex", "99998")
+ .css("width", $(this).innerWidth())
+ .css("top", -1000)
+ .appendTo($divMainScroller);
+
+ return $guide;
+ })
+ .bind("drag", function(e) {
+ var top = e.clientY - $(this).offset().top;
+ $(this).data("selectionProxy").css("top",top-5);
+
+ var insertBefore = Math.max(0,Math.min(Math.round(top/options.rowHeight),data.length));
+ if (insertBefore != $(this).data("insertBefore")) {
+ if (self.onBeforeMoveRows && self.onBeforeMoveRows(selectedRows.concat(),insertBefore) === false)
+ $(e.dragProxy).css("top", -1000);
+ else
+ $(e.dragProxy).css("top",insertBefore*options.rowHeight);
+ $(this).data("insertBefore", insertBefore);
+ }
+ })
+ .bind("dragend", function(e) {
+ $(e.dragProxy).remove();
+ $(this).data("selectionProxy").remove();
+ var insertBefore = $(this).data("insertBefore");
+ $(this).removeData("selectionProxy").removeData("insertBefore");
+ if (self.onMoveRows) self.onMoveRows(selectedRows.concat(),insertBefore);
+ })
}
- total = existingTotal;
-
- removeAllRows();
-
- // shrink
- var workdone = true;
- while (total > availWidth && workdone) {
- workdone = false;
- for (var i = 0; i < columns.length && total > availWidth; i++) {
- var c = columns[i];
- if (c.hidden || !c.resizable || c.minWidth == c.width || c.width == minWidth || (columnToHold && columnToHold.id == c.id)) continue;
- total -= 1;
- c.width -= 1;
- workdone = true;
- }
+ function measureCellPaddingAndBorder() {
+ var tmp = $("<div class='slick-header-column cell='' id='' style='visibility:hidden'>-</div>").appendTo($divHeaders);
+ headerColumnWidthDiff = tmp.outerWidth() - tmp.width();
+ headerColumnHeightDiff = tmp.outerHeight() - tmp.height();
+ tmp.remove();
+
+ var r = $("<div class='r' />").appendTo($divMain);
+ tmp = $("<div class='c' cell='' id='' style='visibility:hidden'>-</div>").appendTo(r);
+ cellWidthDiff = tmp.outerWidth() - tmp.width();
+ cellHeightDiff = tmp.outerHeight() - tmp.height();
+ r.remove();
}
- // shrink the column being "held" as a last resort
- if (total > availWidth && columnToHold && columnToHold.resizable && !columnToHold.hidden) {
- while (total > availWidth) {
- if (columnToHold.minWidth == columnToHold.width || columnToHold.width == minWidth) break;
- total -= 1;
- columnToHold.width -= 1;
+ function createCssRules() {
+ var $style = $("<style type='text/css' rel='stylesheet' lib='slickgrid' />").appendTo($("head"));
+ $.rule(".grid-canvas .r .c { height:" + (options.rowHeight - cellHeightDiff) + "px;}").appendTo($style);
+
+ for (var i = 0; i < columns.length; i++) {
+ $.rule(
+ "." + uid + " .grid-canvas .c" + i + " { " +
+ "width:" + (columns[i].width - cellWidthDiff) + "px; " +
+ "display: " + (columns[i].hidden ? "none" : "block") +
+ " }").appendTo($style);
}
}
- // grow
- workdone = true;
- while (total < availWidth && workdone) {
- workdone = false;
- for (var i = 0; i < columns.length && total < availWidth; i++) {
- var c = columns[i];
- if (c.hidden || !c.resizable || c.maxWidth == c.width || (columnToHold && columnToHold.id == c.id)) continue;
- total += 1;
- c.width += 1;
- workdone = true;
- }
+ function removeCssRules() {
+ $("style[lib=slickgrid]").remove();
}
-
- // grow the column being "held" as a last resort
- if (total < availWidth && columnToHold && columnToHold.resizable && !columnToHold.hidden) {
- while (total < availWidth) {
- if (columnToHold.maxWidth == columnToHold.width) break;
- total += 1;
- columnToHold.width += 1;
- }
- }
-
- for (var i=0; i<columns.length; i++) {
- updateColumnWidth(i, columns[i].width);
+
+ function destroy() {
+ if (currentEditor)
+ cancelCurrentEdit();
+
+ $divHeaders.sortable("destroy");
+ $container.unbind("resize", resizeCanvas);
+ removeCssRules();
+
+ $container.empty().removeClass(uid);
}
- resizeCanvas();
- }
-
- function updateColumnWidth(index,width) {
- columns[index].width = width;
- $divHeaders.find(".slick-header-column[id=" + columns[index].id + "]").css("width",width - headerColumnWidthDiff);
- $.rule("." + uid + " .grid-canvas .c" + index, "style[lib=slickgrid]").css("width", (columns[index].width - cellWidthDiff) + "px");
- }
-
- function setColumnVisibility(column,visible) {
- var index = columnsById[column.id];
- columns[index].hidden = !visible;
- resizeCanvas();
- var header = $divHeaders.find("[id=" + columns[index].id + "]");
- header.css("display", visible?"block":"none");
- $.rule("." + uid + " .grid-canvas .c" + index, "style[lib=slickgrid]").css("display", visible?"block":"none");
-
- if (options.forceFitColumns)
- autosizeColumns(columns[index]);
- }
-
- function getSelectedRows() {
- return selectedRows.concat();
- }
-
- function setSelectedRows(rows) {
- if (GlobalEditorLock.isEditing() && !GlobalEditorLock.hasLock(self))
- throw "Grid : setSelectedRows : cannot set selected rows when somebody else has an edit lock";
-
- var lookup = {};
- for (var i=0; i<rows.length; i++)
- lookup[rows[i]] = true;
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // General
- // unselect old rows
- for (var i=0; i<selectedRows.length; i++) {
- var row = selectedRows[i];
- if (rowsCache[row] && !lookup[row])
- $(rowsCache[row]).removeClass("selected");
+ function getColumnIndex(id) {
+ return columnsById[id];
}
-
- // select new ones
- for (var i=0; i<rows.length; i++) {
- var row = rows[i];
- if (rowsCache[row] && !selectedRowsLookup[row])
- $(rowsCache[row]).addClass("selected");
+
+ function autosizeColumns(columnToHold) {
+ var availWidth = viewportW-$.getScrollbarWidth();
+ var total = 0;
+ var existingTotal = 0;
+ var minWidth = Math.max(headerColumnWidthDiff,cellWidthDiff);
+
+ for (var i = 0; i < columns.length; i++) {
+ if (!columns[i].hidden)
+ existingTotal += columns[i].width;
+ }
+
+ total = existingTotal;
+
+ removeAllRows();
+
+ // shrink
+ var workdone = true;
+ while (total > availWidth && workdone) {
+ workdone = false;
+ for (var i = 0; i < columns.length && total > availWidth; i++) {
+ var c = columns[i];
+ if (c.hidden || !c.resizable || c.minWidth == c.width || c.width == minWidth || (columnToHold && columnToHold.id == c.id)) continue;
+ total -= 1;
+ c.width -= 1;
+ workdone = true;
+ }
+ }
+
+ // shrink the column being "held" as a last resort
+ if (total > availWidth && columnToHold && columnToHold.resizable && !columnToHold.hidden) {
+ while (total > availWidth) {
+ if (columnToHold.minWidth == columnToHold.width || columnToHold.width == minWidth) break;
+ total -= 1;
+ columnToHold.width -= 1;
+ }
+ }
+
+ // grow
+ workdone = true;
+ while (total < availWidth && workdone) {
+ workdone = false;
+ for (var i = 0; i < columns.length && total < availWidth; i++) {
+ var c = columns[i];
+ if (c.hidden || !c.resizable || c.maxWidth == c.width || (columnToHold && columnToHold.id == c.id)) continue;
+ total += 1;
+ c.width += 1;
+ workdone = true;
+ }
+ }
+
+ // grow the column being "held" as a last resort
+ if (total < availWidth && columnToHold && columnToHold.resizable && !columnToHold.hidden) {
+ while (total < availWidth) {
+ if (columnToHold.maxWidth == columnToHold.width) break;
+ total += 1;
+ columnToHold.width += 1;
+ }
+ }
+
+ for (var i=0; i<columns.length; i++) {
+ updateColumnWidth(i, columns[i].width);
+ }
+
+ resizeCanvas();
}
-
- selectedRows = rows.concat();
- selectedRowsLookup = lookup;
- }
-
- function setOptions(args) {
- if (currentEditor && !commitCurrentEdit())
- return;
- makeSelectedCellNormal();
+ function updateColumnWidth(index,width) {
+ columns[index].width = width;
+ $divHeaders.find(".slick-header-column[id=" + columns[index].id + "]").css("width",width - headerColumnWidthDiff);
+ $.rule("." + uid + " .grid-canvas .c" + index, "style[lib=slickgrid]").css("width", (columns[index].width - cellWidthDiff) + "px");
+ }
- if (options.enableAddRow != args.enableAddRow)
- removeRow(data.length);
+ function setColumnVisibility(column,visible) {
+ var index = columnsById[column.id];
+ columns[index].hidden = !visible;
+ resizeCanvas();
+ var header = $divHeaders.find("[id=" + columns[index].id + "]");
+ header.css("display", visible?"block":"none");
+ $.rule("." + uid + " .grid-canvas .c" + index, "style[lib=slickgrid]").css("display", visible?"block":"none");
- options = $.extend(options,args);
-
- render();
- }
+ if (options.forceFitColumns)
+ autosizeColumns(columns[index]);
+ }
- function setData(newData,scrollToTop)
- {
- removeAllRows();
- data = newData;
- if (scrollToTop)
- $divMainScroller.scrollTop(0);
- }
+ function getSelectedRows() {
+ return selectedRows.concat();
+ }
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Rendering / Scrolling
-
- function defaultFormatter(row, cell, value, columnDef, dataContext) {
- return (value == null || value == undefined) ? "" : value;
- }
-
- function appendRowHtml(stringArray,row) {
- var d = data[row];
- var dataLoading = row < data.length && !d;
- var css = "r" + (dataLoading ? " loading" : "") + (selectedRowsLookup[row] ? " selected" : "");
+ function setSelectedRows(rows) {
+ if (Slick.GlobalEditorLock.isEditing() && !Slick.GlobalEditorLock.hasLock(self))
+ throw "Grid : setSelectedRows : cannot set selected rows when somebody else has an edit lock";
+
+ var lookup = {};
+ for (var i=0; i<rows.length; i++)
+ lookup[rows[i]] = true;
+
+ // unselect old rows
+ for (var i=0; i<selectedRows.length; i++) {
+ var row = selectedRows[i];
+ if (rowsCache[row] && !lookup[row])
+ $(rowsCache[row]).removeClass("selected");
+ }
+
+ // select new ones
+ for (var i=0; i<rows.length; i++) {
+ var row = rows[i];
+ if (rowsCache[row] && !selectedRowsLookup[row])
+ $(rowsCache[row]).addClass("selected");
+ }
+
+ selectedRows = rows.concat();
+ selectedRowsLookup = lookup;
+ }
+
+ function setOptions(args) {
+ if (currentEditor && !commitCurrentEdit())
+ return;
+
+ makeSelectedCellNormal();
+
+ if (options.enableAddRow != args.enableAddRow)
+ removeRow(data.length);
+
+ options = $.extend(options,args);
+
+ render();
+ }
- stringArray.push("<div class='" + css + "' row='" + row + "' style='top:" + (options.rowHeight*row) + "px'>");
+ function setData(newData,scrollToTop)
+ {
+ removeAllRows();
+ data = newData;
+ if (scrollToTop)
+ $divMainScroller.scrollTop(0);
+ }
- for (var i=0, cols=columns.length; i<cols; i++) {
- var m = columns[i];
-
- stringArray.push("<div " + (m.unselectable ? "" : "hideFocus tabIndex=0 ") + "class='c c" + i + (m.cssClass ? " " + m.cssClass : "") + "' cell=" + i + ">");
-
- // if there is a corresponding row (if not, this is the Add New row or this data hasn't been loaded yet)
- if (d && row < data.length)
- stringArray.push(m.formatter(row, i, d[m.field], m, d));
-
- stringArray.push("</div>");
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Rendering / Scrolling
+
+ function defaultFormatter(row, cell, value, columnDef, dataContext) {
+ return (value == null || value == undefined) ? "" : value;
}
-
- stringArray.push("</div>");
- }
- function getRowHtml(row) {
- var html = [];
- appendRowHtml(html,row);
- return html.join("");
- }
+ function appendRowHtml(stringArray,row) {
+ var d = data[row];
+ var dataLoading = row < data.length && !d;
+ var css = "r" + (dataLoading ? " loading" : "") + (selectedRowsLookup[row] ? " selected" : "");
+
+ stringArray.push("<div class='" + css + "' row='" + row + "' style='top:" + (options.rowHeight*row) + "px'>");
+
+ for (var i=0, cols=columns.length; i<cols; i++) {
+ var m = columns[i];
+
+ stringArray.push("<div " + (m.unselectable ? "" : "hideFocus tabIndex=0 ") + "class='c c" + i + (m.cssClass ? " " + m.cssClass : "") + "' cell=" + i + ">");
- function cleanupRows(visibleFrom,visibleTo) {
- var rowsBefore = renderedRows;
- var parentNode = $divMain[0];
- for (var i in rowsCache) {
- if ((i < visibleFrom || i > visibleTo) && i != currentRow) {
- parentNode.removeChild(rowsCache[i]);
- delete rowsCache[i];
- delete postProcessedRows[i];
- renderedRows--;
- counter_rows_removed++;
+ // if there is a corresponding row (if not, this is the Add New row or this data hasn't been loaded yet)
+ if (d && row < data.length)
+ stringArray.push(m.formatter(row, i, d[m.field], m, d));
+
+ stringArray.push("</div>");
}
+
+ stringArray.push("</div>");
}
- }
-
- function removeAllRows() {
- $divMain[0].innerHTML = "";
- rowsCache= {};
- postProcessedRows = {};
- counter_rows_removed += renderedRows;
- renderedRows = 0;
- }
-
- function removeRow(row) {
- var node = rowsCache[row];
- if (!node) return;
-
- if (currentEditor && currentRow == row)
- throw "Grid : removeRow : Cannot remove a row that is currently in edit mode";
- // if we're removing rows, we're probably not scrolling
- scrollDir = 0;
+ function getRowHtml(row) {
+ var html = [];
+ appendRowHtml(html,row);
+ return html.join("");
+ }
- node.parentNode.removeChild(node);
- node = null;
- delete rowsCache[row];
- delete postProcessedRows[row];
- renderedRows--;
- counter_rows_removed++;
- }
-
- function removeRows(rows) {
- if (!rows || !rows.length) return;
- scrollDir = 0;
- var nodes = [];
- for (var i=0, rl=rows.length; i<rl; i++) {
- if (currentEditor && currentRow == i)
- throw "Grid : removeRow : Cannot remove a row that is currently in edit mode";
-
- if (rowsCache[rows[i]])
- nodes.push(rows[i]);
+ function cleanupRows(visibleFrom,visibleTo) {
+ var rowsBefore = renderedRows;
+ var parentNode = $divMain[0];
+ for (var i in rowsCache) {
+ if ((i < visibleFrom || i > visibleTo) && i != currentRow) {
+ parentNode.removeChild(rowsCache[i]);
+ delete rowsCache[i];
+ delete postProcessedRows[i];
+ renderedRows--;
+ counter_rows_removed++;
+ }
+ }
}
- if (renderedRows > 10 && nodes.length == renderedRows) {
+ function removeAllRows() {
$divMain[0].innerHTML = "";
rowsCache= {};
postProcessedRows = {};
counter_rows_removed += renderedRows;
- renderedRows = 0;
- } else {
- for (var i=0, nl=nodes.length; i<nl; i++) {
- var node = rowsCache[nodes[i]];
- node.parentNode.removeChild(node);
- delete rowsCache[nodes[i]];
- delete postProcessedRows[nodes[i]];
- renderedRows--;
- counter_rows_removed++;
- }
- }
- }
+ renderedRows = 0;
+ }
- function updateCell(row,cell) {
- if (!rowsCache[row]) return;
- var $cell = $(rowsCache[row]).find(".c[cell=" + cell + "]");
- if ($cell.length == 0) return;
-
- var m = columns[cell], d = data[row];
- if (currentEditor && currentRow == row && currentCell == cell)
- currentEditor.setValue(d[m.field]);
- else {
- $cell[0].innerHTML = d ? m.formatter(row, cell, d[m.field], m, d) : "";
- invalidatePostProcessingResults(row);
+ function removeRow(row) {
+ removeRows([row]);
}
- }
-
- function updateRow(row) {
- if (!rowsCache[row]) return;
- // todo: perf: iterate over direct children?
- $(rowsCache[row]).find(".c").each(function(i) {
- var m = columns[i];
- if (row == currentRow && i == currentCell && currentEditor)
- currentEditor.setValue(data[currentRow][m.field]);
- else if (data[row])
- this.innerHTML = m.formatter(row, i, data[row][m.field], m, data[row]);
- else
- this.innerHTML = "";
- });
-
- invalidatePostProcessingResults(row);
- }
-
- function resizeCanvas() {
- viewportW = $divMainScroller.innerWidth();
- viewportH = $divMainScroller.innerHeight();
- BUFFER = numVisibleRows = Math.ceil(viewportH / options.rowHeight);
- CAPACITY = Math.max(50, numVisibleRows + 2*BUFFER);
-
- var totalWidth = 0;
- for (var i=0; i<columns.length; i++) {
- if (columns[i].hidden != true)
- totalWidth += columns[i].width;
+ function removeRows(rows) {
+ if (!rows || !rows.length) return;
+ scrollDir = 0;
+ var nodes = [];
+ for (var i=0, rl=rows.length; i<rl; i++) {
+ if (currentEditor && currentRow == i)
+ throw "Grid : removeRow : Cannot remove a row that is currently in edit mode";
+
+ if (rowsCache[rows[i]])
+ nodes.push(rows[i]);
+ }
+
+ if (renderedRows > 10 && nodes.length == renderedRows) {
+ removeAllRows();
+ } else {
+ for (var i=0, nl=nodes.length; i<nl; i++) {
+ var node = rowsCache[nodes[i]];
+ node.parentNode.removeChild(node);
+ delete rowsCache[nodes[i]];
+ delete postProcessedRows[nodes[i]];
+ renderedRows--;
+ counter_rows_removed++;
+ }
+ }
}
- $divMain.width(totalWidth);
-
- var newHeight = Math.max(options.rowHeight * (data.length - 1 + (options.leaveSpaceForNewRows?numVisibleRows-1:0)), viewportH - $.getScrollbarWidth());
- $divMainScroller.height( $container.innerHeight() - $divHeadersScroller.outerHeight() );
- // browsers sometimes do not adjust scrollTop/scrollHeight when the height of contained objects changes
- if ($divMainScroller.scrollTop() > newHeight - $divMainScroller.height() + $.getScrollbarWidth()) {
- $divMainScroller.scrollTop(newHeight - $divMainScroller.height() + $.getScrollbarWidth());
+ function updateCell(row,cell) {
+ if (!rowsCache[row]) return;
+ var $cell = $(rowsCache[row]).find(".c[cell=" + cell + "]");
+ if ($cell.length == 0) return;
+
+ var m = columns[cell], d = data[row];
+ if (currentEditor && currentRow == row && currentCell == cell)
+ currentEditor.setValue(d[m.field]);
+ else {
+ $cell[0].innerHTML = d ? m.formatter(row, cell, d[m.field], m, d) : "";
+ invalidatePostProcessingResults(row);
+ }
}
- $divMain.height(newHeight);
-
- render();
- }
- function updateRowCount() {
- // remove the rows that are now outside of the data range
- // this helps avoid redundant calls to .removeRow() when the size of the data decreased by thousands of rows
- var parentNode = $divMain[0];
- var l = options.enableAddRow ? data.length : data.length - 1;
- for (var i in rowsCache) {
- if (i >= l) {
- parentNode.removeChild(rowsCache[i]);
- delete rowsCache[i];
- delete postProcessedRows[i];
- renderedRows--;
- counter_rows_removed++;
- }
+ function updateRow(row) {
+ if (!rowsCache[row]) return;
+
+ // todo: perf: iterate over direct children?
+ $(rowsCache[row]).find(".c").each(function(i) {
+ var m = columns[i];
+ if (row == currentRow && i == currentCell && currentEditor)
+ currentEditor.setValue(data[currentRow][m.field]);
+ else if (data[row])
+ this.innerHTML = m.formatter(row, i, data[row][m.field], m, data[row]);
+ else
+ this.innerHTML = "";
+ });
+
+ invalidatePostProcessingResults(row);
}
-
- var newHeight = Math.max(options.rowHeight * (data.length - 1 + (options.leaveSpaceForNewRows?numVisibleRows-1:0)), viewportH - $.getScrollbarWidth());
-
- // browsers sometimes do not adjust scrollTop/scrollHeight when the height of contained objects changes
- if ($divMainScroller.scrollTop() > newHeight - $divMainScroller.height() + $.getScrollbarWidth())
- $divMainScroller.scrollTop(newHeight - $divMainScroller.height() + $.getScrollbarWidth());
- $divMain.height(newHeight);
- }
- function getViewport()
- {
- return {
- top: Math.floor(currentScrollTop / options.rowHeight),
- bottom: Math.floor((currentScrollTop + viewportH) / options.rowHeight)
- };
- }
+ function resizeCanvas() {
+ viewportW = $divMainScroller.innerWidth();
+ viewportH = $divMainScroller.innerHeight();
+ BUFFER = numVisibleRows = Math.ceil(viewportH / options.rowHeight);
+ CAPACITY = Math.max(50, numVisibleRows + 2*BUFFER);
- function renderRows(from,to) {
- var parentNode = $divMain[0];
- var rowsBefore = renderedRows;
- var stringArray = [], rows =[];
- var _start = new Date();
+ var totalWidth = 0;
+ for (var i=0; i<columns.length; i++) {
+ if (columns[i].hidden != true)
+ totalWidth += columns[i].width;
+ }
+ $divMain.width(totalWidth);
+
+ var newHeight = Math.max(options.rowHeight * (data.length - 1 + (options.leaveSpaceForNewRows?numVisibleRows-1:0)), viewportH - $.getScrollbarWidth());
+ $divMainScroller.height( $container.innerHeight() - $divHeadersScroller.outerHeight() );
+
+ // browsers sometimes do not adjust scrollTop/scrollHeight when the height of contained objects changes
+ if ($divMainScroller.scrollTop() > newHeight - $divMainScroller.height() + $.getScrollbarWidth()) {
+ $divMainScroller.scrollTop(newHeight - $divMainScroller.height() + $.getScrollbarWidth());
+ }
+ $divMain.height(newHeight);
+
+ render();
+ }
- for (var i = from; i <= to; i++) {
- if (rowsCache[i]) continue;
- renderedRows++;
- rows.push(i);
- appendRowHtml(stringArray,i);
- counter_rows_rendered++;
+ function updateRowCount() {
+ // remove the rows that are now outside of the data range
+ // this helps avoid redundant calls to .removeRow() when the size of the data decreased by thousands of rows
+ var parentNode = $divMain[0];
+ var l = options.enableAddRow ? data.length : data.length - 1;
+ for (var i in rowsCache) {
+ if (i >= l) {
+ parentNode.removeChild(rowsCache[i]);
+ delete rowsCache[i];
+ delete postProcessedRows[i];
+ renderedRows--;
+ counter_rows_removed++;
+ }
+ }
+
+ var newHeight = Math.max(options.rowHeight * (data.length - 1 + (options.leaveSpaceForNewRows?numVisibleRows-1:0)), viewportH - $.getScrollbarWidth());
+
+ // browsers sometimes do not adjust scrollTop/scrollHeight when the height of contained objects changes
+ if ($divMainScroller.scrollTop() > newHeight - $divMainScroller.height() + $.getScrollbarWidth())
+ $divMainScroller.scrollTop(newHeight - $divMainScroller.height() + $.getScrollbarWidth());
+ $divMain.height(newHeight);
}
- var x = document.createElement("div");
- x.innerHTML = stringArray.join("");
-
- for (var i = 0, l = x.childNodes.length; i < l; i++)
- rowsCache[rows[i]] = parentNode.appendChild(x.firstChild);
+ function getViewport()
+ {
+ return {
+ top: Math.floor(currentScrollTop / options.rowHeight),
+ bottom: Math.floor((currentScrollTop + viewportH) / options.rowHeight)
+ };
+ }
- if (renderedRows - rowsBefore > MIN_BUFFER)
- avgRowRenderTime = (new Date() - _start) / (renderedRows - rowsBefore);
- }
-
- function startPostProcessing() {
- window.clearTimeout(h_postrender);
- h_postrender = window.setTimeout(processPostRenderChunk, POSTPROCESSING_DELAY);
- }
-
- function invalidatePostProcessingResults(row) {
- delete postProcessedRows[row];
- rowsToPostProcess.unshift(row);
- startPostProcessing();
- }
+ function renderRows(from,to) {
+ var parentNode = $divMain[0];
+ var rowsBefore = renderedRows;
+ var stringArray = [], rows =[];
+ var _start = new Date();
+
+ for (var i = from; i <= to; i++) {
+ if (rowsCache[i]) continue;
+ renderedRows++;
+ rows.push(i);
+ appendRowHtml(stringArray,i);
+ counter_rows_rendered++;
+ }
+
+ var x = document.createElement("div");
+ x.innerHTML = stringArray.join("");
- function render() {
- var vp = getViewport();
- var from = Math.max(0, vp.top - (scrollDir >= 0 ? MIN_BUFFER : BUFFER));
- var to = Math.min(options.enableAddRow ? data.length : data.length - 1, vp.bottom + (scrollDir > 0 ? BUFFER : MIN_BUFFER));
+ for (var i = 0, l = x.childNodes.length; i < l; i++)
+ rowsCache[rows[i]] = parentNode.appendChild(x.firstChild);
+
+ if (renderedRows - rowsBefore > MIN_BUFFER)
+ avgRowRenderTime = (new Date() - _start) / (renderedRows - rowsBefore);
+ }
- if (renderedRows > 10 && Math.abs(lastRenderedScrollTop - currentScrollTop) > options.rowHeight*CAPACITY)
- removeAllRows();
- else
- cleanupRows(from,to);
-
- renderRows(from,to);
-
- rowsToPostProcess = [];
- from = Math.max(0,vp.top-MIN_BUFFER);
- to = Math.min(options.enableAddRow ? data.length : data.length - 1, vp.bottom+MIN_BUFFER);
- for (var i=from; i<=to; i++) {
- rowsToPostProcess.push(i);
+ function startPostProcessing() {
+ clearTimeout(h_postrender);
+ h_postrender = setTimeout(processPostRenderChunk, POSTPROCESSING_DELAY);
}
- startPostProcessing();
-
- lastRenderedScrollTop = currentScrollTop;
- h_render = null;
- }
-
- function handleScroll() {
- currentScrollTop = $divMainScroller[0].scrollTop;
- var scrollDistance = Math.abs(lastRenderedScrollTop - currentScrollTop);
- var scrollLeft = $divMainScroller[0].scrollLeft;
-
- if (scrollLeft != currentScrollLeft)
- $divHeadersScroller[0].scrollLeft = currentScrollLeft = scrollLeft;
-
- // min scroll distance = 25% of the viewport or MIN_BUFFER rows (whichever is smaller)
- if (scrollDistance < Math.min(viewportH/4, MIN_BUFFER*options.rowHeight)) return;
-
- if (lastRenderedScrollTop == currentScrollTop)
- scrollDir = 0;
- else if (lastRenderedScrollTop < currentScrollTop)
- scrollDir = 1;
- else
- scrollDir = -1;
+ function invalidatePostProcessingResults(row) {
+ delete postProcessedRows[row];
+ rowsToPostProcess.unshift(row);
+ startPostProcessing();
+ }
- if (h_render)
- window.clearTimeout(h_render);
-
- if (scrollDistance < numVisibleRows*options.rowHeight)
- render();
- else
- h_render = window.setTimeout(render, 50);
+ function render() {
+ var vp = getViewport();
+ var from = Math.max(0, vp.top - (scrollDir >= 0 ? MIN_BUFFER : BUFFER));
+ var to = Math.min(options.enableAddRow ? data.length : data.length - 1, vp.bottom + (scrollDir > 0 ? BUFFER : MIN_BUFFER));
- if (self.onViewportChanged)
- self.onViewportChanged();
- }
-
- function processPostRenderChunk() {
- if (rowsToPostProcess.length == 0) return;
- while (rowsToPostProcess.length > 0) {
- var row = rowsToPostProcess.shift();
- if (postProcessedRows[row] || row>=data.length) continue;
- var node = rowsCache[row];
- if (!node) continue;
+ if (renderedRows > 10 && Math.abs(lastRenderedScrollTop - currentScrollTop) > options.rowHeight*CAPACITY)
+ removeAllRows();
+ else
+ cleanupRows(from,to);
- if (self.onPostProcessRowNode)
- self.onPostProcessRowNode(node, row, data[row]);
- startPostProcessing();
- postProcessedRows[row] = true;
- return;
- }
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Interactivity
-
- function handleKeyDown(e) {
- // do we have any registered handlers?
- if (self.onKeyDown && data[currentRow]) {
- // grid must not be in edit mode
- if (!currentEditor) {
- // handler will return true if the event was handled
- if (self.onKeyDown(e, currentRow, currentCell)) {
- e.stopPropagation();
- e.preventDefault();
- return false;
- }
+ renderRows(from,to);
+
+ rowsToPostProcess = [];
+ from = Math.max(0,vp.top-MIN_BUFFER);
+ to = Math.min(options.enableAddRow ? data.length : data.length - 1, vp.bottom+MIN_BUFFER);
+ for (var i=from; i<=to; i++) {
+ rowsToPostProcess.push(i);
}
+
+ startPostProcessing();
+
+ lastRenderedScrollTop = currentScrollTop;
+ h_render = null;
}
-
- switch (e.which) {
- case 27: // esc
- if (GlobalEditorLock.isEditing() && GlobalEditorLock.hasLock(self))
- cancelCurrentEdit(self);
-
- if (currentCellNode)
- currentCellNode.focus();
-
- break;
+
+ function handleScroll() {
+ currentScrollTop = $divMainScroller[0].scrollTop;
+ var scrollDistance = Math.abs(lastRenderedScrollTop - currentScrollTop);
+ var scrollLeft = $divMainScroller[0].scrollLeft;
- case 9: // tab
- gotoDir(0, (e.shiftKey) ? -1 : 1, true);
- break;
-
- case 37: // left
- gotoDir(0,-1);
- break;
-
- case 39: // right
- gotoDir(0,1);
- break;
-
- case 38: // up
- gotoDir(-1,0);
- break;
+ if (scrollLeft != currentScrollLeft)
+ $divHeadersScroller[0].scrollLeft = currentScrollLeft = scrollLeft;
+
+ // min scroll distance = 25% of the viewport or MIN_BUFFER rows (whichever is smaller)
+ if (scrollDistance < Math.min(viewportH/4, MIN_BUFFER*options.rowHeight)) return;
+
+ if (lastRenderedScrollTop == currentScrollTop)
+ scrollDir = 0;
+ else if (lastRenderedScrollTop < currentScrollTop)
+ scrollDir = 1;
+ else
+ scrollDir = -1;
+
+ if (h_render)
+ clearTimeout(h_render);
+
+ if (scrollDistance < numVisibleRows*options.rowHeight)
+ render();
+ else
+ h_render = setTimeout(render, 50);
- case 40: // down
- case 13: // enter
- gotoDir(1,0);
- break;
-
- default:
- // exit without cancelling the event
- return;
+ if (self.onViewportChanged)
+ self.onViewportChanged();
}
-
- e.stopPropagation();
- e.preventDefault();
- return false;
- }
-
- function handleClick(e) {
- var $cell = $(e.target).closest(".c");
- if ($cell.length == 0) return;
-
- // are we editing this cell?
- if (currentCellNode == $cell[0] && currentEditor != null) return;
-
- var row = parseInt($cell.parent().attr("row"));
- var cell = parseInt($cell.attr("cell"));
- var validated = null;
- // do we have any registered handlers?
- if (data[row] && self.onClick) {
- // grid must not be in edit mode
- if (!currentEditor || (validated = commitCurrentEdit())) {
- // handler will return true if the event was handled
- if (self.onClick(e, row, cell)) {
- e.stopPropagation();
- e.preventDefault();
- return false;
- }
+ function processPostRenderChunk() {
+ if (rowsToPostProcess.length == 0) return;
+ while (rowsToPostProcess.length > 0) {
+ var row = rowsToPostProcess.shift();
+ if (postProcessedRows[row] || row>=data.length) continue;
+ var node = rowsCache[row];
+ if (!node) continue;
+
+ if (self.onPostProcessRowNode)
+ self.onPostProcessRowNode(node, row, data[row]);
+ startPostProcessing();
+ postProcessedRows[row] = true;
+ return;
}
}
-
- if (options.enableCellNavigation && !columns[cell].unselectable) {
- // commit current edit before proceeding
- if (validated == true || (validated == null && commitCurrentEdit()))
- setSelectedCellAndRow($cell[0]);
- }
- }
- function handleContextMenu(e) {
- var $cell = $(e.target).closest(".c");
- if ($cell.length == 0) return;
-
- // are we editing this cell?
- if (currentCellNode == $cell[0] && currentEditor != null) return;
-
- var row = parseInt($cell.parent().attr("row"));
- var cell = parseInt($cell.attr("cell"));
- var validated = null;
- // do we have any registered handlers?
- if (data[row] && self.onContextMenu) {
- // grid must not be in edit mode
- if (!currentEditor || (validated = commitCurrentEdit())) {
- // handler will return true if the event was handled
- if (self.onContextMenu(e, row, cell)) {
- e.stopPropagation();
- e.preventDefault();
- return false;
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Interactivity
+
+ function handleKeyDown(e) {
+ // do we have any registered handlers?
+ if (self.onKeyDown && data[currentRow]) {
+ // grid must not be in edit mode
+ if (!currentEditor) {
+ // handler will return true if the event was handled
+ if (self.onKeyDown(e, currentRow, currentCell)) {
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ }
}
}
- }
- }
- function handleDblClick(e) {
- var $cell = $(e.target).closest(".c");
- if ($cell.length == 0) return;
-
- // are we editing this cell?
- if (currentCellNode == $cell[0] && currentEditor != null) return;
+ switch (e.which) {
+ case 27: // esc
+ if (Slick.GlobalEditorLock.isEditing() && Slick.GlobalEditorLock.hasLock(self))
+ cancelCurrentEdit(self);
+
+ if (currentCellNode)
+ currentCellNode.focus();
+
+ break;
- var row = parseInt($cell.parent().attr("row"));
- var cell = parseInt($cell.attr("cell"));
- var validated = null;
-
- // do we have any registered handlers?
- if (data[row] && self.onDblClick) {
- // grid must not be in edit mode
- if (!currentEditor || (validated = commitCurrentEdit())) {
- // handler will return true if the event was handled
- if (self.onDblClick(e, row, cell)) {
- e.stopPropagation();
- e.preventDefault();
- return false;
+ case 9: // tab
+ gotoDir(0, (e.shiftKey) ? -1 : 1, true);
+ break;
+
+ case 37: // left
+ gotoDir(0,-1);
+ break;
+
+ case 39: // right
+ gotoDir(0,1);
+ break;
+
+ case 38: // up
+ gotoDir(-1,0);
+ break;
+
+ case 40: // down
+ case 13: // enter
+ gotoDir(1,0);
+ break;
+
+ default:
+ // exit without cancelling the event
+ return;
+ }
+
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ }
+
+ function handleClick(e) {
+ var $cell = $(e.target).closest(".c");
+ if ($cell.length == 0) return;
+
+ // are we editing this cell?
+ if (currentCellNode == $cell[0] && currentEditor != null) return;
+
+ var row = parseInt($cell.parent().attr("row"));
+ var cell = parseInt($cell.attr("cell"));
+ var validated = null;
+
+ // do we have any registered handlers?
+ if (data[row] && self.onClick) {
+ // grid must not be in edit mode
+ if (!currentEditor || (validated = commitCurrentEdit())) {
+ // handler will return true if the event was handled
+ if (self.onClick(e, row, cell)) {
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ }
}
}
- }
-
- if (options.editOnDoubleClick)
- makeSelectedCellEditable();
- }
- function handleHeaderContextMenu(e) {
- if (self.onHeaderContextMenu && (!currentEditor || (validated = commitCurrentEdit()))) {
- e.preventDefault();
- // TODO: figure out which column was acted on and pass it as a param to the handler
- self.onHeaderContextMenu(e);
+ if (options.enableCellNavigation && !columns[cell].unselectable) {
+ // commit current edit before proceeding
+ if (validated == true || (validated == null && commitCurrentEdit()))
+ setSelectedCellAndRow($cell[0]);
+ }
}
- }
-
- function getCellFromPoint(x,y) {
- var row = Math.floor(y/options.rowHeight);
- var cell = 0;
- var w = 0;
- for (var i=0; i<columns.length && w<y; i++) {
- w += columns[i].width;
- cell++;
+ function handleContextMenu(e) {
+ var $cell = $(e.target).closest(".c");
+ if ($cell.length == 0) return;
+
+ // are we editing this cell?
+ if (currentCellNode == $cell[0] && currentEditor != null) return;
+
+ var row = parseInt($cell.parent().attr("row"));
+ var cell = parseInt($cell.attr("cell"));
+ var validated = null;
+
+ // do we have any registered handlers?
+ if (data[row] && self.onContextMenu) {
+ // grid must not be in edit mode
+ if (!currentEditor || (validated = commitCurrentEdit())) {
+ // handler will return true if the event was handled
+ if (self.onContextMenu(e, row, cell)) {
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ }
+ }
+ }
}
- return {row:row,cell:cell-1};
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Cell switching
-
- function setSelectedCell(newCell,async) {
- if (currentCellNode != null) {
- makeSelectedCellNormal();
- $(currentCellNode).removeClass("selected");
+ function handleDblClick(e) {
+ var $cell = $(e.target).closest(".c");
+ if ($cell.length == 0) return;
+
+ // are we editing this cell?
+ if (currentCellNode == $cell[0] && currentEditor != null) return;
+
+ var row = parseInt($cell.parent().attr("row"));
+ var cell = parseInt($cell.attr("cell"));
+ var validated = null;
+
+ // do we have any registered handlers?
+ if (data[row] && self.onDblClick) {
+ // grid must not be in edit mode
+ if (!currentEditor || (validated = commitCurrentEdit())) {
+ // handler will return true if the event was handled
+ if (self.onDblClick(e, row, cell)) {
+ e.stopPropagation();
+ e.preventDefault();
+ return false;
+ }
+ }
+ }
+
+ if (options.editOnDoubleClick)
+ makeSelectedCellEditable();
}
- currentCellNode = newCell;
-
- if (currentCellNode != null) {
- currentRow = parseInt($(currentCellNode).parent().attr("row"));
- currentCell = parseInt($(currentCellNode).attr("cell"));
+ function handleHeaderContextMenu(e) {
+ if (self.onHeaderContextMenu && (!currentEditor || (validated = commitCurrentEdit()))) {
+ e.preventDefault();
+ // TODO: figure out which column was acted on and pass it as a param to the handler
+ self.onHeaderContextMenu(e);
+ }
+ }
+
+ function getCellFromPoint(x,y) {
+ var row = Math.floor(y/options.rowHeight);
+ var cell = 0;
- $(currentCellNode).addClass("selected");
+ var w = 0;
+ for (var i=0; i<columns.length && w<y; i++) {
+ w += columns[i].width;
+ cell++;
+ }
- scrollSelectedCellIntoView();
+ return {row:row,cell:cell-1};
+ }
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Cell switching
+
+ function setSelectedCell(newCell,async) {
+ if (currentCellNode != null) {
+ makeSelectedCellNormal();
+ $(currentCellNode).removeClass("selected");
+ }
- if (options.editable && !options.editOnDoubleClick && (data[currentRow] || currentRow == data.length)) {
- window.clearTimeout(h_editorLoader);
+ currentCellNode = newCell;
+
+ if (currentCellNode != null) {
+ currentRow = parseInt($(currentCellNode).parent().attr("row"));
+ currentCell = parseInt($(currentCellNode).attr("cell"));
+
+ $(currentCellNode).addClass("selected");
+
+ scrollSelectedCellIntoView();
- if (async)
- h_editorLoader = window.setTimeout(makeSelectedCellEditable, 100);
- else
- makeSelectedCellEditable();
+ if (options.editable && !options.editOnDoubleClick && (data[currentRow] || currentRow == data.length)) {
+ clearTimeout(h_editorLoader);
+
+ if (async)
+ h_editorLoader = setTimeout(makeSelectedCellEditable, EDITOR_LOAD_DELAY);
+ else
+ makeSelectedCellEditable();
+ }
+ }
+ else {
+ currentRow = null;
+ currentCell = null;
}
}
- else {
- currentRow = null;
- currentCell = null;
+
+ function setSelectedCellAndRow(newCell,async) {
+ setSelectedCell(newCell,async);
+
+ if (newCell)
+ setSelectedRows([currentRow]);
+ else
+ setSelectedRows([]);
+
+ if (self.onSelectedRowsChanged)
+ self.onSelectedRowsChanged();
}
- }
-
- function setSelectedCellAndRow(newCell,async) {
- setSelectedCell(newCell,async);
- if (newCell)
- setSelectedRows([currentRow]);
- else
- setSelectedRows([]);
+ function clearTextSelection() {
+ if (document.selection && document.selection.empty)
+ document.selection.empty();
+ else if (window.getSelection) {
+ var sel = window.getSelection();
+ if (sel && sel.removeAllRanges)
+ sel.removeAllRanges();
+ }
+ }
+
+ function isCellPotentiallyEditable(row,cell) {
+ // is the data for this row loaded?
+ if (row < data.length && !data[row])
+ return false;
- if (self.onSelectedRowsChanged)
- self.onSelectedRowsChanged();
- }
+ // are we in the Add New row? can we create new from this cell?
+ if (columns[cell].cannotTriggerInsert && row >= data.length)
+ return false;
+
+ // does this cell have an editor?
+ if (!columns[cell].editor)
+ return false;
+
+ return true;
+ }
+
+ function makeSelectedCellNormal() {
+ if (!currentEditor) return;
+
+ currentEditor.destroy();
+ $(currentCellNode).removeClass("editable invalid");
+
+ if (data[currentRow]) {
+ currentCellNode.innerHTML = columns[currentCell].formatter(currentRow, currentCell, data[currentRow][columns[currentCell].field], columns[currentCell], data[currentRow]);
+ invalidatePostProcessingResults(currentRow);
+ }
+
+ currentEditor = null;
+
+ // if there previously was text selected on a page (such as selected text in the edit cell just removed),
+ // IE can't set focus to anything else correctly
+ if ($.browser.msie) clearTextSelection();
- function clearTextSelection() {
- if (document.selection && document.selection.empty)
- document.selection.empty();
- else if (window.getSelection) {
- var sel = window.getSelection();
- if (sel && sel.removeAllRanges)
- sel.removeAllRanges();
+ Slick.GlobalEditorLock.leaveEditMode(self);
}
- }
-
- function isCellPotentiallyEditable(row,cell) {
- // is the data for this row loaded?
- if (row < data.length && !data[row])
- return false;
-
- // are we in the Add New row? can we create new from this cell?
- if (columns[cell].cannotTriggerInsert && row >= data.length)
- return false;
+
+ function makeSelectedCellEditable() {
+ if (!currentCellNode) return;
+ if (!options.editable)
+ throw "Grid : makeSelectedCellEditable : should never get called when options.editable is false";
- // does this cell have an editor?
- if (!columns[cell].editor)
- return false;
+ // cancel pending async call if there is one
+ clearTimeout(h_editorLoader);
- return true;
- }
-
- function makeSelectedCellNormal() {
- if (!currentEditor) return;
-
- currentEditor.destroy();
- $(currentCellNode).removeClass("editable invalid");
+ if (!isCellPotentiallyEditable(currentRow,currentCell))
+ return;
+
+ Slick.GlobalEditorLock.enterEditMode(self);
+
+ $(currentCellNode).addClass("editable");
+
+ var value = null;
- if (data[currentRow]) {
- currentCellNode.innerHTML = columns[currentCell].formatter(currentRow, currentCell, data[currentRow][columns[currentCell].field], columns[currentCell], data[currentRow]);
- invalidatePostProcessingResults(currentRow);
+ // if there is a corresponding row
+ if (data[currentRow])
+ value = data[currentRow][columns[currentCell].field];
+
+ currentCellNode.innerHTML = "";
+
+ currentEditor = new columns[currentCell].editor($(currentCellNode), columns[currentCell], value, data[currentRow]);
}
-
- currentEditor = null;
-
- // if there previously was text selected on a page (such as selected text in the edit cell just removed),
- // IE can't set focus to anything else correctly
- if ($.browser.msie) clearTextSelection();
-
- GlobalEditorLock.leaveEditMode(self);
- }
-
- function makeSelectedCellEditable() {
- if (!currentCellNode) return;
- if (!options.editable)
- throw "Grid : makeSelectedCellEditable : should never get called when options.editable is false";
-
- // cancel pending async call if there is one
- window.clearTimeout(h_editorLoader);
-
- if (!isCellPotentiallyEditable(currentRow,currentCell))
- return;
-
- GlobalEditorLock.enterEditMode(self);
-
- $(currentCellNode).addClass("editable");
-
- var value = null;
- // if there is a corresponding row
- if (data[currentRow])
- value = data[currentRow][columns[currentCell].field];
-
- currentCellNode.innerHTML = "";
-
- currentEditor = new columns[currentCell].editor($(currentCellNode), columns[currentCell], value, data[currentRow]);
- }
-
- function scrollSelectedCellIntoView() {
- if (!currentCellNode) return;
- var scrollTop = $divMainScroller[0].scrollTop;
-
- // need to page down?
- if ((currentRow + 2) * options.rowHeight > scrollTop + viewportH) {
- $divMainScroller[0].scrollTop = (currentRow ) * options.rowHeight;
- handleScroll();
+ function scrollSelectedCellIntoView() {
+ if (!currentCellNode) return;
+ var scrollTop = $divMainScroller[0].scrollTop;
+
+ // need to page down?
+ if ((currentRow + 2) * options.rowHeight > scrollTop + viewportH) {
+ $divMainScroller[0].scrollTop = (currentRow ) * options.rowHeight;
+ handleScroll();
+ }
+ // or page up?
+ else if (currentRow * options.rowHeight < scrollTop) {
+ $divMainScroller[0].scrollTop = (currentRow + 2) * options.rowHeight - viewportH;
+ handleScroll();
+ }
}
- // or page up?
- else if (currentRow * options.rowHeight < scrollTop) {
- $divMainScroller[0].scrollTop = (currentRow + 2) * options.rowHeight - viewportH;
- handleScroll();
- }
- }
-
- function gotoDir(dy, dx, rollover) {
- if (!currentCellNode) return;
- if (!options.enableCellNavigation) return;
- if (!GlobalEditorLock.commitCurrentEdit()) return;
-
- var nextRow = rowsCache[currentRow + dy];
- var nextCell = nextRow ? $(nextRow).find(".c[cell=" + (currentCell + dx) + "][tabIndex=0]") : null;
-
- if (rollover && dy == 0 && !(nextRow && nextCell && nextCell.length)) {
- if (!nextCell || !nextCell.length) {
- if (dx > 0) {
- nextRow = rowsCache[currentRow + dy + 1];
- nextCell = nextRow ? $(nextRow).find(".c[cell][tabIndex=0]:first") : null;
- }
- else {
- nextRow = rowsCache[currentRow + dy - 1];
- nextCell = nextRow ? $(nextRow).find(".c[cell][tabIndex=0]:last") : null;
+
+ function gotoDir(dy, dx, rollover) {
+ if (!currentCellNode) return;
+ if (!options.enableCellNavigation) return;
+ if (!Slick.GlobalEditorLock.commitCurrentEdit()) return;
+
+ var nextRow = rowsCache[currentRow + dy];
+ var nextCell = nextRow ? $(nextRow).find(".c[cell=" + (currentCell + dx) + "][tabIndex=0]") : null;
+
+ if (rollover && dy == 0 && !(nextRow && nextCell && nextCell.length)) {
+ if (!nextCell || !nextCell.length) {
+ if (dx > 0) {
+ nextRow = rowsCache[currentRow + dy + 1];
+ nextCell = nextRow ? $(nextRow).find(".c[cell][tabIndex=0]:first") : null;
+ }
+ else {
+ nextRow = rowsCache[currentRow + dy - 1];
+ nextCell = nextRow ? $(nextRow).find(".c[cell][tabIndex=0]:last") : null;
+ }
}
}
+
+
+ if (nextRow && nextCell && nextCell.length) {
+ setSelectedCellAndRow(nextCell[0],options.asyncEditorLoading);
+
+ // if no editor was created, set the focus back on the cell
+ if (!currentEditor)
+ currentCellNode.focus();
+ }
+ else
+ currentCellNode.focus();
}
-
-
- if (nextRow && nextCell && nextCell.length) {
- setSelectedCellAndRow(nextCell[0],options.asyncEditorLoading);
+
+ function gotoCell(row,cell) {
+ if (row > data.length || row < 0 || cell >= columns.length || cell < 0) return;
+ if (!options.enableCellNavigation || columns[cell].unselectable) return;
+
+ if (!Slick.GlobalEditorLock.commitCurrentEdit()) return;
+
+ if (!rowsCache[row])
+ renderRows(row,row);
+
+ var cell = $(rowsCache[row]).find(".c[cell=" + cell + "][tabIndex=0]")[0];
+
+ setSelectedCellAndRow(cell);
// if no editor was created, set the focus back on the cell
if (!currentEditor)
currentCellNode.focus();
}
- else
- currentCellNode.focus();
- }
-
- function gotoCell(row,cell) {
- if (row > data.length || row < 0 || cell >= columns.length || cell < 0) return;
- if (!options.enableCellNavigation || columns[cell].unselectable) return;
-
- if (!GlobalEditorLock.commitCurrentEdit()) return;
-
- if (!rowsCache[row])
- renderRows(row,row);
-
- var cell = $(rowsCache[row]).find(".c[cell=" + cell + "][tabIndex=0]")[0];
-
- setSelectedCellAndRow(cell);
-
- // if no editor was created, set the focus back on the cell
- if (!currentEditor)
- currentCellNode.focus();
- }
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // IEditor implementation for GlobalEditorLock
- function commitCurrentEdit() {
- if (currentEditor) {
- if (currentEditor.isValueChanged()) {
- var validationResults = currentEditor.validate();
-
- if (validationResults.valid) {
- var value = currentEditor.getValue();
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // IEditor implementation for Slick.GlobalEditorLock
+
+ function commitCurrentEdit() {
+ if (currentEditor) {
+ if (currentEditor.isValueChanged()) {
+ var validationResults = currentEditor.validate();
- if (currentRow < data.length) {
- if (columns[currentCell].setValueHandler) {
- makeSelectedCellNormal();
- columns[currentCell].setValueHandler(value, columns[currentCell], data[currentRow]);
- }
- else {
- data[currentRow][columns[currentCell].field] = value;
- makeSelectedCellNormal();
+ if (validationResults.valid) {
+ var value = currentEditor.getValue();
+
+ if (currentRow < data.length) {
+ if (columns[currentCell].setValueHandler) {
+ makeSelectedCellNormal();
+ columns[currentCell].setValueHandler(value, columns[currentCell], data[currentRow]);
+ }
+ else {
+ data[currentRow][columns[currentCell].field] = value;
+ makeSelectedCellNormal();
+ }
}
+ else if (self.onAddNewRow) {
+ makeSelectedCellNormal();
+ self.onAddNewRow(columns[currentCell], value);
+ }
+
+ return true;
+ }
+ else {
+ $(currentCellNode).addClass("invalid");
+ $(currentCellNode).stop(true,true).effect("highlight", {color:"red"}, 300);
+
+ if (self.onValidationError)
+ self.onValidationError(currentCellNode, validationResults, currentRow, currentCell, columns[currentCell]);
+
+ currentEditor.focus();
+ return false;
}
- else if (self.onAddNewRow) {
- makeSelectedCellNormal();
- self.onAddNewRow(columns[currentCell], value);
- }
-
- return true;
- }
- else {
- $(currentCellNode).addClass("invalid");
- $(currentCellNode).stop(true,true).effect("highlight", {color:"red"}, 300);
-
- if (self.onValidationError)
- self.onValidationError(currentCellNode, validationResults, currentRow, currentCell, columns[currentCell]);
-
- currentEditor.focus();
- return false;
}
+
+ makeSelectedCellNormal();
}
- makeSelectedCellNormal();
+
+ return true;
}
+ function cancelCurrentEdit() {
+ makeSelectedCellNormal();
+ }
- return true;
- }
-
- function cancelCurrentEdit() {
- makeSelectedCellNormal();
- }
-
-
-
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Debug
-
- this.debug = function() {
- var s = "";
-
- s += ("\n" + "counter_rows_rendered: " + counter_rows_rendered);
- s += ("\n" + "counter_rows_removed: " + counter_rows_removed);
- s += ("\n" + "renderedRows: " + renderedRows);
- s += ("\n" + "numVisibleRows: " + numVisibleRows);
- s += ("\n" + "CAPACITY: " + CAPACITY);
- s += ("\n" + "BUFFER: " + BUFFER);
- s += ("\n" + "avgRowRenderTime: " + avgRowRenderTime);
-
- alert(s);
- };
-
- this.benchmark_render_200 = function() {
- removeAllRows();
- // render 200 rows in the viewport
- renderRows(0, 200);
- cleanupRows();
- };
-
- this.stressTest = function() {
- console.time("benchmark-stress");
-
- renderRows(0,500);
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Debug
- cleanupRows();
+ this.debug = function() {
+ var s = "";
+
+ s += ("\n" + "counter_rows_rendered: " + counter_rows_rendered);
+ s += ("\n" + "counter_rows_removed: " + counter_rows_removed);
+ s += ("\n" + "renderedRows: " + renderedRows);
+ s += ("\n" + "numVisibleRows: " + numVisibleRows);
+ s += ("\n" + "CAPACITY: " + CAPACITY);
+ s += ("\n" + "BUFFER: " + BUFFER);
+ s += ("\n" + "avgRowRenderTime: " + avgRowRenderTime);
+
+ alert(s);
+ };
- console.timeEnd("benchmark-stress");
+ this.benchmark_render_200 = function() {
+ removeAllRows();
+
+ // render 200 rows in the viewport
+ renderRows(0, 200);
+
+ cleanupRows();
+ };
- window.setTimeout(self.stressTest, 50);
- };
+ this.stressTest = function() {
+ console.time("benchmark-stress");
- this.benchmarkFn = function(fn) {
- var s = new Date();
-
- var args = new Array(arguments);
- args.splice(0,1);
+ renderRows(0,500);
+
+ cleanupRows();
+
+ console.timeEnd("benchmark-stress");
+
+ setTimeout(self.stressTest, 50);
+ };
- self[fn].call(this,args);
+ this.benchmarkFn = function(fn) {
+ var s = new Date();
+
+ var args = new Array(arguments);
+ args.splice(0,1);
+
+ self[fn].call(this,args);
+
+ alert("Grid : benchmarkFn : " + fn + " : " + (new Date() - s) + "ms");
+ };
- alert("Grid : benchmarkFn : " + fn + " : " + (new Date() - s) + "ms");
- };
-
-
-
- init();
- //////////////////////////////////////////////////////////////////////////////////////////////
- // Public API
+ init();
+
+
+ //////////////////////////////////////////////////////////////////////////////////////////////
+ // Public API
+
+ $.extend(this, {
+ // Events
+ "onSort": null,
+ "onHeaderContextMenu": null,
+ "onClick": null,
+ "onContextMenu": null,
+ "onKeyDown": null,
+ "onAddNewRow": null,
+ "onValidationError": null,
+ "onViewportChanged": null,
+ "onSelectedRowsChanged": null,
+ "onColumnsReordered": null,
+ "onBeforeMoveRows" : null,
+ "onMoveRows": null,
+ "onPostProcessRowNode": null,
+
+ // Methods
+ "setOptions": setOptions,
+ "setData": setData,
+ "destroy": destroy,
+ "getColumnIndex": getColumnIndex,
+ "setColumnVisibility": setColumnVisibility,
+ "autosizeColumns": autosizeColumns,
+ "updateCell": updateCell,
+ "updateRow": updateRow,
+ "removeRow": removeRow,
+ "removeRows": removeRows,
+ "removeAllRows": removeAllRows,
+ "render": render,
+ "getViewport": getViewport,
+ "resizeCanvas": resizeCanvas,
+ "updateRowCount": updateRowCount,
+ "scroll": scroll, // TODO
+ "getCellFromPoint": getCellFromPoint,
+ "gotoCell": gotoCell,
+ "editCurrentCell": makeSelectedCellEditable,
+ "getSelectedRows": getSelectedRows,
+ "setSelectedRows": setSelectedRows,
+
+ // IEditor implementation
+ "commitCurrentEdit": commitCurrentEdit,
+ "cancelCurrentEdit": cancelCurrentEdit
+ });
+ }
- $.extend(this, {
- // Events
- "onSort": null,
- "onHeaderContextMenu": null,
- "onClick": null,
- "onContextMenu": null,
- "onKeyDown": null,
- "onAddNewRow": null,
- "onValidationError": null,
- "onViewportChanged": null,
- "onSelectedRowsChanged": null,
- "onColumnsReordered": null,
- "onBeforeMoveRows" : null,
- "onMoveRows": null,
- "onPostProcessRowNode": null,
-
- // Methods
- "setOptions": setOptions,
- "setData": setData,
- "destroy": destroy,
- "getColumnIndex": getColumnIndex,
- "setColumnVisibility": setColumnVisibility,
- "autosizeColumns": autosizeColumns,
- "updateCell": updateCell,
- "updateRow": updateRow,
- "removeRow": removeRow,
- "removeRows": removeRows,
- "removeAllRows": removeAllRows,
- "render": render,
- "getViewport": getViewport,
- "resizeCanvas": resizeCanvas,
- "updateRowCount": updateRowCount,
- "scroll": scroll, // TODO
- "getCellFromPoint": getCellFromPoint,
- "gotoCell": gotoCell,
- "editCurrentCell": makeSelectedCellEditable,
- "getSelectedRows": getSelectedRows,
- "setSelectedRows": setSelectedRows,
-
- // IEditor implementation
- "commitCurrentEdit": commitCurrentEdit,
- "cancelCurrentEdit": cancelCurrentEdit
- });
-}
+ // Slick.Grid
+ $.extend(true, window, { Slick: { Grid: SlickGrid }});
+})(); \ No newline at end of file
diff --git a/slick.model.js b/slick.model.js
index ec2be94..76ec45c 100644
--- a/slick.model.js
+++ b/slick.model.js
@@ -18,214 +18,217 @@ function EventHelper() {
}
-
-/***
- * A sample Model implementation.
- * Provides a filtered view of the underlying data.
- *
- * Relies on the data item having an "id" property uniquely identifying it.
- */
-function DataView() {
- var self = this;
-
- // private
- var items = []; // data by index
- var rows = []; // data by row
- var idxById = {}; // indexes by id
- var rowsById = null; // rows by id; lazy-calculated
- var filter = null; // filter function
- var updated = null; // updated item ids
- var suspend = false; // suspends the recalculation
-
- var pagesize = 0;
- var pagenum = 0;
- var totalRows = 0;
-
- // events
- var onRowCountChanged = new EventHelper();
- var onRowsChanged = new EventHelper();
- var onPagingInfoChanged = new EventHelper();
-
-
- function beginUpdate() {
- suspend = true;
- }
-
- function endUpdate() {
- suspend = false;
- refresh();
- }
-
- function setItems(data) {
- items = data.concat();
- for (var i=0,l=items.length; i<l; i++) {
- var id = items[i].id;
- if (id == undefined || idxById[id] != undefined)
- throw "Each data element must implement a unique 'id' property";
- idxById[id] = i;
- }
- refresh();
- }
-
- function setPagingOptions(args) {
- if (args.pageSize != undefined)
- pagesize = args.pageSize;
-
- if (args.pageNum != undefined)
- pagenum = Math.min(args.pageNum, Math.ceil(totalRows/pagesize));
-
- onPagingInfoChanged.notify(getPagingInfo());
-
- refresh();
- }
-
- function getPagingInfo() {
- return {pageSize:pagesize, pageNum:pagenum, totalRows:totalRows};
- }
-
- function sort(comparer) {
- items.sort(comparer);
- refresh();
- }
-
- function setFilter(filterFn) {
- filter = filterFn;
- refresh();
- }
-
- function getItemByIdx(i) {
- return items[i];
- }
-
- function getIdxById(id) {
- return idxById[id];
- }
-
- // calculate the lookup table on first call
- function getRowById(id) {
- if (!rowsById) {
- rowsById = {};
- for (var i=0, l=rows.length; i<l; ++i) {
- rowsById[rows[i].id] = i;
- }
+(function() {
+ /***
+ * A sample Model implementation.
+ * Provides a filtered view of the underlying data.
+ *
+ * Relies on the data item having an "id" property uniquely identifying it.
+ */
+ function DataView() {
+ var self = this;
+
+ // private
+ var items = []; // data by index
+ var rows = []; // data by row
+ var idxById = {}; // indexes by id
+ var rowsById = null; // rows by id; lazy-calculated
+ var filter = null; // filter function
+ var updated = null; // updated item ids
+ var suspend = false; // suspends the recalculation
+
+ var pagesize = 0;
+ var pagenum = 0;
+ var totalRows = 0;
+
+ // events
+ var onRowCountChanged = new EventHelper();
+ var onRowsChanged = new EventHelper();
+ var onPagingInfoChanged = new EventHelper();
+
+
+ function beginUpdate() {
+ suspend = true;
}
- return rowsById[id];
- }
-
- function getItemById(id) {
- return items[idxById[id]];
- }
-
- function updateItem(id,item) {
- items[idxById[id]] = item;
- if (!updated) updated = {};
- updated[id] = true;
- 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 endUpdate() {
+ suspend = false;
+ refresh();
+ }
+
+ function setItems(data) {
+ items = data.concat();
+ for (var i=0,l=items.length; i<l; i++) {
+ var id = items[i].id;
+ if (id == undefined || idxById[id] != undefined)
+ throw "Each data element must implement a unique 'id' property";
+ idxById[id] = i;
+ }
+ refresh();
+ }
+
+ function setPagingOptions(args) {
+ if (args.pageSize != undefined)
+ pagesize = args.pageSize;
+
+ if (args.pageNum != undefined)
+ pagenum = Math.min(args.pageNum, Math.ceil(totalRows/pagesize));
- function recalc(_items,_rows,_filter,_updated) {
- var diff = [];
- var items=_items, rows=_rows, filter=_filter, updated=_updated; // cache as local vars
-
- rowsById = null;
-
- // go over all items remapping them to rows on the fly
- // while keeping track of the differences and updating indexes
- var rl = rows.length;
- var currentRowIndex = 0;
- var currentPageIndex = 0;
- var item,id;
+ onPagingInfoChanged.notify(getPagingInfo());
- for (var i = 0, il = items.length; i < il; ++i) {
- item = items[i];
- id = item.id;
-
- if (!filter || filter(item)) {
- if (!pagesize || (currentRowIndex >= pagesize * pagenum && currentRowIndex < pagesize * (pagenum + 1))) {
- if (currentPageIndex >= rl || id != rows[currentPageIndex].id || (updated && updated[id]))
- diff[diff.length] = currentPageIndex;
-
- rows[currentPageIndex] = item;
- currentPageIndex++;
- }
-
- currentRowIndex++;
+ refresh();
+ }
+
+ function getPagingInfo() {
+ return {pageSize:pagesize, pageNum:pagenum, totalRows:totalRows};
+ }
+
+ function sort(comparer) {
+ items.sort(comparer);
+ refresh();
+ }
+
+ function setFilter(filterFn) {
+ filter = filterFn;
+ refresh();
+ }
+
+ function getItemByIdx(i) {
+ return items[i];
+ }
+
+ function getIdxById(id) {
+ return idxById[id];
+ }
+
+ // calculate the lookup table on first call
+ function getRowById(id) {
+ if (!rowsById) {
+ rowsById = {};
+ for (var i=0, l=rows.length; i<l; ++i) {
+ rowsById[rows[i].id] = i;
+ }
}
+
+ return rowsById[id];
}
- if (rl > currentPageIndex)
- rows.splice(currentPageIndex, rl - currentPageIndex);
+ function getItemById(id) {
+ return items[idxById[id]];
+ }
- totalRows = currentRowIndex;
+ function updateItem(id,item) {
+ items[idxById[id]] = item;
+ if (!updated) updated = {};
+ updated[id] = true;
+ refresh();
+ }
- return diff;
- }
-
- function refresh() {
- if (suspend) return;
+ function insertItem(insertBefore,item) {
+ items.splice(insertBefore,0,item);
+ refresh();
+ }
+
+ function addItem(item) {
+ items.push(item);
+ refresh();
+ }
- var countBefore = rows.length;
- var totalRowsBefore = totalRows;
+ function deleteItem(id) {
+ items.splice(idxById[id],1);
+ refresh();
+ }
- var diff = recalc(items,rows,filter,updated); // pass as direct refs to avoid closure perf hit
+ function recalc(_items,_rows,_filter,_updated) {
+ var diff = [];
+ var items=_items, rows=_rows, filter=_filter, updated=_updated; // cache as local vars
+
+ rowsById = null;
+
+ // go over all items remapping them to rows on the fly
+ // while keeping track of the differences and updating indexes
+ var rl = rows.length;
+ var currentRowIndex = 0;
+ var currentPageIndex = 0;
+ var item,id;
- // if the current page is no longer valid, go to last page and recalc
- // we suffer a performance penalty here, but the main loop (recalc) remains highly optimized
- if (pagesize && totalRows < pagenum*pagesize) {
- pagenum = Math.floor(totalRows/pagesize);
- diff = recalc(items,rows,filter,updated);
+ for (var i = 0, il = items.length; i < il; ++i) {
+ item = items[i];
+ id = item.id;
+
+ if (!filter || filter(item)) {
+ if (!pagesize || (currentRowIndex >= pagesize * pagenum && currentRowIndex < pagesize * (pagenum + 1))) {
+ if (currentPageIndex >= rl || id != rows[currentPageIndex].id || (updated && updated[id]))
+ diff[diff.length] = currentPageIndex;
+
+ rows[currentPageIndex] = item;
+ currentPageIndex++;
+ }
+
+ currentRowIndex++;
+ }
+ }
+
+ if (rl > currentPageIndex)
+ rows.splice(currentPageIndex, rl - currentPageIndex);
+
+ totalRows = currentRowIndex;
+
+ return diff;
}
-
- updated = null;
- if (totalRowsBefore != totalRows) onPagingInfoChanged.notify(getPagingInfo());
- if (countBefore != rows.length) onRowCountChanged.notify({previous:countBefore, current:rows.length});
- if (diff.length > 0 || countBefore != rows.length) onRowsChanged.notify(diff);
- }
+ function refresh() {
+ if (suspend) return;
+
+ var countBefore = rows.length;
+ var totalRowsBefore = totalRows;
+
+ var diff = recalc(items,rows,filter,updated); // pass as direct refs to avoid closure perf hit
+
+ // if the current page is no longer valid, go to last page and recalc
+ // we suffer a performance penalty here, but the main loop (recalc) remains highly optimized
+ if (pagesize && totalRows < pagenum*pagesize) {
+ pagenum = Math.floor(totalRows/pagesize);
+ diff = recalc(items,rows,filter,updated);
+ }
-
+ updated = null;
+
+ if (totalRowsBefore != totalRows) onPagingInfoChanged.notify(getPagingInfo());
+ if (countBefore != rows.length) onRowCountChanged.notify({previous:countBefore, current:rows.length});
+ if (diff.length > 0 || countBefore != rows.length) onRowsChanged.notify(diff);
+ }
+
- return {
- // properties
- "rows": rows, // note: neither the array or the data in it should be modified directly
-
- // methods
- "beginUpdate": beginUpdate,
- "endUpdate": endUpdate,
- "setPagingOptions": setPagingOptions,
- "getPagingInfo": getPagingInfo,
- "setItems": setItems,
- "setFilter": setFilter,
- "sort": sort,
- "getIdxById": getIdxById,
- "getRowById": getRowById,
- "getItemById": getItemById,
- "getItemByIdx": getItemByIdx,
- "refresh": refresh,
- "updateItem": updateItem,
- "insertItem": insertItem,
- "addItem": addItem,
- "deleteItem": deleteItem,
- // events
- "onRowCountChanged": onRowCountChanged,
- "onRowsChanged": onRowsChanged,
- "onPagingInfoChanged": onPagingInfoChanged
- };
-}
+ return {
+ // properties
+ "rows": rows, // note: neither the array or the data in it should be modified directly
+
+ // methods
+ "beginUpdate": beginUpdate,
+ "endUpdate": endUpdate,
+ "setPagingOptions": setPagingOptions,
+ "getPagingInfo": getPagingInfo,
+ "setItems": setItems,
+ "setFilter": setFilter,
+ "sort": sort,
+ "getIdxById": getIdxById,
+ "getRowById": getRowById,
+ "getItemById": getItemById,
+ "getItemByIdx": getItemByIdx,
+ "refresh": refresh,
+ "updateItem": updateItem,
+ "insertItem": insertItem,
+ "addItem": addItem,
+ "deleteItem": deleteItem,
+
+ // events
+ "onRowCountChanged": onRowCountChanged,
+ "onRowsChanged": onRowsChanged,
+ "onPagingInfoChanged": onPagingInfoChanged
+ };
+ }
+ // Slick.Data.DataView
+ $.extend(true, window, { Slick: { Data: { DataView: DataView }}});
+})(); \ No newline at end of file
diff --git a/slick.pager.js b/slick.pager.js
index c9c45bb..9d0bb25 100644
--- a/slick.pager.js
+++ b/slick.pager.js
@@ -1,138 +1,144 @@
-function SlickGridPager(dataView, grid, $container)
-{
- var $status, $contextMenu;
-
- function init()
- {
- dataView.onPagingInfoChanged.subscribe(function(pagingInfo) {
- updatePager(pagingInfo);
- });
-
- constructPagerUI();
- updatePager(dataView.getPagingInfo());
- }
-
- function getNavState()
+(function() {
+ function SlickGridPager(dataView, grid, $container)
{
- var cannotLeaveEditMode = !(!GlobalEditorLock.isEditing() || GlobalEditorLock.commitCurrentEdit())
- var pagingInfo = dataView.getPagingInfo();
- var lastPage = Math.floor(pagingInfo.totalRows/pagingInfo.pageSize);
+ var $status, $contextMenu;
- return {
- canGotoFirst: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum > 0,
- canGotoLast: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum != lastPage,
- canGotoPrev: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum > 0,
- canGotoNext: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum < lastPage,
- pagingInfo: pagingInfo,
- lastPage: lastPage
+ function init()
+ {
+ dataView.onPagingInfoChanged.subscribe(function(pagingInfo) {
+ updatePager(pagingInfo);
+ });
+
+ constructPagerUI();
+ updatePager(dataView.getPagingInfo());
}
- }
-
- function setPageSize(n)
- {
- dataView.setPagingOptions({pageSize:n});
- }
-
- function gotoFirst()
- {
- if (getNavState().canGotoFirst)
- dataView.setPagingOptions({pageNum: 0});
- }
-
- function gotoLast()
- {
- var state = getNavState();
- if (state.canGotoLast)
- dataView.setPagingOptions({pageNum: state.lastPage});
- }
-
- function gotoPrev()
- {
- var state = getNavState();
- if (state.canGotoPrev)
- dataView.setPagingOptions({pageNum: state.pagingInfo.pageNum-1});
- }
-
- function gotoNext()
- {
- var state = getNavState();
- if (state.canGotoNext)
- dataView.setPagingOptions({pageNum: state.pagingInfo.pageNum+1});
- }
-
- function constructPagerUI()
- {
- $container.empty();
-
- $status = $("<span class='slick-pager-status' />").appendTo($container);
-
- var $nav = $("<span class='slick-pager-nav' />").appendTo($container);
- var $settings = $("<span class='slick-pager-settings' />").appendTo($container);
-
- $settings
- .append("<span class='slick-pager-settings-expanded' style='display:none'>Show: <a data=0>All</a><a data='-1'>Auto</a><a data=25>25</a><a data=50>50</a><a data=100>100</a></span>");
- $settings.find("a[data]").click(function(e) {
- var pagesize = $(e.target).attr("data");
- if (pagesize != undefined)
- {
- if (pagesize == -1)
- {
- var vp = grid.getViewport();
- setPageSize(vp.bottom-vp.top);
- }
- else
- setPageSize(parseInt(pagesize));
- }
- });
+ function getNavState()
+ {
+ var cannotLeaveEditMode = !(!Slick.GlobalEditorLock.isEditing() || Slick.GlobalEditorLock.commitCurrentEdit())
+ var pagingInfo = dataView.getPagingInfo();
+ var lastPage = Math.floor(pagingInfo.totalRows/pagingInfo.pageSize);
- $("<span class='ui-icon ui-icon-lightbulb' />")
- .click(function() { $(".slick-pager-settings-expanded").toggle() })
- .appendTo($settings);
+ return {
+ canGotoFirst: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum > 0,
+ canGotoLast: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum != lastPage,
+ canGotoPrev: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum > 0,
+ canGotoNext: !cannotLeaveEditMode && pagingInfo.pageSize != 0 && pagingInfo.pageNum < lastPage,
+ pagingInfo: pagingInfo,
+ lastPage: lastPage
+ }
+ }
- $("<span class='ui-icon ui-icon-seek-first' />")
- .click(gotoFirst)
- .appendTo($nav);
+ function setPageSize(n)
+ {
+ dataView.setPagingOptions({pageSize:n});
+ }
- $("<span class='ui-icon ui-icon-seek-prev' />")
- .click(gotoPrev)
- .appendTo($nav);
-
- $("<span class='ui-icon ui-icon-seek-next' />")
- .click(gotoNext)
- .appendTo($nav);
+ function gotoFirst()
+ {
+ if (getNavState().canGotoFirst)
+ dataView.setPagingOptions({pageNum: 0});
+ }
- $("<span class='ui-icon ui-icon-seek-end' />")
- .click(gotoLast)
- .appendTo($nav);
+ function gotoLast()
+ {
+ var state = getNavState();
+ if (state.canGotoLast)
+ dataView.setPagingOptions({pageNum: state.lastPage});
+ }
- $container.find(".ui-icon")
- .addClass("ui-state-default ui-corner-all")
- .mouseover(function(e) { $(e.target).addClass("ui-state-hover") })
- .mouseout(function(e) { $(e.target).removeClass("ui-state-hover") })
+ function gotoPrev()
+ {
+ var state = getNavState();
+ if (state.canGotoPrev)
+ dataView.setPagingOptions({pageNum: state.pagingInfo.pageNum-1});
+ }
- $container.children().wrapAll("<div class='slick-pager zui-state-default' />");
- }
+ function gotoNext()
+ {
+ var state = getNavState();
+ if (state.canGotoNext)
+ dataView.setPagingOptions({pageNum: state.pagingInfo.pageNum+1});
+ }
+
+ function constructPagerUI()
+ {
+ $container.empty();
+
+ $status = $("<span class='slick-pager-status' />").appendTo($container);
+ var $nav = $("<span class='slick-pager-nav' />").appendTo($container);
+ var $settings = $("<span class='slick-pager-settings' />").appendTo($container);
- function updatePager(pagingInfo)
- {
- var state = getNavState();
+ $settings
+ .append("<span class='slick-pager-settings-expanded' style='display:none'>Show: <a data=0>All</a><a data='-1'>Auto</a><a data=25>25</a><a data=50>50</a><a data=100>100</a></span>");
+
+ $settings.find("a[data]").click(function(e) {
+ var pagesize = $(e.target).attr("data");
+ if (pagesize != undefined)
+ {
+ if (pagesize == -1)
+ {
+ var vp = grid.getViewport();
+ setPageSize(vp.bottom-vp.top);
+ }
+ else
+ setPageSize(parseInt(pagesize));
+ }
+ });
+
+ $("<span class='ui-icon ui-icon-lightbulb' />")
+ .click(function() { $(".slick-pager-settings-expanded").toggle() })
+ .appendTo($settings);
+
+ $("<span class='ui-icon ui-icon-seek-first' />")
+ .click(gotoFirst)
+ .appendTo($nav);
+
+ $("<span class='ui-icon ui-icon-seek-prev' />")
+ .click(gotoPrev)
+ .appendTo($nav);
+
+ $("<span class='ui-icon ui-icon-seek-next' />")
+ .click(gotoNext)
+ .appendTo($nav);
+
+ $("<span class='ui-icon ui-icon-seek-end' />")
+ .click(gotoLast)
+ .appendTo($nav);
+
+ $container.find(".ui-icon")
+ .addClass("ui-state-default ui-corner-all")
+ .mouseover(function(e) { $(e.target).addClass("ui-state-hover") })
+ .mouseout(function(e) { $(e.target).removeClass("ui-state-hover") })
+
+ $container.children().wrapAll("<div class='slick-pager zui-state-default' />");
+ }
+
+
+ function updatePager(pagingInfo)
+ {
+ var state = getNavState();
+
+ $container.find(".slick-pager-nav span").removeClass("ui-state-disabled");
+ if (!state.canGotoFirst) $container.find(".ui-icon-seek-first").addClass("ui-state-disabled");
+ if (!state.canGotoLast) $container.find(".ui-icon-seek-end").addClass("ui-state-disabled");
+ if (!state.canGotoNext) $container.find(".ui-icon-seek-next").addClass("ui-state-disabled");
+ if (!state.canGotoPrev) $container.find(".ui-icon-seek-prev").addClass("ui-state-disabled");
+
+
+ if (pagingInfo.pageSize == 0)
+ $status.text("Showing all " + pagingInfo.totalRows + " rows");
+ else
+ $status.text("Showing page " + (pagingInfo.pageNum+1) + " of " + (Math.floor(pagingInfo.totalRows/pagingInfo.pageSize)+1));
+ }
- $container.find(".slick-pager-nav span").removeClass("ui-state-disabled");
- if (!state.canGotoFirst) $container.find(".ui-icon-seek-first").addClass("ui-state-disabled");
- if (!state.canGotoLast) $container.find(".ui-icon-seek-end").addClass("ui-state-disabled");
- if (!state.canGotoNext) $container.find(".ui-icon-seek-next").addClass("ui-state-disabled");
- if (!state.canGotoPrev) $container.find(".ui-icon-seek-prev").addClass("ui-state-disabled");
- if (pagingInfo.pageSize == 0)
- $status.text("Showing all " + pagingInfo.totalRows + " rows");
- else
- $status.text("Showing page " + (pagingInfo.pageNum+1) + " of " + (Math.floor(pagingInfo.totalRows/pagingInfo.pageSize)+1));
+ init();
}
-
-
- init();
-}
+ // Slick.Controls.Pager
+ $.extend(true, window, { Slick: { Controls: { Pager: SlickGridPager }}});
+})();
+
diff --git a/slick.remotemodel.js b/slick.remotemodel.js
index 4dce1b8..0ffa555 100644
--- a/slick.remotemodel.js
+++ b/slick.remotemodel.js
@@ -18,166 +18,170 @@ function EventHelper() {
}
-
-/***
- * A sample AJAX data store implementation.
- * Right now, it's hooked up to load all Apple-related Digg stories, but can
- * easily be extended to support and JSONP-compatible backend that accepts paging parameters.
- */
-function RemoteModel() {
- // private
- var PAGESIZE = 50;
- var data = {length:0};
- var searchstr = "apple";
- var sortcol = null;
- var sortdir = 1;
- var h_request = null;
- var req = null; // ajax request
- var req_page;
-
- // events
- var onDataLoading = new EventHelper();
- var onDataLoaded = new EventHelper();
-
-
- function init() {
- }
-
-
- function isDataLoaded(from,to) {
- for (var i=from; i<=to; i++) {
- if (data[i] == undefined || data[i] == null)
- return false;
- }
+(function() {
+ /***
+ * A sample AJAX data store implementation.
+ * Right now, it's hooked up to load all Apple-related Digg stories, but can
+ * easily be extended to support and JSONP-compatible backend that accepts paging parameters.
+ */
+ function RemoteModel() {
+ // private
+ var PAGESIZE = 50;
+ var data = {length:0};
+ var searchstr = "apple";
+ var sortcol = null;
+ var sortdir = 1;
+ var h_request = null;
+ var req = null; // ajax request
+ var req_page;
- return true;
- }
-
-
- function clear() {
- for (var key in data) {
- delete data[key];
+ // events
+ var onDataLoading = new EventHelper();
+ var onDataLoaded = new EventHelper();
+
+
+ function init() {
}
- data.length = 0;
- }
-
-
- function ensureData(from,to) {
- if (from < 0)
- from = 0;
- var fromPage = Math.floor(from / PAGESIZE);
- var toPage = Math.floor(to / PAGESIZE);
- while (data[fromPage * PAGESIZE] !== undefined && fromPage < toPage)
- fromPage++;
+ function isDataLoaded(from,to) {
+ for (var i=from; i<=to; i++) {
+ if (data[i] == undefined || data[i] == null)
+ return false;
+ }
+
+ return true;
+ }
+
- while (data[toPage * PAGESIZE] !== undefined && fromPage < toPage)
- toPage--;
+ function clear() {
+ for (var key in data) {
+ delete data[key];
+ }
+ data.length = 0;
+ }
+
+
+ function ensureData(from,to) {
+ if (from < 0)
+ from = 0;
- if (fromPage > toPage || ((fromPage == toPage) && data[fromPage*PAGESIZE] !== undefined)) {
- // TODO: lookeahead
+ var fromPage = Math.floor(from / PAGESIZE);
+ var toPage = Math.floor(to / PAGESIZE);
- //if ()
+ while (data[fromPage * PAGESIZE] !== undefined && fromPage < toPage)
+ fromPage++;
- return;
- }
+ while (data[toPage * PAGESIZE] !== undefined && fromPage < toPage)
+ toPage--;
+
+ if (fromPage > toPage || ((fromPage == toPage) && data[fromPage*PAGESIZE] !== undefined)) {
+ // TODO: lookeahead
+
+ //if ()
+
+ return;
+ }
+
+
+ var url = "http://services.digg.com/search/stories?query=" + searchstr + "&offset=" + (fromPage * PAGESIZE) + "&count=" + (((toPage-fromPage)*PAGESIZE)+PAGESIZE) + "&appkey=http://slickgrid.googlecode.com&type=javascript"
+
+ switch (sortcol) {
+ case "diggs":
+ url += ("&sort=" + ((sortdir>0)?"digg_count-asc":"digg_count-desc"));
+ break;
+ }
- var url = "http://services.digg.com/search/stories?query=" + searchstr + "&offset=" + (fromPage * PAGESIZE) + "&count=" + (((toPage-fromPage)*PAGESIZE)+PAGESIZE) + "&appkey=http://slickgrid.googlecode.com&type=javascript"
-
-
- switch (sortcol) {
- case "diggs":
- url += ("&sort=" + ((sortdir>0)?"digg_count-asc":"digg_count-desc"));
- break;
+
+ if (req) {
+ req.abort();
+ data[req_page*PAGESIZE] = undefined;
+ }
+
+ if (h_request != null)
+ clearTimeout(h_request);
+
+ h_request = setTimeout(function() {
+ for (var i=fromPage; i<=toPage; i++)
+ data[i*PAGESIZE] = null; // null indicates a 'requested but not available yet'
+
+ req_page = fromPage;
+
+ onDataLoading.notify({from:from, to:to});
+
+ req = $.jsonp({
+ url: url,
+ callbackParameter: "callback",
+ cache: true, // Digg doesn't accept the autogenerated cachebuster param
+ success: onSuccess,
+ error: function(){
+ onError(fromPage, toPage)
+ }
+ });
+ }, 50);
}
- if (req) {
- req.abort();
- data[req_page*PAGESIZE] = undefined;
+ function onError(fromPage,toPage) {
+ alert("error loading pages " + fromPage + " to " + toPage);
}
- if (h_request != null)
- window.clearTimeout(h_request);
-
- h_request = window.setTimeout(function() {
- for (var i=fromPage; i<=toPage; i++)
- data[i*PAGESIZE] = null; // null indicates a 'requested but not available yet'
+ function onSuccess(resp) {
+ var from = resp.offset, to = resp.offset + resp.count;
+ data.length = parseInt(resp.total);
- req_page = fromPage;
+ for (var i = 0; i < resp.stories.length; i++) {
+ data[from + i] = resp.stories[i];
+ data[from + i].index = from + i;
+ }
- onDataLoading.notify({from:from, to:to});
+ req = null;
- req = $.jsonp({
- url: url,
- callbackParameter: "callback",
- cache: true, // Digg doesn't accept the autogenerated cachebuster param
- success: onSuccess,
- error: function(){
- onError(fromPage, toPage)
- }
- });
- }, 50);
- }
-
-
- function onError(fromPage,toPage) {
- alert("error loading pages " + fromPage + " to " + toPage);
- }
-
- function onSuccess(resp) {
- var from = resp.offset, to = resp.offset + resp.count;
- data.length = parseInt(resp.total);
+ onDataLoaded.notify({from:from, to:to});
+ }
- for (var i = 0; i < resp.stories.length; i++) {
- data[from + i] = resp.stories[i];
- data[from + i].index = from + i;
+
+ function reloadData(from,to) {
+ for (var i=from; i<=to; i++)
+ delete data[i];
+
+ ensureData(from,to);
}
- req = null;
- onDataLoaded.notify({from:from, to:to});
- }
+ function setSort(column,dir) {
+ sortcol = column;
+ sortdir = dir;
+ clear();
+ }
+
+ function setSearch(str) {
+ searchstr = str;
+ clear();
+ }
- function reloadData(from,to) {
- for (var i=from; i<=to; i++)
- delete data[i];
+ init();
+
+ return {
+ // properties
+ "data": data,
- ensureData(from,to);
+ // methods
+ "clear": clear,
+ "isDataLoaded": isDataLoaded,
+ "ensureData": ensureData,
+ "reloadData": reloadData,
+ "setSort": setSort,
+ "setSearch": setSearch,
+
+ // events
+ "onDataLoading": onDataLoading,
+ "onDataLoaded": onDataLoaded
+ };
}
-
-
- function setSort(column,dir) {
- sortcol = column;
- sortdir = dir;
- clear();
- }
-
- function setSearch(str) {
- searchstr = str;
- clear();
- }
-
-
- init();
-
- return {
- // properties
- "data": data,
-
- // methods
- "clear": clear,
- "isDataLoaded": isDataLoaded,
- "ensureData": ensureData,
- "reloadData": reloadData,
- "setSort": setSort,
- "setSearch": setSearch,
- // events
- "onDataLoading": onDataLoading,
- "onDataLoaded": onDataLoaded
- };
-}
+ // Slick.Data.RemoteModel
+ $.extend(true, window, { Slick: { Data: { RemoteModel: RemoteModel }}});
+})();
diff --git a/tests/model benchmarks.html b/tests/model benchmarks.html
index 4881c38..46a29f1 100644
--- a/tests/model benchmarks.html
+++ b/tests/model benchmarks.html
@@ -6,8 +6,8 @@
</head>
<body>
<script language="JavaScript" src="../lib/firebugx.js"></script>
- <script language="JavaScript" src="../slick.model.js"></script>
<script language="JavaScript" src="../lib/jquery-1.3.2.min.js"></script>
+ <script language="JavaScript" src="../slick.model.js"></script>
<script>
@@ -34,7 +34,7 @@
}
- var dv = new DataView();
+ var dv = new Slick.Data.DataView();
dv.beginUpdate();
dv.setItems(data);
dv.setFilter(filter);
diff --git a/tests/scrolling benchmarks.html b/tests/scrolling benchmarks.html
index 6a0aa98..f5b35a4 100644
--- a/tests/scrolling benchmarks.html
+++ b/tests/scrolling benchmarks.html
@@ -119,7 +119,7 @@
// initialize the model
- dataView = new DataView();
+ dataView = new Slick.Data.DataView();
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(myFilter);
@@ -127,7 +127,7 @@
// initialize the grid
- grid = new SlickGrid($("#myGrid"), dataView.rows, columns, options);
+ grid = new Slick.Grid($("#myGrid"), dataView.rows, columns, options);
grid.onPostProcessRowNode = function(rowNode) {