diff --git a/.DS_Store b/.DS_Store
deleted file mode 100644
index 81ef9d186..000000000
Binary files a/.DS_Store and /dev/null differ
diff --git a/.gitignore b/.gitignore
index 8b3887f2b..d2f89b666 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
.gitk*
-.idea/*
\ No newline at end of file
+.idea/*
+.DS_Store
diff --git a/README.md b/README.md
new file mode 100644
index 000000000..7eb6fdac4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,27 @@
+# Welcome to SlickGrid
+
+Find documentation and examples in [the wiki](https://github.com/mleibman/SlickGrid/wiki).
+
+
+**UPDATE: March 5th, 2014 - I have too many things going on in my life right now to really give SlickGrid support and development the time and attention it deserves. I am not stopping it, but I will most likely be unresponsive for some time. Sorry.**
+
+**UPDATE: This repo hasn't been updated in a while. https://github.com/6pac/SlickGrid/wiki seems to be the most active fork at the moment.**
+
+## SlickGrid is an advanced JavaScript grid/spreadsheet component
+
+Some highlights:
+
+* Adaptive virtual scrolling (handle hundreds of thousands of rows with extreme responsiveness)
+* Extremely fast rendering speed
+* Supports jQuery UI Themes
+* Background post-rendering for richer cells
+* Configurable & customizable
+* Full keyboard navigation
+* Column resize/reorder/show/hide
+* Column autosizing & force-fit
+* Pluggable cell formatters & editors
+* Support for editing and creating new rows.
+* Grouping, filtering, custom aggregators, and more!
+* Advanced detached & multi-field editors with undo/redo support.
+* “GlobalEditorLock” to manage concurrent edits in cases where multiple Views on a page can edit the same data.
+* Support for [millions of rows](http://stackoverflow.com/a/2569488/1269037)
diff --git a/controls/slick.columnpicker.css b/controls/slick.columnpicker.css
index a2845cc86..bcbb37584 100644
--- a/controls/slick.columnpicker.css
+++ b/controls/slick.columnpicker.css
@@ -4,6 +4,7 @@
padding: 6px;
-moz-box-shadow: 2px 2px 2px silver;
-webkit-box-shadow: 2px 2px 2px silver;
+ box-shadow: 2px 2px 2px silver;
min-width: 100px;
cursor: default;
}
@@ -27,4 +28,4 @@
.slick-columnpicker li a:hover {
background: white;
-}
\ No newline at end of file
+}
diff --git a/controls/slick.columnpicker.js b/controls/slick.columnpicker.js
index ecd0d4dcc..dc1672099 100644
--- a/controls/slick.columnpicker.js
+++ b/controls/slick.columnpicker.js
@@ -9,6 +9,7 @@
function init() {
grid.onHeaderContextMenu.subscribe(handleHeaderContextMenu);
+ grid.onColumnsReordered.subscribe(updateColumnOrder);
options = $.extend({}, defaults, options);
$menu = $(" ").appendTo(document.body);
@@ -20,9 +21,16 @@
}
+ function destroy() {
+ grid.onHeaderContextMenu.unsubscribe(handleHeaderContextMenu);
+ grid.onColumnsReordered.unsubscribe(updateColumnOrder);
+ $menu.remove();
+ }
+
function handleHeaderContextMenu(e, args) {
e.preventDefault();
$menu.empty();
+ updateColumnOrder();
columnCheckboxes = [];
var $li, $input;
@@ -68,6 +76,28 @@
.fadeIn(options.fadeSpeed);
}
+ function updateColumnOrder() {
+ // Because columns can be reordered, we have to update the `columns`
+ // to reflect the new order, however we can't just take `grid.getColumns()`,
+ // as it does not include columns currently hidden by the picker.
+ // We create a new `columns` structure by leaving currently-hidden
+ // columns in their original ordinal position and interleaving the results
+ // of the current column sort.
+ var current = grid.getColumns().slice(0);
+ var ordered = new Array(columns.length);
+ for (var i = 0; i < ordered.length; i++) {
+ if ( grid.getColumnIndex(columns[i].id) === undefined ) {
+ // If the column doesn't return a value from getColumnIndex,
+ // it is hidden. Leave it in this position.
+ ordered[i] = columns[i];
+ } else {
+ // Otherwise, grab the next visible column.
+ ordered[i] = current.shift();
+ }
+ }
+ columns = ordered;
+ }
+
function updateColumn(e) {
if ($(e.target).data("option") == "autoresize") {
if (e.target.checked) {
@@ -105,7 +135,16 @@
}
}
+ function getAllColumns() {
+ return columns;
+ }
+
init();
+
+ return {
+ "getAllColumns": getAllColumns,
+ "destroy": destroy
+ };
}
// Slick.Controls.ColumnPicker
diff --git a/controls/slick.pager.js b/controls/slick.pager.js
index b9c6b7413..b3242d979 100644
--- a/controls/slick.pager.js
+++ b/controls/slick.pager.js
@@ -133,6 +133,13 @@
}
if (pagingInfo.pageSize == 0) {
+ var totalRowsCount = dataView.getItems().length;
+ var visibleRowsCount = pagingInfo.totalRows;
+ if (visibleRowsCount < totalRowsCount) {
+ $status.text("Showing " + visibleRowsCount + " of " + totalRowsCount + " rows");
+ } else {
+ $status.text("Showing all " + totalRowsCount + " rows");
+ }
$status.text("Showing all " + pagingInfo.totalRows + " rows");
} else {
$status.text("Showing page " + (pagingInfo.pageNum + 1) + " of " + pagingInfo.totalPages);
diff --git a/examples/example-autotooltips.html b/examples/example-autotooltips.html
new file mode 100644
index 000000000..cdad5488b
--- /dev/null
+++ b/examples/example-autotooltips.html
@@ -0,0 +1,78 @@
+
+
+
+
+ SlickGrid plugin example: AutoTooltips
+
+
+
+
+
+
+
+
+
+
+
+ Demonstrates:
+
+ Instructions:
+ Resize the columns until see ellipsis in column or header. Hover over cell to see tooltip.
+ Usage:
+ plugin = new Slick.AutoTooltips(pluginOptions);
+grid.registerPlugin(plugin);
+grid.render();
+
+ View Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/examples/example-checkbox-row-select.html b/examples/example-checkbox-row-select.html
index 6eebb16c7..4ad6e9be0 100644
--- a/examples/example-checkbox-row-select.html
+++ b/examples/example-checkbox-row-select.html
@@ -5,6 +5,7 @@
+
@@ -28,7 +36,7 @@
-
+
Options:
+
50 rows
+
50k rows
+
500k rows
-
Clear grouping
+
Clear grouping
Group by duration & sort groups by value
-
Group by duration & sort groups by count
+
Group by duration & sort groups by count
-
Group by duration & sort groups by count, group
+ Group by duration & sort groups by count, aggregate
collapsed
- Collapse all groups
+ Group by duration then effort-driven
- Expand all groups
+ Group by duration then effort-driven then percent.
+
+
+ Collapse all groups
+
+ Expand all groups
Demonstrates:
- Fully dynamic and interactive grouping with filtering and aggregates over 50'000 items
+ Fully dynamic and interactive multi-level grouping with filtering and aggregates over 50'000 items
+ Each grouping level can have its own aggregates (over child rows, child groups, or all descendant rows).
Personally, this is just the coolest slickest thing I've ever seen done with DHTML grids!
+
View Source:
+
@@ -71,7 +92,7 @@ Demonstrates:
-
+
@@ -91,11 +112,12 @@ Demonstrates:
var data = [];
var columns = [
{id: "sel", name: "#", field: "num", cssClass: "cell-selection", width: 40, resizable: false, selectable: false, focusable: false },
- {id: "title", name: "Title", field: "title", width: 120, minWidth: 120, cssClass: "cell-title", sortable: true, editor: Slick.Editors.Text},
- {id: "duration", name: "Duration", field: "duration", sortable: true},
+ {id: "title", name: "Title", field: "title", width: 70, minWidth: 50, cssClass: "cell-title", sortable: true, editor: Slick.Editors.Text},
+ {id: "duration", name: "Duration", field: "duration", width: 70, sortable: true, groupTotalsFormatter: sumTotalsFormatter},
{id: "%", name: "% Complete", field: "percentComplete", width: 80, formatter: Slick.Formatters.PercentCompleteBar, sortable: true, groupTotalsFormatter: avgTotalsFormatter},
{id: "start", name: "Start", field: "start", minWidth: 60, sortable: true},
{id: "finish", name: "Finish", field: "finish", minWidth: 60, sortable: true},
+ {id: "cost", name: "Cost", field: "cost", width: 90, sortable: true, groupTotalsFormatter: sumTotalsFormatter},
{id: "effort-driven", name: "Effort Driven", width: 80, minWidth: 20, maxWidth: 80, cssClass: "cell-effort-driven", field: "effortDriven", formatter: Slick.Formatters.Checkmark, sortable: true}
];
@@ -110,7 +132,19 @@ Demonstrates:
var prevPercentCompleteThreshold = 0;
function avgTotalsFormatter(totals, columnDef) {
- return "avg: " + Math.round(totals.avg[columnDef.field]) + "%";
+ var val = totals.avg && totals.avg[columnDef.field];
+ if (val != null) {
+ return "avg: " + Math.round(val) + "%";
+ }
+ return "";
+}
+
+function sumTotalsFormatter(totals, columnDef) {
+ var val = totals.sum && totals.sum[columnDef.field];
+ if (val != null) {
+ return "total: " + ((Math.round(parseFloat(val)*100)/100));
+ }
+ return "";
}
function myFilter(item, args) {
@@ -126,71 +160,129 @@ Demonstrates:
return (x == y ? 0 : (x > y ? 1 : -1));
}
-function collapseAllGroups() {
- dataView.beginUpdate();
- for (var i = 0; i < dataView.getGroups().length; i++) {
- dataView.collapseGroup(dataView.getGroups()[i].value);
- }
- dataView.endUpdate();
-}
-
-function expandAllGroups() {
- dataView.beginUpdate();
- for (var i = 0; i < dataView.getGroups().length; i++) {
- dataView.expandGroup(dataView.getGroups()[i].value);
- }
- dataView.endUpdate();
+function groupByDuration() {
+ dataView.setGrouping({
+ getter: "duration",
+ formatter: function (g) {
+ return "Duration: " + g.value + " (" + g.count + " items) ";
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg("percentComplete"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ aggregateCollapsed: false,
+ lazyTotalsCalculation: true
+ });
}
-function clearGrouping() {
- dataView.groupBy(null);
+function groupByDurationOrderByCount(aggregateCollapsed) {
+ dataView.setGrouping({
+ getter: "duration",
+ formatter: function (g) {
+ return "Duration: " + g.value + " (" + g.count + " items) ";
+ },
+ comparer: function (a, b) {
+ return a.count - b.count;
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg("percentComplete"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ aggregateCollapsed: aggregateCollapsed,
+ lazyTotalsCalculation: true
+ });
}
-function groupByDuration() {
- dataView.groupBy(
- "duration",
- function (g) {
+function groupByDurationEffortDriven() {
+ dataView.setGrouping([
+ {
+ getter: "duration",
+ formatter :function (g) {
return "Duration: " + g.value + " (" + g.count + " items) ";
},
- function (a, b) {
- return a.value - b.value;
- }
- );
- dataView.setAggregators([
- new Slick.Data.Aggregators.Avg("percentComplete")
- ], false);
+ aggregators: [
+ new Slick.Data.Aggregators.Sum("duration"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ aggregateCollapsed: true,
+ lazyTotalsCalculation: true
+ },
+ {
+ getter: "effortDriven",
+ formatter :function (g) {
+ return "Effort-Driven: " + (g.value ? "True" : "False") + " (" + g.count + " items) ";
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg("percentComplete"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ collapsed: true,
+ lazyTotalsCalculation: true
+ }
+ ]);
}
-function groupByDurationOrderByCount() {
- dataView.groupBy(
- "duration",
- function (g) {
+function groupByDurationEffortDrivenPercent() {
+ dataView.setGrouping([
+ {
+ getter: "duration",
+ formatter: function (g) {
return "Duration: " + g.value + " (" + g.count + " items) ";
},
- function (a, b) {
- return a.count - b.count;
- }
- );
- dataView.setAggregators([
- new Slick.Data.Aggregators.Avg("percentComplete")
- ], false);
+ aggregators: [
+ new Slick.Data.Aggregators.Sum("duration"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ aggregateCollapsed: true,
+ lazyTotalsCalculation: true
+ },
+ {
+ getter: "effortDriven",
+ formatter: function (g) {
+ return "Effort-Driven: " + (g.value ? "True" : "False") + " (" + g.count + " items) ";
+ },
+ aggregators :[
+ new Slick.Data.Aggregators.Sum("duration"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ lazyTotalsCalculation: true
+ },
+ {
+ getter: "percentComplete",
+ formatter: function (g) {
+ return "% Complete: " + g.value + " (" + g.count + " items) ";
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg("percentComplete")
+ ],
+ aggregateCollapsed: true,
+ collapsed: true,
+ lazyTotalsCalculation: true
+ }
+ ]);
}
-function groupByDurationOrderByCountGroupCollapsed() {
- dataView.groupBy(
- "duration",
- function (g) {
- return "Duration: " + g.value + " (" + g.count + " items) ";
- },
- function (a, b) {
- return a.count - b.count;
- }
- );
- dataView.setAggregators([
- new Slick.Data.Aggregators.Avg("percentComplete")
- ], true);
+function loadData(count) {
+ var someDates = ["01/01/2009", "02/02/2009", "03/03/2009"];
+ data = [];
+ // prepare the data
+ for (var i = 0; i < count; i++) {
+ var d = (data[i] = {});
+
+ d["id"] = "id_" + i;
+ d["num"] = i;
+ d["title"] = "Task " + i;
+ d["duration"] = Math.round(Math.random() * 30);
+ d["percentComplete"] = Math.round(Math.random() * 100);
+ d["start"] = someDates[ Math.floor((Math.random()*2)) ];
+ d["finish"] = someDates[ Math.floor((Math.random()*2)) ];
+ d["cost"] = Math.round(Math.random() * 10000) / 100;
+ d["effortDriven"] = (i % 5 == 0);
+ }
+ dataView.setItems(data);
}
+
$(".grid-header .ui-icon")
.addClass("ui-state-default ui-corner-all")
.mouseover(function (e) {
@@ -201,20 +293,6 @@ Demonstrates:
});
$(function () {
- // prepare the data
- for (var i = 0; i < 50000; i++) {
- var d = (data[i] = {});
-
- d["id"] = "id_" + i;
- d["num"] = i;
- d["title"] = "Task " + i;
- d["duration"] = Math.round(Math.random() * 14);
- d["percentComplete"] = Math.round(Math.random() * 100);
- d["start"] = "01/01/2009";
- d["finish"] = "01/05/2009";
- d["effortDriven"] = (i % 5 == 0);
- }
-
var groupItemMetadataProvider = new Slick.Data.GroupItemMetadataProvider();
dataView = new Slick.Data.DataView({
groupItemMetadataProvider: groupItemMetadataProvider,
@@ -309,24 +387,12 @@ Demonstrates:
// initialize the model after all the events have been hooked up
dataView.beginUpdate();
- dataView.setItems(data);
dataView.setFilter(myFilter);
dataView.setFilterArgs({
percentComplete: percentCompleteThreshold
});
- dataView.groupBy(
- "duration",
- function (g) {
- return "Duration: " + g.value + " (" + g.count + " items) ";
- },
- function (a, b) {
- return a.value - b.value;
- }
- );
- dataView.setAggregators([
- new Slick.Data.Aggregators.Avg("percentComplete")
- ], false);
- dataView.collapseGroup(0);
+ loadData(50);
+ groupByDuration();
dataView.endUpdate();
$("#gridContainer").resizable();
diff --git a/examples/example-header-row.html b/examples/example-header-row.html
index 6f309bc9b..1d0110c98 100644
--- a/examples/example-header-row.html
+++ b/examples/example-header-row.html
@@ -35,6 +35,10 @@ Demonstrates:
Using a fixed header row to implement column-level filters
Type numbers in textboxes to filter grid data
+ View Source:
+
@@ -42,7 +46,7 @@ Demonstrates:
-
+
diff --git a/examples/example-multi-column-sort.html b/examples/example-multi-column-sort.html
index 2e4f7a941..6edc0033b 100644
--- a/examples/example-multi-column-sort.html
+++ b/examples/example-multi-column-sort.html
@@ -18,12 +18,16 @@ Demonstrates:
basic grid with multi-column sort option
+ View Source:
+
-
+
diff --git a/examples/example-optimizing-dataview.html b/examples/example-optimizing-dataview.html
index 5622dc044..31b3cf7f3 100644
--- a/examples/example-optimizing-dataview.html
+++ b/examples/example-optimizing-dataview.html
@@ -61,13 +61,17 @@
Providing a range of rows for which onRowsChanged even should be fired.
+ View Source:
+
-
+
diff --git a/examples/example-plugin-headerbuttons.html b/examples/example-plugin-headerbuttons.html
index 356439a81..15f95989e 100644
--- a/examples/example-plugin-headerbuttons.html
+++ b/examples/example-plugin-headerbuttons.html
@@ -31,6 +31,10 @@
This example demonstrates using the Slick.Plugins.HeaderButtons plugin to easily add buttons to column
headers. These buttons can be specified directly in the column definition, and are very easy to configure and use.
+ View Source:
+
@@ -38,7 +42,7 @@
-
+
@@ -48,7 +52,7 @@
var grid;
var data = [];
var options = {
- enableCellNavigation:true
+ enableCellNavigation: true
};
var columns = [];
var columnsWithHighlightingById = {};
@@ -61,6 +65,7 @@
name: String.fromCharCode("A".charCodeAt(0) + i),
field: i,
width: 90,
+ sortable: true,
formatter: highlightingFormatter,
header: {
buttons: [
diff --git a/examples/example-plugin-headermenu.html b/examples/example-plugin-headermenu.html
index 895919a90..341c997e2 100644
--- a/examples/example-plugin-headermenu.html
+++ b/examples/example-plugin-headermenu.html
@@ -54,11 +54,15 @@
This example demonstrates using the Slick.Plugins.HeaderMenu plugin to add drop-down menus to column
headers. (Hover over the headers.)
+ View Source:
+
-
+
diff --git a/examples/example-spreadsheet.html b/examples/example-spreadsheet.html
index 9fe72141e..0eadeaa3d 100644
--- a/examples/example-spreadsheet.html
+++ b/examples/example-spreadsheet.html
@@ -29,6 +29,10 @@ Demonstrates:
Use Esc to cancel a copy and paste operation
Edit the cell and select a cell range to paste the range
+ View Source:
+
@@ -36,7 +40,7 @@ Demonstrates:
-
+
diff --git a/examples/example-totals-via-data-provider.html b/examples/example-totals-via-data-provider.html
new file mode 100644
index 000000000..626092f51
--- /dev/null
+++ b/examples/example-totals-via-data-provider.html
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Demonstrates:
+
+ Implementing a data provider to create a totals row at the end of the grid.
+ This is a simplification of what the DataView does.
+
+
+
View Source:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/example1-simple.html b/examples/example1-simple.html
index 6f151d414..5c50a9e5f 100644
--- a/examples/example1-simple.html
+++ b/examples/example1-simple.html
@@ -18,12 +18,16 @@ Demonstrates:
basic grid with minimal configuration
+ View Source:
+
-
+
diff --git a/examples/example10-async-post-render.html b/examples/example10-async-post-render.html
index e72226f48..9f911b522 100644
--- a/examples/example10-async-post-render.html
+++ b/examples/example10-async-post-render.html
@@ -52,13 +52,17 @@ Demonstrates:
The graphs themselves are created using the excellent jQuery Sparklines library.
+ View Source:
+
-
+
diff --git a/examples/example11-autoheight.html b/examples/example11-autoheight.html
index f818ca982..a777a0304 100644
--- a/examples/example11-autoheight.html
+++ b/examples/example11-autoheight.html
@@ -39,11 +39,15 @@ Demonstrates:
autoHeight:true grid option
+ View Source:
+
-
+
diff --git a/examples/example12-fillbrowser.html b/examples/example12-fillbrowser.html
index c17496c34..0f9ff200e 100644
--- a/examples/example12-fillbrowser.html
+++ b/examples/example12-fillbrowser.html
@@ -50,10 +50,14 @@ Demonstrates:
Grid resizing when browser window changes size
Overall performance of the grid when displaying large tabular data (17 columns x 10,000 rows)
+ View Source:
+
-
+
diff --git a/examples/example13-getItem-sorting.html b/examples/example13-getItem-sorting.html
index 6825021fc..b971e93ff 100644
--- a/examples/example13-getItem-sorting.html
+++ b/examples/example13-getItem-sorting.html
@@ -49,10 +49,14 @@ Demonstrates:
Sorting grid items by an index
Using the getItem method to provide data
+ View Source:
+
-
+
diff --git a/examples/example14-highlighting.html b/examples/example14-highlighting.html
index 5b8228062..e85e947aa 100644
--- a/examples/example14-highlighting.html
+++ b/examples/example14-highlighting.html
@@ -47,6 +47,10 @@ Demonstrates
Controls
Start simulation
Find current server
+ View Source:
+
@@ -54,7 +58,7 @@ Controls
-
+
diff --git a/examples/example2-formatters.html b/examples/example2-formatters.html
index fd1b366de..d89be12c9 100644
--- a/examples/example2-formatters.html
+++ b/examples/example2-formatters.html
@@ -17,6 +17,9 @@
+
+
+
@@ -28,25 +31,36 @@ Demonstrates:
width, minWidth, maxWidth, resizable, cssClass column attributes
custom column formatters
+ View Source:
+
+
+
-
+
-
+
diff --git a/examples/example3a-compound-editors.html b/examples/example3a-compound-editors.html
index 24e631ed0..a61706521 100644
--- a/examples/example3a-compound-editors.html
+++ b/examples/example3a-compound-editors.html
@@ -26,6 +26,12 @@ Demonstrates:
providing validation from the editor
hooking into validation events
+ View Source:
+
+
+
@@ -33,7 +39,7 @@ Demonstrates:
-
+
diff --git a/examples/example3b-editing-with-undo.html b/examples/example3b-editing-with-undo.html
index d48c87b0f..c8182e9b0 100644
--- a/examples/example3b-editing-with-undo.html
+++ b/examples/example3b-editing-with-undo.html
@@ -30,6 +30,10 @@ Demonstrates:
Controls:
Undo
+ View Source:
+
@@ -37,7 +41,7 @@ Controls:
-
+
diff --git a/examples/example4-model.html b/examples/example4-model.html
index bebd733e2..ea7277164 100644
--- a/examples/example4-model.html
+++ b/examples/example4-model.html
@@ -77,6 +77,11 @@ Demonstrates:
Paging.
inline filter panel
+ View Source:
+
+
@@ -91,7 +96,7 @@ Demonstrates:
-
+
diff --git a/examples/example5-collapsing.html b/examples/example5-collapsing.html
index 9202c3b54..9524f58b7 100644
--- a/examples/example5-collapsing.html
+++ b/examples/example5-collapsing.html
@@ -54,6 +54,11 @@ Demonstrates:
implementing expand/collapse as a filter for DataView
+
+ View Source:
+
@@ -62,7 +67,7 @@ Demonstrates:
-
+
@@ -152,20 +157,19 @@ Demonstrates:
// prepare the data
for (var i = 0; i < 1000; i++) {
var d = (data[i] = {});
- var parent = null;
+ var parent;
- if (Math.random() > 0.8) {
+ if (Math.random() > 0.8 && i > 0) {
indent++;
- parent = i - 1;
- parents.push(parent);
+ parents.push(i - 1);
} else if (Math.random() < 0.3 && indent > 0) {
indent--;
- parent = parents.pop();
- } else if (parents.length > 0) {
+ parents.pop();
+ }
+
+ if (parents.length > 0) {
parent = parents[parents.length - 1];
- }
-
- if (indent == 0) {
+ } else {
parent = null;
}
diff --git a/examples/example6-ajax-loading.html b/examples/example6-ajax-loading.html
index a85fa2dd5..749919c49 100644
--- a/examples/example6-ajax-loading.html
+++ b/examples/example6-ajax-loading.html
@@ -37,10 +37,10 @@
@@ -55,18 +55,22 @@
Demonstrates:
WARNING:
- Digg API uses request rate limiting. You may occasionally get an error if you do a frequent
- scrolling/resorting/searching.
+ API access to Hackernews provided through ThriftDB has some latency when paging through results. Be patient.
+
+
View Source:
+
-
-
+
+
@@ -77,15 +81,25 @@ WARNING:
var loader = new Slick.Data.RemoteModel();
var storyTitleFormatter = function (row, cell, value, columnDef, dataContext) {
- return "" +
- dataContext["title"] + " " + dataContext["description"];
+ s ="" +
+ dataContext["title"] + " ";
+ desc = dataContext["text"];
+ if (desc) { // on Hackernews many stories don't have a description
+ s += desc;
+ }
+ return s;
+ };
+
+ var dateFormatter = function (row, cell, value, columnDef, dataContext) {
+ return (value.getMonth()+1) + "/" + value.getDate() + "/" + value.getFullYear();
};
var columns = [
{id: "num", name: "#", field: "index", width: 40},
- {id: "story", name: "Story", width: 580, formatter: storyTitleFormatter, cssClass: "cell-story"},
- {id: "diggs", name: "Diggs", field: "diggs", width: 60, sortable: true}
+ {id: "story", name: "Story", width: 520, formatter: storyTitleFormatter, cssClass: "cell-story"},
+ {id: "date", name: "Date", field: "create_ts", width: 60, formatter: dateFormatter, sortable: true},
+ {id: "points", name: "Points", field: "points", width: 60, sortable: true}
];
var options = {
@@ -145,6 +159,10 @@ WARNING:
}
});
+ loader.setSearch($("#txtSearch").val());
+ loader.setSort("create_ts", -1);
+ grid.setSortColumn("date", false);
+
// load the first page
grid.onViewportChanged.notify();
})
diff --git a/examples/example7-events.html b/examples/example7-events.html
index fc5122397..a8b0b4c0b 100644
--- a/examples/example7-events.html
+++ b/examples/example7-events.html
@@ -47,6 +47,10 @@ Demonstrates:
Right-click the row to open the context menu
Click the priority cell to toggle values
+ View Source:
+
@@ -61,7 +65,7 @@ Demonstrates:
-
+
@@ -109,6 +113,10 @@ Demonstrates:
grid.onClick.subscribe(function (e) {
var cell = grid.getCellFromEvent(e);
if (grid.getColumns()[cell.cell].id == "priority") {
+ if (!grid.getEditorLock().commitCurrentEdit()) {
+ return;
+ }
+
var states = { "Low": "Medium", "Medium": "High", "High": "Low" };
data[cell.row].priority = states[data[cell.row].priority];
grid.updateRow(cell.row);
@@ -121,7 +129,9 @@ Demonstrates:
if (!$(e.target).is("li")) {
return;
}
-
+ if (!grid.getEditorLock().commitCurrentEdit()) {
+ return;
+ }
var row = $(this).data("row");
data[row].priority = $(e.target).attr("data");
grid.updateRow(row);
diff --git a/examples/example8-alternative-display.html b/examples/example8-alternative-display.html
index 64a5e6955..fdba4f9fa 100644
--- a/examples/example8-alternative-display.html
+++ b/examples/example8-alternative-display.html
@@ -73,6 +73,11 @@ Demonstrates:
SlickGrid's virtual rendering technology.
+ View Source:
+
+
@@ -93,7 +98,7 @@ Demonstrates:
-
+
diff --git a/examples/example9-row-reordering.html b/examples/example9-row-reordering.html
index ed54f6077..672dac328 100644
--- a/examples/example9-row-reordering.html
+++ b/examples/example9-row-reordering.html
@@ -7,10 +7,6 @@
+
+
+ Examples
+
+
+
diff --git a/images/arrow_redo.png b/images/arrow_redo.png
index fdc394c7c..4f7f55d6f 100644
Binary files a/images/arrow_redo.png and b/images/arrow_redo.png differ
diff --git a/images/arrow_right_peppermint.png b/images/arrow_right_peppermint.png
index 1804fa9f9..872256786 100644
Binary files a/images/arrow_right_peppermint.png and b/images/arrow_right_peppermint.png differ
diff --git a/images/arrow_right_spearmint.png b/images/arrow_right_spearmint.png
index 298515ab6..277ddde38 100644
Binary files a/images/arrow_right_spearmint.png and b/images/arrow_right_spearmint.png differ
diff --git a/images/arrow_undo.png b/images/arrow_undo.png
index 6972c5e59..bc9924ac0 100644
Binary files a/images/arrow_undo.png and b/images/arrow_undo.png differ
diff --git a/images/bullet_blue.png b/images/bullet_blue.png
index a7651ec8a..79d978c36 100644
Binary files a/images/bullet_blue.png and b/images/bullet_blue.png differ
diff --git a/images/bullet_star.png b/images/bullet_star.png
index 3829023b8..142ea482a 100644
Binary files a/images/bullet_star.png and b/images/bullet_star.png differ
diff --git a/images/bullet_toggle_minus.png b/images/bullet_toggle_minus.png
index b47ce55f6..f5aa0450d 100644
Binary files a/images/bullet_toggle_minus.png and b/images/bullet_toggle_minus.png differ
diff --git a/images/bullet_toggle_plus.png b/images/bullet_toggle_plus.png
index 9ab4a8966..a96505342 100644
Binary files a/images/bullet_toggle_plus.png and b/images/bullet_toggle_plus.png differ
diff --git a/images/drag-handle.png b/images/drag-handle.png
index 86727b194..ad7531cf0 100644
Binary files a/images/drag-handle.png and b/images/drag-handle.png differ
diff --git a/images/help.png b/images/help.png
index 0eff0a5cb..85eca0950 100644
Binary files a/images/help.png and b/images/help.png differ
diff --git a/images/sort-asc.png b/images/sort-asc.png
index e6b6264fc..8604ff4e0 100644
Binary files a/images/sort-asc.png and b/images/sort-asc.png differ
diff --git a/images/sort-desc.png b/images/sort-desc.png
index 74ad1540e..a2a6adf93 100644
Binary files a/images/sort-desc.png and b/images/sort-desc.png differ
diff --git a/images/stripes.png b/images/stripes.png
index 0c293a927..c3c4b28a8 100644
Binary files a/images/stripes.png and b/images/stripes.png differ
diff --git a/images/tag_red.png b/images/tag_red.png
index 6ebb37d25..d290fcd79 100644
Binary files a/images/tag_red.png and b/images/tag_red.png differ
diff --git a/images/tick.png b/images/tick.png
index a9925a06a..3899d71df 100644
Binary files a/images/tick.png and b/images/tick.png differ
diff --git a/lib/jquery.event.drag-2.0.min.js b/lib/jquery.event.drag-2.0.min.js
deleted file mode 100644
index 2cb7fee0e..000000000
--- a/lib/jquery.event.drag-2.0.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
- * jquery.event.drag - v 2.0.0
- * Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
- * Open Source MIT License - http://threedubmedia.com/code/license
- */
-;(function(f){f.fn.drag=function(b,a,d){var e=typeof b=="string"?b:"",k=f.isFunction(b)?b:f.isFunction(a)?a:null;if(e.indexOf("drag")!==0)e="drag"+e;d=(b==k?a:d)||{};return k?this.bind(e,d,k):this.trigger(e)};var i=f.event,h=i.special,c=h.drag={defaults:{which:1,distance:0,not:":input",handle:null,relative:false,drop:true,click:false},datakey:"dragdata",livekey:"livedrag",add:function(b){var a=f.data(this,c.datakey),d=b.data||{};a.related+=1;if(!a.live&&b.selector){a.live=true;i.add(this,"draginit."+ c.livekey,c.delegate)}f.each(c.defaults,function(e){if(d[e]!==undefined)a[e]=d[e]})},remove:function(){f.data(this,c.datakey).related-=1},setup:function(){if(!f.data(this,c.datakey)){var b=f.extend({related:0},c.defaults);f.data(this,c.datakey,b);i.add(this,"mousedown",c.init,b);this.attachEvent&&this.attachEvent("ondragstart",c.dontstart)}},teardown:function(){if(!f.data(this,c.datakey).related){f.removeData(this,c.datakey);i.remove(this,"mousedown",c.init);i.remove(this,"draginit",c.delegate);c.textselect(true); this.detachEvent&&this.detachEvent("ondragstart",c.dontstart)}},init:function(b){var a=b.data,d;if(!(a.which>0&&b.which!=a.which))if(!f(b.target).is(a.not))if(!(a.handle&&!f(b.target).closest(a.handle,b.currentTarget).length)){a.propagates=1;a.interactions=[c.interaction(this,a)];a.target=b.target;a.pageX=b.pageX;a.pageY=b.pageY;a.dragging=null;d=c.hijack(b,"draginit",a);if(a.propagates){if((d=c.flatten(d))&&d.length){a.interactions=[];f.each(d,function(){a.interactions.push(c.interaction(this,a))})}a.propagates= a.interactions.length;a.drop!==false&&h.drop&&h.drop.handler(b,a);c.textselect(false);i.add(document,"mousemove mouseup",c.handler,a);return false}}},interaction:function(b,a){return{drag:b,callback:new c.callback,droppable:[],offset:f(b)[a.relative?"position":"offset"]()||{top:0,left:0}}},handler:function(b){var a=b.data;switch(b.type){case !a.dragging&&"mousemove":if(Math.pow(b.pageX-a.pageX,2)+Math.pow(b.pageY-a.pageY,2) 0 && event.which != dd.which )
+ return;
+ // check for suppressed selector
+ if ( $( event.target ).is( dd.not ) )
+ return;
+ // check for handle selector
+ if ( dd.handle && !$( event.target ).closest( dd.handle, event.currentTarget ).length )
+ return;
+
+ drag.touched = event.type == 'touchstart' ? this : null;
+ dd.propagates = 1;
+ dd.mousedown = this;
+ dd.interactions = [ drag.interaction( this, dd ) ];
+ dd.target = event.target;
+ dd.pageX = event.pageX;
+ dd.pageY = event.pageY;
+ dd.dragging = null;
+ // handle draginit event...
+ results = drag.hijack( event, "draginit", dd );
+ // early cancel
+ if ( !dd.propagates )
+ return;
+ // flatten the result set
+ results = drag.flatten( results );
+ // insert new interaction elements
+ if ( results && results.length ){
+ dd.interactions = [];
+ $.each( results, function(){
+ dd.interactions.push( drag.interaction( this, dd ) );
+ });
+ }
+ // remember how many interactions are propagating
+ dd.propagates = dd.interactions.length;
+ // locate and init the drop targets
+ if ( dd.drop !== false && $special.drop )
+ $special.drop.handler( event, dd );
+ // disable text selection
+ drag.textselect( false );
+ // bind additional events...
+ if ( drag.touched )
+ $event.add( drag.touched, "touchmove touchend", drag.handler, dd );
+ else
+ $event.add( document, "mousemove mouseup", drag.handler, dd );
+ // helps prevent text selection or scrolling
+ if ( !drag.touched || dd.live )
+ return false;
+ },
+
+ // returns an interaction object
+ interaction: function( elem, dd ){
+ var offset = $( elem )[ dd.relative ? "position" : "offset" ]() || { top:0, left:0 };
+ return {
+ drag: elem,
+ callback: new drag.callback(),
+ droppable: [],
+ offset: offset
+ };
+ },
+
+ // handle drag-releatd DOM events
+ handler: function( event ){
+ // read the data before hijacking anything
+ var dd = event.data;
+ // handle various events
+ switch ( event.type ){
+ // mousemove, check distance, start dragging
+ case !dd.dragging && 'touchmove':
+ event.preventDefault();
+ case !dd.dragging && 'mousemove':
+ // drag tolerance, x≤ + y≤ = distance≤
+ if ( Math.pow( event.pageX-dd.pageX, 2 ) + Math.pow( event.pageY-dd.pageY, 2 ) < Math.pow( dd.distance, 2 ) )
+ break; // distance tolerance not reached
+ event.target = dd.target; // force target from "mousedown" event (fix distance issue)
+ drag.hijack( event, "dragstart", dd ); // trigger "dragstart"
+ if ( dd.propagates ) // "dragstart" not rejected
+ dd.dragging = true; // activate interaction
+ // mousemove, dragging
+ case 'touchmove':
+ event.preventDefault();
+ case 'mousemove':
+ if ( dd.dragging ){
+ // trigger "drag"
+ drag.hijack( event, "drag", dd );
+ if ( dd.propagates ){
+ // manage drop events
+ if ( dd.drop !== false && $special.drop )
+ $special.drop.handler( event, dd ); // "dropstart", "dropend"
+ break; // "drag" not rejected, stop
+ }
+ event.type = "mouseup"; // helps "drop" handler behave
+ }
+ // mouseup, stop dragging
+ case 'touchend':
+ case 'mouseup':
+ default:
+ if ( drag.touched )
+ $event.remove( drag.touched, "touchmove touchend", drag.handler ); // remove touch events
+ else
+ $event.remove( document, "mousemove mouseup", drag.handler ); // remove page events
+ if ( dd.dragging ){
+ if ( dd.drop !== false && $special.drop )
+ $special.drop.handler( event, dd ); // "drop"
+ drag.hijack( event, "dragend", dd ); // trigger "dragend"
+ }
+ drag.textselect( true ); // enable text selection
+ // if suppressing click events...
+ if ( dd.click === false && dd.dragging )
+ $.data( dd.mousedown, "suppress.click", new Date().getTime() + 5 );
+ dd.dragging = drag.touched = false; // deactivate element
+ break;
+ }
+ },
+
+ // re-use event object for custom events
+ hijack: function( event, type, dd, x, elem ){
+ // not configured
+ if ( !dd )
+ return;
+ // remember the original event and type
+ var orig = { event:event.originalEvent, type:event.type },
+ // is the event drag related or drog related?
+ mode = type.indexOf("drop") ? "drag" : "drop",
+ // iteration vars
+ result, i = x || 0, ia, $elems, callback,
+ len = !isNaN( x ) ? x : dd.interactions.length;
+ // modify the event type
+ event.type = type;
+ // remove the original event
+ event.originalEvent = null;
+ // initialize the results
+ dd.results = [];
+ // handle each interacted element
+ do if ( ia = dd.interactions[ i ] ){
+ // validate the interaction
+ if ( type !== "dragend" && ia.cancelled )
+ continue;
+ // set the dragdrop properties on the event object
+ callback = drag.properties( event, dd, ia );
+ // prepare for more results
+ ia.results = [];
+ // handle each element
+ $( elem || ia[ mode ] || dd.droppable ).each(function( p, subject ){
+ // identify drag or drop targets individually
+ callback.target = subject;
+ // force propagtion of the custom event
+ event.isPropagationStopped = function(){ return false; };
+ // handle the event
+ result = subject ? $event.dispatch.call( subject, event, callback ) : null;
+ // stop the drag interaction for this element
+ if ( result === false ){
+ if ( mode == "drag" ){
+ ia.cancelled = true;
+ dd.propagates -= 1;
+ }
+ if ( type == "drop" ){
+ ia[ mode ][p] = null;
+ }
+ }
+ // assign any dropinit elements
+ else if ( type == "dropinit" )
+ ia.droppable.push( drag.element( result ) || subject );
+ // accept a returned proxy element
+ if ( type == "dragstart" )
+ ia.proxy = $( drag.element( result ) || ia.drag )[0];
+ // remember this result
+ ia.results.push( result );
+ // forget the event result, for recycling
+ delete event.result;
+ // break on cancelled handler
+ if ( type !== "dropinit" )
+ return result;
+ });
+ // flatten the results
+ dd.results[ i ] = drag.flatten( ia.results );
+ // accept a set of valid drop targets
+ if ( type == "dropinit" )
+ ia.droppable = drag.flatten( ia.droppable );
+ // locate drop targets
+ if ( type == "dragstart" && !ia.cancelled )
+ callback.update();
+ }
+ while ( ++i < len )
+ // restore the original event & type
+ event.type = orig.type;
+ event.originalEvent = orig.event;
+ // return all handler results
+ return drag.flatten( dd.results );
+ },
+
+ // extend the callback object with drag/drop properties...
+ properties: function( event, dd, ia ){
+ var obj = ia.callback;
+ // elements
+ obj.drag = ia.drag;
+ obj.proxy = ia.proxy || ia.drag;
+ // starting mouse position
+ obj.startX = dd.pageX;
+ obj.startY = dd.pageY;
+ // current distance dragged
+ obj.deltaX = event.pageX - dd.pageX;
+ obj.deltaY = event.pageY - dd.pageY;
+ // original element position
+ obj.originalX = ia.offset.left;
+ obj.originalY = ia.offset.top;
+ // adjusted element position
+ obj.offsetX = obj.originalX + obj.deltaX;
+ obj.offsetY = obj.originalY + obj.deltaY;
+ // assign the drop targets information
+ obj.drop = drag.flatten( ( ia.drop || [] ).slice() );
+ obj.available = drag.flatten( ( ia.droppable || [] ).slice() );
+ return obj;
+ },
+
+ // determine is the argument is an element or jquery instance
+ element: function( arg ){
+ if ( arg && ( arg.jquery || arg.nodeType == 1 ) )
+ return arg;
+ },
+
+ // flatten nested jquery objects and arrays into a single dimension array
+ flatten: function( arr ){
+ return $.map( arr, function( member ){
+ return member && member.jquery ? $.makeArray( member ) :
+ member && member.length ? drag.flatten( member ) : member;
+ });
+ },
+
+ // toggles text selection attributes ON (true) or OFF (false)
+ textselect: function( bool ){
+ $( document )[ bool ? "unbind" : "bind" ]("selectstart", drag.dontstart )
+ .css("MozUserSelect", bool ? "" : "none" );
+ // .attr("unselectable", bool ? "off" : "on" )
+ document.unselectable = bool ? "off" : "on";
+ },
+
+ // suppress "selectstart" and "ondragstart" events
+ dontstart: function(){
+ return false;
+ },
+
+ // a callback instance contructor
+ callback: function(){}
+
+};
+
+// callback methods
+drag.callback.prototype = {
+ update: function(){
+ if ( $special.drop && this.available.length )
+ $.each( this.available, function( i ){
+ $special.drop.locate( this, i );
+ });
+ }
+};
+
+// patch $.event.$dispatch to allow suppressing clicks
+var $dispatch = $event.dispatch;
+$event.dispatch = function( event ){
+ if ( $.data( this, "suppress."+ event.type ) - new Date().getTime() > 0 ){
+ $.removeData( this, "suppress."+ event.type );
+ return;
+ }
+ return $dispatch.apply( this, arguments );
+};
+
+// event fix hooks for touch events...
+var touchHooks =
+$event.fixHooks.touchstart =
+$event.fixHooks.touchmove =
+$event.fixHooks.touchend =
+$event.fixHooks.touchcancel = {
+ props: "clientX clientY pageX pageY screenX screenY".split( " " ),
+ filter: function( event, orig ) {
+ if ( orig ){
+ var touched = ( orig.touches && orig.touches[0] )
+ || ( orig.changedTouches && orig.changedTouches[0] )
+ || null;
+ // iOS webkit: touchstart, touchmove, touchend
+ if ( touched )
+ $.each( touchHooks.props, function( i, prop ){
+ event[ prop ] = touched[ prop ];
+ });
+ }
+ return event;
+ }
+};
+
+// share the same special event configuration with related events...
+$special.draginit = $special.dragstart = $special.dragend = drag;
+
+})( jQuery );
\ No newline at end of file
diff --git a/lib/jquery.event.drop-2.0.min.js b/lib/jquery.event.drop-2.0.min.js
deleted file mode 100644
index b98857517..000000000
--- a/lib/jquery.event.drop-2.0.min.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*!
- * jquery.event.drop - v 2.0.0
- * Copyright (c) 2010 Three Dub Media - http://threedubmedia.com
- * Open Source MIT License - http://threedubmedia.com/code/license
- */
-;(function(f){f.fn.drop=function(c,a,d){var g=typeof c=="string"?c:"",e=f.isFunction(c)?c:f.isFunction(a)?a:null;if(g.indexOf("drop")!==0)g="drop"+g;d=(c==e?a:d)||{};return e?this.bind(g,d,e):this.trigger(g)};f.drop=function(c){c=c||{};b.multi=c.multi===true?Infinity:c.multi===false?1:!isNaN(c.multi)?c.multi:b.multi;b.delay=c.delay||b.delay;b.tolerance=f.isFunction(c.tolerance)?c.tolerance:c.tolerance===null?null:b.tolerance;b.mode=c.mode||b.mode||"intersect"};var l=f.event,i=l.special,b=f.event.special.drop= {multi:1,delay:20,mode:"overlap",targets:[],datakey:"dropdata",livekey:"livedrop",add:function(c){var a=f.data(this,b.datakey);a.related+=1;if(!a.live&&c.selector){a.live=true;l.add(this,"dropinit."+b.livekey,b.delegate)}},remove:function(){f.data(this,b.datakey).related-=1},setup:function(){if(!f.data(this,b.datakey)){f.data(this,b.datakey,{related:0,active:[],anyactive:0,winner:0,location:{}});b.targets.push(this)}},teardown:function(){if(!f.data(this,b.datakey).related){f.removeData(this,b.datakey); l.remove(this,"dropinit",b.delegate);var c=this;b.targets=f.grep(b.targets,function(a){return a!==c})}},handler:function(c,a){var d;if(a)switch(c.type){case "mousedown":d=f(b.targets);if(typeof a.drop=="string")d=d.filter(a.drop);d.each(function(){var g=f.data(this,b.datakey);g.active=[];g.anyactive=0;g.winner=0});a.droppable=d;b.delegates=[];i.drag.hijack(c,"dropinit",a);b.delegates=f.unique(i.drag.flatten(b.delegates));break;case "mousemove":b.event=c;b.timer||b.tolerate(a);break;case "mouseup":b.timer= clearTimeout(b.timer);if(a.propagates){i.drag.hijack(c,"drop",a);i.drag.hijack(c,"dropend",a);f.each(b.delegates||[],function(){l.remove(this,"."+b.livekey)})}break}},delegate:function(c){var a=[],d,g=f.data(this,"events")||{};f.each(g.live||[],function(e,h){if(h.preType.indexOf("drop")===0){d=f(c.currentTarget).find(h.selector);d.length&&d.each(function(){l.add(this,h.origType+"."+b.livekey,h.origHandler,h.data);f.inArray(this,a)<0&&a.push(this)})}});b.delegates.push(a);return a.length?f(a):false}, locate:function(c,a){var d=f.data(c,b.datakey),g=f(c),e=g.offset()||{},h=g.outerHeight();g=g.outerWidth();e={elem:c,width:g,height:h,top:e.top,left:e.left,right:e.left+g,bottom:e.top+h};if(d){d.location=e;d.index=a;d.elem=c}return e},contains:function(c,a){return(a[0]||a.left)>=c.left&&(a[0]||a.right)<=c.right&&(a[1]||a.top)>=c.top&&(a[1]||a.bottom)<=c.bottom},modes:{intersect:function(c,a,d){return this.contains(d,[c.pageX,c.pageY])?1E9:this.modes.overlap.apply(this,arguments)},overlap:function(c, a,d){return Math.max(0,Math.min(d.bottom,a.bottom)-Math.max(d.top,a.top))*Math.max(0,Math.min(d.right,a.right)-Math.max(d.left,a.left))},fit:function(c,a,d){return this.contains(d,a)?1:0},middle:function(c,a,d){return this.contains(d,[a.left+a.width*0.5,a.top+a.height*0.5])?1:0}},sort:function(c,a){return a.winner-c.winner||c.index-a.index},tolerate:function(c){var a,d,g,e,h,m,j=0,k,p=c.interactions.length,n=[b.event.pageX,b.event.pageY],o=b.tolerance||b.modes[b.mode];do if(k=c.interactions[j]){if(!k)return; k.drop=[];h=[];m=k.droppable.length;if(o)g=b.locate(k.proxy);a=0;do if(d=k.droppable[a]){e=f.data(d,b.datakey);if(d=e.location){e.winner=o?o.call(b,b.event,g,d):b.contains(d,n)?1:0;h.push(e)}}while(++a>
+ case 'touchstart': // DROPINIT >>
+ // collect and assign the drop targets
+ $targets = $( drop.targets );
+ if ( typeof dd.drop == "string" )
+ $targets = $targets.filter( dd.drop );
+ // reset drop data winner properties
+ $targets.each(function(){
+ var data = $.data( this, drop.datakey );
+ data.active = [];
+ data.anyactive = 0;
+ data.winner = 0;
+ });
+ // set available target elements
+ dd.droppable = $targets;
+ // activate drop targets for the initial element being dragged
+ $special.drag.hijack( event, "dropinit", dd );
+ break;
+ // drag, from $.event.special.drag
+ case 'mousemove': // TOLERATE >>
+ case 'touchmove': // TOLERATE >>
+ drop.event = event; // store the mousemove event
+ if ( !drop.timer )
+ // monitor drop targets
+ drop.tolerate( dd );
+ break;
+ // dragend, from $.event.special.drag
+ case 'mouseup': // DROP >> DROPEND >>
+ case 'touchend': // DROP >> DROPEND >>
+ drop.timer = clearTimeout( drop.timer ); // delete timer
+ if ( dd.propagates ){
+ $special.drag.hijack( event, "drop", dd );
+ $special.drag.hijack( event, "dropend", dd );
+ }
+ break;
+
+ }
+ },
+
+ // returns the location positions of an element
+ locate: function( elem, index ){
+ var data = $.data( elem, drop.datakey ),
+ $elem = $( elem ),
+ posi = $elem.offset() || {},
+ height = $elem.outerHeight(),
+ width = $elem.outerWidth(),
+ location = {
+ elem: elem,
+ width: width,
+ height: height,
+ top: posi.top,
+ left: posi.left,
+ right: posi.left + width,
+ bottom: posi.top + height
+ };
+ // drag elements might not have dropdata
+ if ( data ){
+ data.location = location;
+ data.index = index;
+ data.elem = elem;
+ }
+ return location;
+ },
+
+ // test the location positions of an element against another OR an X,Y coord
+ contains: function( target, test ){ // target { location } contains test [x,y] or { location }
+ return ( ( test[0] || test.left ) >= target.left && ( test[0] || test.right ) <= target.right
+ && ( test[1] || test.top ) >= target.top && ( test[1] || test.bottom ) <= target.bottom );
+ },
+
+ // stored tolerance modes
+ modes: { // fn scope: "$.event.special.drop" object
+ // target with mouse wins, else target with most overlap wins
+ 'intersect': function( event, proxy, target ){
+ return this.contains( target, [ event.pageX, event.pageY ] ) ? // check cursor
+ 1e9 : this.modes.overlap.apply( this, arguments ); // check overlap
+ },
+ // target with most overlap wins
+ 'overlap': function( event, proxy, target ){
+ // calculate the area of overlap...
+ return Math.max( 0, Math.min( target.bottom, proxy.bottom ) - Math.max( target.top, proxy.top ) )
+ * Math.max( 0, Math.min( target.right, proxy.right ) - Math.max( target.left, proxy.left ) );
+ },
+ // proxy is completely contained within target bounds
+ 'fit': function( event, proxy, target ){
+ return this.contains( target, proxy ) ? 1 : 0;
+ },
+ // center of the proxy is contained within target bounds
+ 'middle': function( event, proxy, target ){
+ return this.contains( target, [ proxy.left + proxy.width * .5, proxy.top + proxy.height * .5 ] ) ? 1 : 0;
+ }
+ },
+
+ // sort drop target cache by by winner (dsc), then index (asc)
+ sort: function( a, b ){
+ return ( b.winner - a.winner ) || ( a.index - b.index );
+ },
+
+ // async, recursive tolerance execution
+ tolerate: function( dd ){
+ // declare local refs
+ var i, drp, drg, data, arr, len, elem,
+ // interaction iteration variables
+ x = 0, ia, end = dd.interactions.length,
+ // determine the mouse coords
+ xy = [ drop.event.pageX, drop.event.pageY ],
+ // custom or stored tolerance fn
+ tolerance = drop.tolerance || drop.modes[ drop.mode ];
+ // go through each passed interaction...
+ do if ( ia = dd.interactions[x] ){
+ // check valid interaction
+ if ( !ia )
+ return;
+ // initialize or clear the drop data
+ ia.drop = [];
+ // holds the drop elements
+ arr = [];
+ len = ia.droppable.length;
+ // determine the proxy location, if needed
+ if ( tolerance )
+ drg = drop.locate( ia.proxy );
+ // reset the loop
+ i = 0;
+ // loop each stored drop target
+ do if ( elem = ia.droppable[i] ){
+ data = $.data( elem, drop.datakey );
+ drp = data.location;
+ if ( !drp ) continue;
+ // find a winner: tolerance function is defined, call it
+ data.winner = tolerance ? tolerance.call( drop, drop.event, drg, drp )
+ // mouse position is always the fallback
+ : drop.contains( drp, xy ) ? 1 : 0;
+ arr.push( data );
+ } while ( ++i < len ); // loop
+ // sort the drop targets
+ arr.sort( drop.sort );
+ // reset the loop
+ i = 0;
+ // loop through all of the targets again
+ do if ( data = arr[ i ] ){
+ // winners...
+ if ( data.winner && ia.drop.length < drop.multi ){
+ // new winner... dropstart
+ if ( !data.active[x] && !data.anyactive ){
+ // check to make sure that this is not prevented
+ if ( $special.drag.hijack( drop.event, "dropstart", dd, x, data.elem )[0] !== false ){
+ data.active[x] = 1;
+ data.anyactive += 1;
+ }
+ // if false, it is not a winner
+ else
+ data.winner = 0;
+ }
+ // if it is still a winner
+ if ( data.winner )
+ ia.drop.push( data.elem );
+ }
+ // losers...
+ else if ( data.active[x] && data.anyactive == 1 ){
+ // former winner... dropend
+ $special.drag.hijack( drop.event, "dropend", dd, x, data.elem );
+ data.active[x] = 0;
+ data.anyactive -= 1;
+ }
+ } while ( ++i < len ); // loop
+ } while ( ++x < end ) // loop
+ // check if the mouse is still moving or is idle
+ if ( drop.last && xy[0] == drop.last.pageX && xy[1] == drop.last.pageY )
+ delete drop.timer; // idle, don't recurse
+ else // recurse
+ drop.timer = setTimeout(function(){
+ drop.tolerate( dd );
+ }, drop.delay );
+ // remember event, to compare idleness
+ drop.last = drop.event;
+ }
+
+};
+
+// share the same special event configuration with related events...
+$special.dropinit = $special.dropstart = $special.dropend = drop;
+
+})(jQuery); // confine scope
\ No newline at end of file
diff --git a/lib/jquery.jsonp-1.1.0.min.js b/lib/jquery.jsonp-1.1.0.min.js
deleted file mode 100644
index 7c47fbd76..000000000
--- a/lib/jquery.jsonp-1.1.0.min.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// jquery.jsonp 1.1.0 (c)2009 Julian Aubourg | MIT License
-// http://code.google.com/p/jquery-jsonp/
-(function(d){var b=function(n){return n!==undefined&&n!==null},m=function(p,n,o){b(p)&&p.apply(n,o)},e=function(n){setTimeout(n,0)},f="",a="&",k="?",l="success",g="error",i=d("head"),h={},c={callback:"C",url:location.href},j=function(s){s=d.extend({},c,s);var r=s.beforeSend,A=0;s.abort=function(){A=1};if(b(r)&&(r(s,s)===false||A)){return s}var q=s.success,o=s.complete,v=s.error,C=s.dataFilter,G=s.callbackParameter,w=s.callback,D=s.cache,n=s.pageCache,t=s.url,I=s.data,x=s.timeout,z,H,F,E;t=b(t)?t:f;I=b(I)?((typeof I)=="string"?I:d.param(I)):f;b(G)&&(I+=(I==f?f:a)+escape(G)+"=?");!D&&!n&&(I+=(I==f?f:a)+"_"+(new Date()).getTime()+"=");z=t.split(k);if(I!=f){H=I.split(k);E=z.length-1;E&&(z[E]+=a+H.shift());z=z.concat(H)}F=z.length-2;F&&(z[F]+=w+z.pop());var p=z.join(k),B=function(J){b(C)&&(J=C.apply(s,[J]));m(q,s,[J,l]);m(o,s,[s,l])},y=function(J){m(v,s,[s,J]);m(o,s,[s,J])},u=h[p];if(n&&b(u)){e(function(){b(u.s)?B(u.s):y(g)});return s}e(function(){if(A){return}var J=d("").appendTo(i),L=J[0],N=L.contentWindow||L.contentDocument,P=N.document,K,Q,R=function(S,T){n&&!b(T)&&(h[p]=f);K();y(b(T)?T:g)},M=function(T){N[T]=undefined;try{delete N[T]}catch(S){}},O=w=="E"?"X":"E";if(!b(P)){P=N;N=P.getParentNode()}P.open();N[w]=function(S){A=1;n&&(h[p]={s:S});e(function(){K();B(S)})};N[O]=function(S){(!S||S=="complete")&&!A++&&e(R)};s.abort=K=function(){clearTimeout(Q);P.open();M(O);M(w);P.write(f);P.close();J.remove()};P.write(['
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/grid/grid.js b/tests/grid/grid.js
index 5106a2093..844113750 100755
--- a/tests/grid/grid.js
+++ b/tests/grid/grid.js
@@ -1,76 +1,68 @@
-(function($) {
-
-var grid;
-var el, offsetBefore, offsetAfter, dragged;
-
-var drag = function(handle, dx, dy) {
+(function ($) {
+
+ var grid;
+ var el, offsetBefore, offsetAfter, dragged;
+
+ var drag = function(handle, dx, dy) {
offsetBefore = el.offset();
$(handle).simulate("drag", {
- dx: dx || 0,
- dy: dy || 0
+ dx: dx || 0,
+ dy: dy || 0
});
dragged = { dx: dx, dy: dy };
offsetAfter = el.offset();
-}
-
-var moved = function (dx, dy, msg) {
+ }
+
+ var moved = function (dx, dy, msg) {
msg = msg ? msg + "." : "";
var actual = { left: offsetAfter.left, top: offsetAfter.top };
var expected = { left: offsetBefore.left + dx, top: offsetBefore.top + dy };
same(actual, expected, 'dragged[' + dragged.dx + ', ' + dragged.dy + '] ' + msg);
-}
-
-
-var ROWS = 500, COLS = 10;
-var data = [], row;
-for (var i=0; i
+
-
-
-
-
-
+ SlickGrid - Grid tests
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/index.html b/tests/index.html
index 764994888..a0a9f89e6 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -1,37 +1,40 @@
-
+
-
-
+ SlickGrid tests
+
-
-
-
-
-Slick.Data
-
-
-Slick
-
-
-
+
+
+
+
+ Slick.Data
+
+
+ Slick
+
+
+ Plugins
+
+
\ No newline at end of file
diff --git a/tests/init benchmark.html b/tests/init benchmark.html
new file mode 100644
index 000000000..8b41c8446
--- /dev/null
+++ b/tests/init benchmark.html
@@ -0,0 +1,57 @@
+
+
+
+
+ SlickGrid Initialization Benchmark
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Run w/o disposing
+ Run w/ disposing
+
+
+
+
+
+
+
+
diff --git a/tests/model benchmarks.html b/tests/model benchmarks.html
index 25dc25357..155f79a9a 100644
--- a/tests/model benchmarks.html
+++ b/tests/model benchmarks.html
@@ -43,18 +43,31 @@
dv.setFilterArgs(0);
//dv.setPagingOptions({pageSize:25});
- dv.groupBy(
- "percentComplete",
- function (g) {
- return "Group: " + g.value;
+ dv.setGrouping([
+ {
+ getter: "duration",
+ formatter: function (g) {
+ return "Duration: " + g.value + " (" + g.count + " items) ";
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg("percentComplete"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ aggregateCollapsed: true,
+ aggregateChildGroups: true
},
- function (a, b) {
- return a.value - b.value;
+ {
+ getter: "effortDriven",
+ formatter: function (g) {
+ return "Effort-Driven: " + (g.value ? "True" : "False") + " (" + g.count + " items) ";
+ },
+ aggregators: [
+ new Slick.Data.Aggregators.Avg("percentComplete"),
+ new Slick.Data.Aggregators.Sum("cost")
+ ],
+ aggregateCollapsed: false
}
- );
- dv.setAggregators([
- new Slick.Data.Aggregators.Avg("percentComplete")
- ], false);
+ ]);
dv.endUpdate();
diff --git a/tests/plugins/autotooltips.html b/tests/plugins/autotooltips.html
new file mode 100644
index 000000000..27ad7849a
--- /dev/null
+++ b/tests/plugins/autotooltips.html
@@ -0,0 +1,34 @@
+
+
+
+ SlickGrid - AutoTooltips plugin tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/plugins/autotooltips.js b/tests/plugins/autotooltips.js
new file mode 100644
index 000000000..1508fad22
--- /dev/null
+++ b/tests/plugins/autotooltips.js
@@ -0,0 +1,133 @@
+(function($) {
+
+ var grid, // The SlickGrid instance
+ cols = [ // The column definitions
+ { name: "Short", field: "short", width: 100 },
+ { name: "Medium", field: "medium", width: 100 },
+ { name: "Long", field: "long", width: 100 },
+ { name: "Mixed", field: "mixed", width: 100 },
+ { name: "Long header creates tooltip", field: "header", width: 50 },
+ { name: "Long header with predefined tooltip", field: "tooltipHeader", width: 50, tooltip: "Already have a tooltip!" }
+ ],
+ data = [], // The grid data
+ LONG_VALUE = "looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong",
+ MEDIUM_VALUE = "mediummmmmmm"
+ SHORT_VALUE = "short",
+ TOOLTIP = "tooltip",
+ TRUNCATED_VALUE = LONG_VALUE.substr(0, 17) + "...",
+ $container = $("#container");
+
+ // Create data
+ for (var i = 0; i < 10; i++) {
+ data.push({
+ "id": "row" + i,
+ "short": SHORT_VALUE,
+ "medium": MEDIUM_VALUE,
+ "long": LONG_VALUE,
+ "mixed": ( i % 2 == 0 ? SHORT_VALUE : LONG_VALUE ),
+ "header": i,
+ "tooltipHeader": i
+ });
+ }
+
+ function setupGrid(pluginOptions) {
+ $('
').appendTo($container);
+ grid = new Slick.Grid("#grid", data, cols);
+ grid.registerPlugin(new Slick.AutoTooltips(pluginOptions));
+ grid.render();
+ }
+
+ function teardownGrid() {
+ $container.empty();
+ }
+
+ function getCell(columnIndex) {
+ return $("#grid .slick-cell.l" + columnIndex).eq(0);
+ }
+
+ function getHeaderCell(columnIndex) {
+ return $("#grid .slick-header-column").eq(columnIndex);
+ }
+
+ module("plugins - autotooltips - defaults", {
+ setup: function () {
+ setupGrid({});
+ },
+ teardown: teardownGrid
+ });
+
+ test("title is empty when cell text has enough room", function () {
+ var $cell = getCell(0); // Grab a cell
+ $cell.trigger("mouseenter"); // Trigger hover on a cell in grid
+
+ strictEqual($cell.attr("title"), "", "title is not present");
+ });
+
+ test("title is present when cell text is cut off", function () {
+ var $cell = getCell(2); // Grab a cell
+ $cell.trigger("mouseenter"); // Trigger hover on a cell in grid
+
+ strictEqual($cell.attr("title"), LONG_VALUE, "title equals cell text");
+ });
+
+ module("plugins - autotooltips - header", {
+ setup: function () {
+ setupGrid({ enableForHeaderCells: true });
+ },
+ teardown: teardownGrid
+ });
+
+ test("title is empty when header column has enough width", function () {
+ var $headerCell = getHeaderCell(0); // Grab the requested header cell
+ $headerCell.trigger("mouseenter"); // Trigger hover on a header cell
+
+ strictEqual($headerCell.attr("title"), "", "title is not present");
+ });
+
+ test("title is present when header column is cut off", function () {
+ var $headerCell = getHeaderCell(4); // Grab the requested header cell
+ $headerCell.trigger("mouseenter"); // Trigger hover on a header cell
+
+ strictEqual($headerCell.attr("title"), "Long header creates tooltip", "title equals column name");
+ });
+
+ test("title is not overridden when header column has pre-defined tooltip", function() {
+ var $headerCell = getHeaderCell(5); // Grab the requested header cell
+ $headerCell.trigger("mouseenter"); // Trigger hover on a header cell
+
+ strictEqual($headerCell.attr("title"), "Long header with predefined tooltip", "title is not overridden");
+ });
+
+ // ******************************** //
+ // Tests for maximum tooltip length //
+ // ******************************** //
+
+ module("plugins - autotooltips - max tooltip", {
+ setup: function () {
+ setupGrid({ maxToolTipLength: 20 });
+ },
+ teardown: teardownGrid
+ });
+
+ test("title is empty when cell text has enough room", function () {
+ var $cell = getCell(0); // Grab a cell
+ $cell.trigger("mouseenter"); // Trigger hover on a cell in grid
+
+ strictEqual($cell.attr("title"), "", "title is not present");
+ });
+
+ test("title is present and not truncated when cell text is cut off but not too long", function () {
+ var $cell = getCell(1); // Grab a cell
+ $cell.trigger("mouseenter"); // Trigger hover on a cell in grid
+
+ strictEqual($cell.attr("title"), MEDIUM_VALUE, "title equals truncated text");
+ });
+
+ test("title is present and truncated when cell text is cut off and too long", function () {
+ var $cell = getCell(2); // Grab a cell
+ $cell.trigger("mouseenter"); // Trigger hover on a cell in grid
+
+ strictEqual($cell.attr("title"), TRUNCATED_VALUE, "title equals truncated text");
+ });
+
+})(jQuery);
\ No newline at end of file
diff --git a/tests/scrolling benchmark raf.html b/tests/scrolling benchmark raf.html
new file mode 100644
index 000000000..01ca0c57c
--- /dev/null
+++ b/tests/scrolling benchmark raf.html
@@ -0,0 +1,154 @@
+
+
+
+
+ SlickGrid Scrolling Benchmark
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Debug info
+ Run (+= 100px)
+ Run (+= 300px)
+ Run (+= 550px; simulate paging)
+ Run (+= 1'000px)
+ Run (+= 5'000px)
+
+
+
+
+
+
+
diff --git a/tests/scrolling benchmarks.html b/tests/scrolling benchmarks.html
index 7e6fefe16..0a2a885f2 100644
--- a/tests/scrolling benchmarks.html
+++ b/tests/scrolling benchmarks.html
@@ -20,7 +20,7 @@
-
+