diff options
-rw-r--r-- | lib/jquery.simulate.js | 150 | ||||
-rw-r--r-- | slick.grid.js | 1 | ||||
-rw-r--r-- | slick.model.js | 12 | ||||
-rw-r--r-- | tests/dataview.js | 384 | ||||
-rw-r--r-- | tests/dataview/dataview.js | 886 | ||||
-rw-r--r-- | tests/dataview/index.html | 28 | ||||
-rw-r--r-- | tests/grid/grid.js | 67 | ||||
-rw-r--r-- | tests/grid/index.html | 41 | ||||
-rw-r--r-- | tests/index.html | 30 |
9 files changed, 1202 insertions, 397 deletions
diff --git a/lib/jquery.simulate.js b/lib/jquery.simulate.js new file mode 100644 index 0000000..be41246 --- /dev/null +++ b/lib/jquery.simulate.js @@ -0,0 +1,150 @@ +/* + * jquery.simulate - simulate browser mouse and keyboard events + * + * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + */ + +;(function($) { + +$.fn.extend({ + simulate: function(type, options) { + return this.each(function() { + var opt = $.extend({}, $.simulate.defaults, options || {}); + new $.simulate(this, type, opt); + }); + } +}); + +$.simulate = function(el, type, options) { + this.target = el; + this.options = options; + + if (/^drag$/.test(type)) { + this[type].apply(this, [this.target, options]); + } else { + this.simulateEvent(el, type, options); + } +} + +$.extend($.simulate.prototype, { + simulateEvent: function(el, type, options) { + var evt = this.createEvent(type, options); + this.dispatchEvent(el, type, evt, options); + return evt; + }, + createEvent: function(type, options) { + if (/^mouse(over|out|down|up|move)|(dbl)?click$/.test(type)) { + return this.mouseEvent(type, options); + } else if (/^key(up|down|press)$/.test(type)) { + return this.keyboardEvent(type, options); + } + }, + mouseEvent: function(type, options) { + var evt; + var e = $.extend({ + bubbles: true, cancelable: (type != "mousemove"), view: window, detail: 0, + screenX: 0, screenY: 0, clientX: 0, clientY: 0, + ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, + button: 0, relatedTarget: undefined + }, options); + + var relatedTarget = $(e.relatedTarget)[0]; + + if ($.isFunction(document.createEvent)) { + evt = document.createEvent("MouseEvents"); + evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail, + e.screenX, e.screenY, e.clientX, e.clientY, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + e.button, e.relatedTarget || document.body.parentNode); + } else if (document.createEventObject) { + evt = document.createEventObject(); + $.extend(evt, e); + evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button; + } + return evt; + }, + keyboardEvent: function(type, options) { + var evt; + + var e = $.extend({ bubbles: true, cancelable: true, view: window, + ctrlKey: false, altKey: false, shiftKey: false, metaKey: false, + keyCode: 0, charCode: 0 + }, options); + + if ($.isFunction(document.createEvent)) { + try { + evt = document.createEvent("KeyEvents"); + evt.initKeyEvent(type, e.bubbles, e.cancelable, e.view, + e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, + e.keyCode, e.charCode); + } catch(err) { + evt = document.createEvent("Events"); + evt.initEvent(type, e.bubbles, e.cancelable); + $.extend(evt, { view: e.view, + ctrlKey: e.ctrlKey, altKey: e.altKey, shiftKey: e.shiftKey, metaKey: e.metaKey, + keyCode: e.keyCode, charCode: e.charCode + }); + } + } else if (document.createEventObject) { + evt = document.createEventObject(); + $.extend(evt, e); + } + if ($.browser.msie || $.browser.opera) { + evt.keyCode = (e.charCode > 0) ? e.charCode : e.keyCode; + evt.charCode = undefined; + } + return evt; + }, + + dispatchEvent: function(el, type, evt) { + if (el.dispatchEvent) { + el.dispatchEvent(evt); + } else if (el.fireEvent) { + el.fireEvent('on' + type, evt); + } + return evt; + }, + + drag: function(el) { + var self = this, center = this.findCenter(this.target), + options = this.options, x = Math.floor(center.x), y = Math.floor(center.y), + dx = options.dx || 0, dy = options.dy || 0, target = this.target; + var coord = { clientX: x, clientY: y }; + this.simulateEvent(target, "mousedown", coord); + coord = { clientX: x + 1, clientY: y + 1 }; + this.simulateEvent(document, "mousemove", coord); + coord = { clientX: x + dx, clientY: y + dy }; + this.simulateEvent(document, "mousemove", coord); + this.simulateEvent(document, "mousemove", coord); + this.simulateEvent(target, "mouseup", coord); + }, + findCenter: function(el) { + var el = $(this.target), o = el.offset(); + return { + x: o.left + el.outerWidth() / 2, + y: o.top + el.outerHeight() / 2 + }; + } +}); + +$.extend($.simulate, { + defaults: { + speed: 'sync' + }, + VK_TAB: 9, + VK_ENTER: 13, + VK_ESC: 27, + VK_PGUP: 33, + VK_PGDN: 34, + VK_END: 35, + VK_HOME: 36, + VK_LEFT: 37, + VK_UP: 38, + VK_RIGHT: 39, + VK_DOWN: 40 +}); + +})(jQuery); diff --git a/slick.grid.js b/slick.grid.js index 281e0ed..2790830 100644 --- a/slick.grid.js +++ b/slick.grid.js @@ -270,7 +270,6 @@ if (!jQuery.fn.drag) { var currentEditor = null; var editController; - var rowsCache = {}; var renderedRows = 0; var numVisibleRows; diff --git a/slick.model.js b/slick.model.js index 1bbf8d1..4294677 100644 --- a/slick.model.js +++ b/slick.model.js @@ -29,7 +29,7 @@ function EventHelper() { var self = this; // private - var idProperty = "id"; // property holding a unique row id + var idProperty = "id"; // property holding a unique row id var items = []; // data by index var rows = []; // data by row var idxById = {}; // indexes by id @@ -112,10 +112,10 @@ function EventHelper() { Object.prototype.toString = (typeof field == "function")?field:function() { return this[field] }; // an extra reversal for descending sort keeps the sort stable // (assuming a stable native sort implementation, which isn't true in some cases) - if (!ascending) items.reverse(); + if (ascending === false) items.reverse(); items.sort(); Object.prototype.toString = oldToString; - if (!ascending) items.reverse(); + if (ascending === false) items.reverse(); refreshIdxById(); refresh(); } @@ -150,6 +150,8 @@ function EventHelper() { } function updateItem(id, item) { + if (idxById[id] === undefined || id !== item[idProperty]) + throw "Invalid or non-matching id"; items[idxById[id]] = item; if (!updated) updated = {}; updated[id] = true; @@ -169,6 +171,8 @@ function EventHelper() { } function deleteItem(id) { + if (idxById[id] === undefined) + throw "Invalid id"; items.splice(idxById[id], 1); refreshIdxById(); // TODO: optimize refresh(); @@ -231,7 +235,7 @@ function EventHelper() { 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); + if (diff.length > 0) onRowsChanged.notify(diff); } diff --git a/tests/dataview.js b/tests/dataview.js deleted file mode 100644 index 9b44166..0000000 --- a/tests/dataview.js +++ /dev/null @@ -1,384 +0,0 @@ - -module("basic"); - -function assertEmpty(dv) { - ok(dv.rows !== null, ".rows is not null"); - ok(dv.rows !== undefined, ".rows is not undefined"); - same(0, dv.rows.length, ".rows is initialized to an empty array"); - same(dv.getItems().length, 0, "getItems().length"); - same(undefined, dv.getIdxById("id"), "getIdxById should return undefined if not found"); - same(undefined, dv.getRowById("id"), "getRowById should return undefined if not found"); - same(undefined, dv.getItemById("id"), "getItemById should return undefined if not found"); - same(undefined, dv.getItemByIdx(0), "getItemByIdx should return undefined if not found"); -} - -function assertConsistency(dv,idProperty) { - idProperty = idProperty || "id"; - var items = dv.getItems(), - filteredOut = 0, - row, - id; - - for (var i=0; i<items.length; i++) { - id = items[i][idProperty]; - same(dv.getItemByIdx(i), items[i], "getItemByIdx"); - same(dv.getItemById(id), items[i], "getItemById"); - same(dv.getIdxById(id), i, "getIdxById"); - - row = dv.getRowById(id); - if (row === undefined) - filteredOut++; - else - same(dv.rows[row], items[i], "getRowById"); - } - - same(items.length-dv.rows.length, filteredOut, "filtered rows"); -} - -test("initial setup", function() { - var dv = new Slick.Data.DataView(); - assertEmpty(dv); -}); - -test("initial setup, refresh", function() { - var dv = new Slick.Data.DataView(); - dv.refresh(); - assertEmpty(dv); -}); - - -module("setItems"); - -test("empty", function() { - var dv = new Slick.Data.DataView(); - dv.setItems([]); - assertEmpty(dv); -}); - -test("basic", function() { - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0},{id:1}]); - same(2, dv.rows.length, "rows.length"); - same(dv.getItems().length, 2, "getItems().length"); - assertConsistency(dv); -}); - -test("alternative idProperty", function() { - var dv = new Slick.Data.DataView(); - dv.setItems([{uid:0},{uid:1}], "uid"); - assertConsistency(dv,"uid"); -}); - -test("requires an id on objects", function() { - var dv = new Slick.Data.DataView(); - try { - dv.setItems([1,2,3]); - ok(false, "exception expected") - } - catch (ex) {} -}); - -test("requires a unique id on objects", function() { - var dv = new Slick.Data.DataView(); - try { - dv.setItems([{id:0},{id:0}]); - ok(false, "exception expected") - } - catch (ex) {} -}); - -test("requires a unique id on objects (alternative idProperty)", function() { - var dv = new Slick.Data.DataView(); - try { - dv.setItems([{uid:0},{uid:0}], "uid"); - ok(false, "exception expected") - } - catch (ex) {} -}); - -test("events fired on setItems", function() { - var count = 0; - var dv = new Slick.Data.DataView(); - dv.onRowsChanged.subscribe(function() { - ok(true, "onRowsChanged called"); - count++; - }); - dv.onRowCountChanged.subscribe(function(args) { - ok(true, "onRowCountChanged called"); - same(args.previous, 0, "previous arg"); - same(args.current, 2, "current arg"); - count++; - }); - dv.onPagingInfoChanged.subscribe(function(args) { - ok(true, "onPagingInfoChanged called"); - same(args.pageSize, 0, "pageSize arg"); - same(args.pageNum, 0, "pageNum arg"); - same(args.totalRows, 2, "totalRows arg"); - count++; - }); - dv.setItems([{id:0},{id:1}]); - dv.refresh(); - same(3, count, "3 events should have been called"); -}); - -test("no events on setItems([])", function() { - var dv = new Slick.Data.DataView(); - dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); - dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); - dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); - dv.setItems([]); - dv.refresh(); -}); - -test("no events on setItems followed by refresh", function() { - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0},{id:1}]); - dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); - dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); - dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); - dv.refresh(); -}); - -test("no refresh while suspended", function() { - var dv = new Slick.Data.DataView(); - dv.beginUpdate(); - dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); - dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); - dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); - dv.setItems([{id:0},{id:1}]); - dv.setFilter(function(o) { return true }); - dv.refresh(); - same(dv.rows.length, 0, "rows aren't updated until resumed"); -}); - -test("refresh fires after resume", function() { - var dv = new Slick.Data.DataView(); - dv.beginUpdate(); - dv.setItems([{id:0},{id:1}]); - same(dv.getItems().length, 2, "items updated immediately"); - dv.setFilter(function(o) { return true }); - dv.refresh(); - - var count = 0; - dv.onRowsChanged.subscribe(function(args) { - ok(true, "onRowsChanged called"); - same(args, [0,1], "args"); - count++; - }); - dv.onRowCountChanged.subscribe(function(args) { - ok(true, "onRowCountChanged called"); - same(args.previous, 0, "previous arg"); - same(args.current, 2, "current arg"); - count++; - }); - dv.onPagingInfoChanged.subscribe(function(args) { - ok(true, "onPagingInfoChanged called"); - same(args.pageSize, 0, "pageSize arg"); - same(args.pageNum, 0, "pageNum arg"); - same(args.totalRows, 2, "totalRows arg"); - count++; - }); - dv.endUpdate(); - same(count, 3, "events fired"); - same(dv.getItems().length, 2, "items are the same"); - same(dv.rows.length, 2, "rows updated"); -}); - -module("sort"); - -test("happy path", function() { - var count = 0; - var items = [{id:2,val:2},{id:1,val:1},{id:0,val:0}]; - var dv = new Slick.Data.DataView(); - dv.setItems(items); - dv.onRowsChanged.subscribe(function() { - ok(true, "onRowsChanged called"); - count++; - }); - dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); - dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); - dv.sort(function(x,y) { return x.val-y.val }, true); - same(count, 1, "events fired"); - same(dv.getItems(), items, "original array should get sorted"); - same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2}], "sort order"); - assertConsistency(dv); -}); - -test("asc by default", function() { - var items = [{id:2,val:2},{id:1,val:1},{id:0,val:0}]; - var dv = new Slick.Data.DataView(); - dv.setItems(items); - dv.sort(function(x,y) { return x.val-y.val }); - same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2}], "sort order"); -}); - -test("desc", function() { - var items = [{id:0,val:0},{id:2,val:2},{id:1,val:1}]; - var dv = new Slick.Data.DataView(); - dv.setItems(items); - dv.sort(function(x,y) { return x.val-y.val }, false); - same(items, [{id:2,val:2},{id:1,val:1},{id:0,val:0}], "sort order"); -}); - -test("sort is stable", function() { - var items = [{id:0,val:0},{id:2,val:2},{id:3,val:2},{id:1,val:1}]; - var dv = new Slick.Data.DataView(); - dv.setItems(items); - - dv.sort(function(x,y) { return x.val-y.val }); - same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:2}], "sort order"); - - dv.sort(function(x,y) { return x.val-y.val }, false); - same(items, [{id:2,val:2},{id:3,val:2},{id:1,val:1},{id:0,val:0}], "sort order"); - -}); - - -module("filtering"); - -test("applied immediately", function() { - var count = 0; - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); - dv.onRowsChanged.subscribe(function(args) { - ok(true, "onRowsChanged called"); - same(args, [0], "args"); - count++; - }); - dv.onRowCountChanged.subscribe(function(args) { - ok(true, "onRowCountChanged called"); - same(args.previous, 3, "previous arg"); - same(args.current, 1, "current arg"); - count++; - }); - dv.onPagingInfoChanged.subscribe(function(args) { - ok(true, "onPagingInfoChanged called"); - same(args.pageSize, 0, "pageSize arg"); - same(args.pageNum, 0, "pageNum arg"); - same(args.totalRows, 1, "totalRows arg"); - count++; - }); - dv.setFilter(function(o) { return o.val === 1 }); - same(count, 3, "events fired"); - same(dv.getItems().length, 3, "original data is still there"); - same(dv.rows.length, 1, "rows are filtered"); - assertConsistency(dv); -}); - -test("re-applied on refresh", function() { - var count = 0; - var filterVal = 0; - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); - dv.setFilter(function(o) { return o.val >= filterVal }); - same(dv.rows.length, 3, "nothing is filtered out"); - assertConsistency(dv); - - dv.onRowsChanged.subscribe(function(args) { - ok(true, "onRowsChanged called"); - same(args, [0], "args"); - count++; - }); - dv.onRowCountChanged.subscribe(function(args) { - ok(true, "onRowCountChanged called"); - same(args.previous, 3, "previous arg"); - same(args.current, 1, "current arg"); - count++; - }); - dv.onPagingInfoChanged.subscribe(function(args) { - ok(true, "onPagingInfoChanged called"); - same(args.pageSize, 0, "pageSize arg"); - same(args.pageNum, 0, "pageNum arg"); - same(args.totalRows, 1, "totalRows arg"); - count++; - }); - filterVal = 2; - dv.refresh(); - same(count, 3, "events fired"); - same(dv.getItems().length, 3, "original data is still there"); - same(dv.rows.length, 1, "rows are filtered"); - assertConsistency(dv); -}); - -test("re-applied on sort", function() { - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); - dv.setFilter(function(o) { return o.val === 1 }); - same(dv.rows.length, 1, "one row is remaining"); - - dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); - dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); - dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); - dv.sort(function(x,y) { return x.val-y.val }, false); - same(dv.getItems().length, 3, "original data is still there"); - same(dv.rows.length, 1, "rows are filtered"); - assertConsistency(dv); -}); - -test("all", function() { - var count = 0; - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); - dv.onRowsChanged.subscribe(function(args) { - ok(true, "onRowsChanged called"); - same(args, [], "args"); - count++; - }); - dv.onRowCountChanged.subscribe(function(args) { - ok(true, "onRowCountChanged called"); - same(args.previous, 3, "previous arg"); - same(args.current, 0, "current arg"); - count++; - }); - dv.onPagingInfoChanged.subscribe(function(args) { - ok(true, "onPagingInfoChanged called"); - same(args.pageSize, 0, "pageSize arg"); - same(args.pageNum, 0, "pageNum arg"); - same(args.totalRows, 0, "totalRows arg"); - count++; - }); - dv.setFilter(function(o) { return false }); - same(count, 3, "events fired"); - same(dv.getItems().length, 3, "original data is still there"); - same(dv.rows.length, 0, "rows are filtered"); - assertConsistency(dv); -}); - -test("all then none", function() { - var filterResult = false; - var count = 0; - var dv = new Slick.Data.DataView(); - dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); - dv.setFilter(function(o) { return filterResult }); - same(dv.rows.length, 0, "all rows are filtered out"); - - dv.onRowsChanged.subscribe(function(args) { - ok(true, "onRowsChanged called"); - same(args, [0,1,2], "args"); - count++; - }); - dv.onRowCountChanged.subscribe(function(args) { - ok(true, "onRowCountChanged called"); - same(args.previous, 0, "previous arg"); - same(args.current, 3, "current arg"); - count++; - }); - dv.onPagingInfoChanged.subscribe(function(args) { - ok(true, "onPagingInfoChanged called"); - same(args.pageSize, 0, "pageSize arg"); - same(args.pageNum, 0, "pageNum arg"); - same(args.totalRows, 3, "totalRows arg"); - count++; - }); - filterResult = true; - dv.refresh(); - same(count, 3, "events fired"); - same(dv.getItems().length, 3, "original data is still there"); - same(dv.rows.length, 3, "all rows are back"); - assertConsistency(dv); -}); - -// TODO: paging -// TODO: fast sort -// TODO: events on refresh on boundary conditions -// TODO: add/insert/update/delete
\ No newline at end of file diff --git a/tests/dataview/dataview.js b/tests/dataview/dataview.js new file mode 100644 index 0000000..a5b56ac --- /dev/null +++ b/tests/dataview/dataview.js @@ -0,0 +1,886 @@ + +module("basic"); + +function assertEmpty(dv) { + ok(dv.rows !== null, ".rows is not null"); + ok(dv.rows !== undefined, ".rows is not undefined"); + same(0, dv.rows.length, ".rows is initialized to an empty array"); + same(dv.getItems().length, 0, "getItems().length"); + same(undefined, dv.getIdxById("id"), "getIdxById should return undefined if not found"); + same(undefined, dv.getRowById("id"), "getRowById should return undefined if not found"); + same(undefined, dv.getItemById("id"), "getItemById should return undefined if not found"); + same(undefined, dv.getItemByIdx(0), "getItemByIdx should return undefined if not found"); +} + +function assertConsistency(dv,idProperty) { + idProperty = idProperty || "id"; + var items = dv.getItems(), + filteredOut = 0, + row, + id; + + for (var i=0; i<items.length; i++) { + id = items[i][idProperty]; + same(dv.getItemByIdx(i), items[i], "getItemByIdx"); + same(dv.getItemById(id), items[i], "getItemById"); + same(dv.getIdxById(id), i, "getIdxById"); + + row = dv.getRowById(id); + if (row === undefined) + filteredOut++; + else + same(dv.rows[row], items[i], "getRowById"); + } + + same(items.length-dv.rows.length, filteredOut, "filtered rows"); +} + +test("initial setup", function() { + var dv = new Slick.Data.DataView(); + assertEmpty(dv); +}); + +test("initial setup, refresh", function() { + var dv = new Slick.Data.DataView(); + dv.refresh(); + assertEmpty(dv); +}); + + +module("setItems"); + +test("empty", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([]); + assertEmpty(dv); +}); + +test("basic", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0},{id:1}]); + same(2, dv.rows.length, "rows.length"); + same(dv.getItems().length, 2, "getItems().length"); + assertConsistency(dv); +}); + +test("alternative idProperty", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([{uid:0},{uid:1}], "uid"); + assertConsistency(dv,"uid"); +}); + +test("requires an id on objects", function() { + var dv = new Slick.Data.DataView(); + try { + dv.setItems([1,2,3]); + ok(false, "exception expected") + } + catch (ex) {} +}); + +test("requires a unique id on objects", function() { + var dv = new Slick.Data.DataView(); + try { + dv.setItems([{id:0},{id:0}]); + ok(false, "exception expected") + } + catch (ex) {} +}); + +test("requires a unique id on objects (alternative idProperty)", function() { + var dv = new Slick.Data.DataView(); + try { + dv.setItems([{uid:0},{uid:0}], "uid"); + ok(false, "exception expected") + } + catch (ex) {} +}); + +test("events fired on setItems", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.onRowsChanged.subscribe(function() { + ok(true, "onRowsChanged called"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + same(args.previous, 0, "previous arg"); + same(args.current, 2, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 2, "totalRows arg"); + count++; + }); + dv.setItems([{id:0},{id:1}]); + dv.refresh(); + same(3, count, "3 events should have been called"); +}); + +test("no events on setItems([])", function() { + var dv = new Slick.Data.DataView(); + dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + dv.setItems([]); + dv.refresh(); +}); + +test("no events on setItems followed by refresh", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0},{id:1}]); + dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + dv.refresh(); +}); + +test("no refresh while suspended", function() { + var dv = new Slick.Data.DataView(); + dv.beginUpdate(); + dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + dv.setItems([{id:0},{id:1}]); + dv.setFilter(function(o) { return true }); + dv.refresh(); + same(dv.rows.length, 0, "rows aren't updated until resumed"); +}); + +test("refresh fires after resume", function() { + var dv = new Slick.Data.DataView(); + dv.beginUpdate(); + dv.setItems([{id:0},{id:1}]); + same(dv.getItems().length, 2, "items updated immediately"); + dv.setFilter(function(o) { return true }); + dv.refresh(); + + var count = 0; + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [0,1], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + same(args.previous, 0, "previous arg"); + same(args.current, 2, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 2, "totalRows arg"); + count++; + }); + dv.endUpdate(); + equal(count, 3, "events fired"); + same(dv.getItems().length, 2, "items are the same"); + same(dv.rows.length, 2, "rows updated"); +}); + +module("sort"); + +test("happy path", function() { + var count = 0; + var items = [{id:2,val:2},{id:1,val:1},{id:0,val:0}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.onRowsChanged.subscribe(function() { + ok(true, "onRowsChanged called"); + count++; + }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + dv.sort(function(x,y) { return x.val-y.val }, true); + equal(count, 1, "events fired"); + same(dv.getItems(), items, "original array should get sorted"); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2}], "sort order"); + assertConsistency(dv); +}); + +test("asc by default", function() { + var items = [{id:2,val:2},{id:1,val:1},{id:0,val:0}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.sort(function(x,y) { return x.val-y.val }); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2}], "sort order"); +}); + +test("desc", function() { + var items = [{id:0,val:0},{id:2,val:2},{id:1,val:1}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.sort(function(x,y) { return x.val-y.val }, false); + same(items, [{id:2,val:2},{id:1,val:1},{id:0,val:0}], "sort order"); +}); + +test("sort is stable", function() { + var items = [{id:0,val:0},{id:2,val:2},{id:3,val:2},{id:1,val:1}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + + dv.sort(function(x,y) { return x.val-y.val }); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:2}], "sort order"); + + dv.sort(function(x,y) { return x.val-y.val }); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:2}], "sorting on the same column again doesn't change the order"); + + dv.sort(function(x,y) { return x.val-y.val }, false); + same(items, [{id:2,val:2},{id:3,val:2},{id:1,val:1},{id:0,val:0}], "sort order"); +}); + + + +module("fastSort"); + +test("happy path", function() { + var count = 0; + var items = [{id:2,val:2},{id:1,val:1},{id:0,val:0}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.onRowsChanged.subscribe(function() { + ok(true, "onRowsChanged called"); + count++; + }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + dv.fastSort("val", true); + equal(count, 1, "events fired"); + same(dv.getItems(), items, "original array should get sorted"); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2}], "sort order"); + assertConsistency(dv); +}); + +test("asc by default", function() { + var items = [{id:2,val:2},{id:1,val:1},{id:0,val:0}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.fastSort("val"); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2}], "sort order"); +}); + +test("desc", function() { + var items = [{id:0,val:0},{id:2,val:2},{id:1,val:1}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.fastSort("val", false); + same(items, [{id:2,val:2},{id:1,val:1},{id:0,val:0}], "sort order"); +}); + +test("sort is stable", function() { + var items = [{id:0,val:0},{id:2,val:2},{id:3,val:2},{id:1,val:1}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + + dv.fastSort("val"); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:2}], "sort order"); + + dv.fastSort("val"); + same(items, [{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:2}], "sorting on the same column again doesn't change the order"); + + dv.fastSort("val", false); + same(items, [{id:2,val:2},{id:3,val:2},{id:1,val:1},{id:0,val:0}], "sort order"); +}); + +test("w/ function param", function() { + var count = 0; + var items = [{id:2,val:2},{id:1,val:10},{id:0,val:0}]; + var dv = new Slick.Data.DataView(); + dv.setItems(items); + dv.onRowsChanged.subscribe(function() { + ok(true, "onRowsChanged called"); + count++; + }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + var numericValueFn = function() { + var val = this["val"]; + if (val < 10) + return "00" + val; + else if (val < 100) + return "0" + val; + else + return val; + }; + dv.fastSort(numericValueFn, true); + equal(count, 1, "events fired"); + same(dv.getItems(), items, "original array should get sorted"); + same(items, [{id:0,val:0},{id:2,val:2},{id:1,val:10}], "sort order"); + assertConsistency(dv); +}); + +module("filtering"); + +test("applied immediately", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [0], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + same(args.previous, 3, "previous arg"); + same(args.current, 1, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 1, "totalRows arg"); + count++; + }); + dv.setFilter(function(o) { return o.val === 1 }); + equal(count, 3, "events fired"); + same(dv.getItems().length, 3, "original data is still there"); + same(dv.rows.length, 1, "rows are filtered"); + assertConsistency(dv); +}); + +test("re-applied on refresh", function() { + var count = 0; + var filterVal = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.setFilter(function(o) { return o.val >= filterVal }); + same(dv.rows.length, 3, "nothing is filtered out"); + assertConsistency(dv); + + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [0], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + same(args.previous, 3, "previous arg"); + same(args.current, 1, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 1, "totalRows arg"); + count++; + }); + filterVal = 2; + dv.refresh(); + equal(count, 3, "events fired"); + same(dv.getItems().length, 3, "original data is still there"); + same(dv.rows.length, 1, "rows are filtered"); + assertConsistency(dv); +}); + +test("re-applied on sort", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.setFilter(function(o) { return o.val === 1 }); + same(dv.rows.length, 1, "one row is remaining"); + + dv.onRowsChanged.subscribe(function() { ok(false, "onRowsChanged called") }); + dv.onRowCountChanged.subscribe(function() { ok(false, "onRowCountChanged called") }); + dv.onPagingInfoChanged.subscribe(function() { ok(false, "onPagingInfoChanged called") }); + dv.sort(function(x,y) { return x.val-y.val }, false); + same(dv.getItems().length, 3, "original data is still there"); + same(dv.rows.length, 1, "rows are filtered"); + assertConsistency(dv); +}); + +test("all", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(false, "onRowsChanged called"); + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + same(args.previous, 3, "previous arg"); + same(args.current, 0, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 0, "totalRows arg"); + count++; + }); + dv.setFilter(function(o) { return false }); + equal(count, 2, "events fired"); + same(dv.getItems().length, 3, "original data is still there"); + same(dv.rows.length, 0, "rows are filtered"); + assertConsistency(dv); +}); + +test("all then none", function() { + var filterResult = false; + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.setFilter(function(o) { return filterResult }); + same(dv.rows.length, 0, "all rows are filtered out"); + + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [0,1,2], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + same(args.previous, 0, "previous arg"); + same(args.current, 3, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 3, "totalRows arg"); + count++; + }); + filterResult = true; + dv.refresh(); + equal(count, 3, "events fired"); + same(dv.getItems().length, 3, "original data is still there"); + same(dv.rows.length, 3, "all rows are back"); + assertConsistency(dv); +}); + +module("updateItem"); + +test("basic", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [1], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(false, "onRowCountChanged called"); + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(false, "onPagingInfoChanged called"); + }); + + dv.updateItem(1,{id:1,val:1337}); + equal(count, 1, "events fired"); + same(dv.rows[1], {id:1,val:1337}, "item updated"); + assertConsistency(dv); +}); + +test("updating an item not passing the filter", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:1337}]); + dv.setFilter(function(o) { return o["val"] !== 1337 }); + dv.onRowsChanged.subscribe(function(args) { + ok(false, "onRowsChanged called"); + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(false, "onRowCountChanged called"); + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(false, "onPagingInfoChanged called"); + }); + dv.updateItem(3,{id:3,val:1337}); + same(dv.getItems()[3], {id:3,val:1337}, "item updated"); + assertConsistency(dv); +}); + +test("updating an item to pass the filter", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:1337}]); + dv.setFilter(function(o) { return o["val"] !== 1337 }); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [3], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 4, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 4, "totalRows arg"); + count++; + }); + dv.updateItem(3,{id:3,val:3}); + equal(count, 3, "events fired"); + same(dv.getItems()[3], {id:3,val:3}, "item updated"); + assertConsistency(dv); +}); + +test("updating an item to not pass the filter", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2},{id:3,val:3}]); + dv.setFilter(function(o) { return o["val"] !== 1337 }); + dv.onRowsChanged.subscribe(function(args) { + console.log(args) + ok(false, "onRowsChanged called"); + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 4, "previous arg"); + equal(args.current, 3, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + same(args.pageSize, 0, "pageSize arg"); + same(args.pageNum, 0, "pageNum arg"); + same(args.totalRows, 3, "totalRows arg"); + count++; + }); + dv.updateItem(3,{id:3,val:1337}); + equal(count, 2, "events fired"); + same(dv.getItems()[3], {id:3,val:1337}, "item updated"); + assertConsistency(dv); +}); + + +module("addItem"); + +test("must have id", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + try { + dv.addItem({val:1337}); + ok(false, "exception thrown"); + } + catch (ex) {} +}); + +test("must have id (custom)", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{uid:0,val:0},{uid:1,val:1},{uid:2,val:2}], "uid"); + try { + dv.addItem({id:3,val:1337}); + ok(false, "exception thrown"); + } + catch (ex) {} +}); + +test("basic", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [3], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 4, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 4, "totalRows arg"); + count++; + }); + dv.addItem({id:3,val:1337}); + equal(count, 3, "events fired"); + same(dv.getItems()[3], {id:3,val:1337}, "item updated"); + same(dv.rows[3], {id:3,val:1337}, "item updated"); + assertConsistency(dv); +}); + +test("add an item not passing the filter", function() { + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.setFilter(function(o) { return o["val"] !== 1337 }); + dv.onRowsChanged.subscribe(function(args) { + ok(false, "onRowsChanged called"); + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(false, "onRowCountChanged called"); + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(false, "onPagingInfoChanged called"); + }); + dv.addItem({id:3,val:1337}); + same(dv.getItems()[3], {id:3,val:1337}, "item updated"); + assertConsistency(dv); +}); + +module("insertItem"); + +test("must have id", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + try { + dv.insertItem(0,{val:1337}); + ok(false, "exception thrown"); + } + catch (ex) {} +}); + +test("must have id (custom)", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{uid:0,val:0},{uid:1,val:1},{uid:2,val:2}], "uid"); + try { + dv.insertItem(0,{id:3,val:1337}); + ok(false, "exception thrown"); + } + catch (ex) {} +}); + +test("insert at the beginning", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [0,1,2,3], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 4, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 4, "totalRows arg"); + count++; + }); + dv.insertItem(0, {id:3,val:1337}); + equal(count, 3, "events fired"); + same(dv.rows[0], {id:3,val:1337}, "item updated"); + equal(dv.getItems().length, 4, "items updated"); + equal(dv.rows.length, 4, "rows updated"); + assertConsistency(dv); +}); + +test("insert in the middle", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [2,3], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 4, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 4, "totalRows arg"); + count++; + }); + dv.insertItem(2,{id:3,val:1337}); + equal(count, 3, "events fired"); + same(dv.rows[2], {id:3,val:1337}, "item updated"); + equal(dv.getItems().length, 4, "items updated"); + equal(dv.rows.length, 4, "rows updated"); + assertConsistency(dv); +}); + +test("insert at the end", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [3], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 4, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 4, "totalRows arg"); + count++; + }); + dv.insertItem(3,{id:3,val:1337}); + equal(count, 3, "events fired"); + same(dv.rows[3], {id:3,val:1337}, "item updated"); + equal(dv.getItems().length, 4, "items updated"); + equal(dv.rows.length, 4, "rows updated"); + assertConsistency(dv); +}); + +module("deleteItem"); + +test("must have id", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:0,val:0},{id:1,val:1},{id:2,val:2}]); + try { + dv.deleteItem(-1); + ok(false, "exception thrown"); + } + catch (ex) {} + try { + dv.deleteItem(undefined); + ok(false, "exception thrown"); + } + catch (ex) {} + try { + dv.deleteItem(null); + ok(false, "exception thrown"); + } + catch (ex) {} + try { + dv.deleteItem(3); + ok(false, "exception thrown"); + } + catch (ex) {} +}); + +test("must have id (custom)", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{uid:0,id:-1,val:0},{uid:1,id:3,val:1},{uid:2,id:null,val:2}], "uid"); + try { + dv.deleteItem(-1); + ok(false, "exception thrown"); + } + catch (ex) {} + try { + dv.deleteItem(undefined); + ok(false, "exception thrown"); + } + catch (ex) {} + try { + dv.deleteItem(null); + ok(false, "exception thrown"); + } + catch (ex) {} + try { + dv.deleteItem(3); + ok(false, "exception thrown"); + } + catch (ex) {} +}); + +test("delete at the beginning", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:05,val:0},{id:15,val:1},{id:25,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [0,1], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 2, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 2, "totalRows arg"); + count++; + }); + dv.deleteItem(05); + equal(count, 3, "events fired"); + equal(dv.getItems().length, 2, "items updated"); + equal(dv.rows.length, 2, "rows updated"); + assertConsistency(dv); +}); + +test("delete in the middle", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:05,val:0},{id:15,val:1},{id:25,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(true, "onRowsChanged called"); + same(args, [1], "args"); + count++; + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 2, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 2, "totalRows arg"); + count++; + }); + dv.deleteItem(15); + equal(count, 3, "events fired"); + equal(dv.getItems().length, 2, "items updated"); + equal(dv.rows.length, 2, "rows updated"); + assertConsistency(dv); +}); + +test("delete at the end", function() { + var count = 0; + var dv = new Slick.Data.DataView(); + dv.setItems([{id:05,val:0},{id:15,val:1},{id:25,val:2}]); + dv.onRowsChanged.subscribe(function(args) { + ok(false, "onRowsChanged called"); + }); + dv.onRowCountChanged.subscribe(function(args) { + ok(true, "onRowCountChanged called"); + equal(args.previous, 3, "previous arg"); + equal(args.current, 2, "current arg"); + count++; + }); + dv.onPagingInfoChanged.subscribe(function(args) { + ok(true, "onPagingInfoChanged called"); + equal(args.pageSize, 0, "pageSize arg"); + equal(args.pageNum, 0, "pageNum arg"); + equal(args.totalRows, 2, "totalRows arg"); + count++; + }); + dv.deleteItem(25); + equal(count, 2, "events fired"); + equal(dv.getItems().length, 2, "items updated"); + equal(dv.rows.length, 2, "rows updated"); + assertConsistency(dv); +}); + +// TODO: paging +// TODO: combination
\ No newline at end of file diff --git a/tests/dataview/index.html b/tests/dataview/index.html new file mode 100644 index 0000000..860b3e7 --- /dev/null +++ b/tests/dataview/index.html @@ -0,0 +1,28 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title></title> + <link rel="stylesheet" href="../../lib/qunit.css" type="text/css"/> +</head> +<body> +<h1 id="qunit-header">QUnit Test Suite</h1> +<h2 id="qunit-banner"></h2> +<div id="qunit-testrunner-toolbar"></div> +<h2 id="qunit-userAgent"></h2> +<ol id="qunit-tests"></ol> + + + +<script type="text/javascript" src="../../lib/qunit.js"></script> +<script type="text/javascript" src="../../lib/jquery-1.4.2.min.js"></script> +<script type="text/javascript" src="../../slick.model.js"></script> + + +<script type="text/javascript" src="dataview.js"></script> + + + + +</body> +</html>
\ No newline at end of file diff --git a/tests/grid/grid.js b/tests/grid/grid.js new file mode 100644 index 0000000..4d52afe --- /dev/null +++ b/tests/grid/grid.js @@ -0,0 +1,67 @@ +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 + }); + dragged = { dx: dx, dy: dy }; + offsetAfter = el.offset(); +} + +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<ROWS; i++) { + row = {}; + row["id"] = "id_" + i; + for (var j=0; j<COLS; j++) { + row["col_" + j] = i + "." + j; + } + data.push(row); +} + +var cols = [], col; +for (var i=0; i<COLS; i++) { + col = {}; + col["id"] = "col" + i; + col["field"] = "col_" + i; + col["name"] = "col_" + i; + cols.push(col); +} + +cols[0].minWidth = 70; + +grid = new Slick.Grid($("#container"), data, cols); +grid.render(); + + + +module("grid - column resizing"); + +test("minWidth is respected", function() { + var firstCol = $("#container .slick-header-column:first"); + firstCol.find(".slick-resizable-handle:first").simulate("drag", {dx:100,dy:0}); + firstCol.find(".slick-resizable-handle:first").simulate("drag", {dx:-200,dy:0}); + equal(firstCol.outerWidth(), 70, "width set to minWidth"); +}); + + +test("onColumnsResized is fired on column resize", function() { + expect(2); + grid.onColumnsResized = function() { ok(true,"onColumnsResized called") }; + var oldWidth = cols[0].width; + $("#container .slick-resizable-handle:first").simulate("drag", {dx:100,dy:0}); + equal(cols[0].width, oldWidth+100-1, "columns array is updated"); + +}); + diff --git a/tests/grid/index.html b/tests/grid/index.html new file mode 100644 index 0000000..6a391bb --- /dev/null +++ b/tests/grid/index.html @@ -0,0 +1,41 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> + <title></title> + <link rel="stylesheet" href="../../lib/qunit.css" type="text/css"/> + <link rel="stylesheet" href="../../slick.grid.css" type="text/css"/> + <link rel="stylesheet" href="../../examples/slick-default-theme.css" type="text/css" /> + +</head> +<body> +<h1 id="qunit-header">QUnit Test Suite</h1> +<h2 id="qunit-banner"></h2> +<div id="qunit-testrunner-toolbar"></div> +<h2 id="qunit-userAgent"></h2> +<ol id="qunit-tests"></ol> + + +<br/><br/><br/> +<div id="container" style="width:600px;height:400px;"></div> + + +<script type="text/javascript" src="../../lib/qunit.js"></script> +<script type="text/javascript" src="../../lib/jquery-1.4.2.min.js"></script> +<script type="text/javascript" src="../../lib/jquery-ui-1.7.2.custom.min.js"></script> +<script type="text/javascript" src="../../lib/jquery.event.drag.custom.js"></script> +<script type="text/javascript" src="../../lib/jquery.rule-1.0.1.1-min.js"></script> +<script type="text/javascript" src="../../lib/jquery.simulate.js"></script> +<script type="text/javascript" src="../../lib/qunit.js"></script> +<script type="text/javascript" src="../../slick.model.js"></script> +<script type="text/javascript" src="../../slick.grid.js"></script> + + + +<script type="text/javascript" src="grid.js"></script> + + + + +</body> +</html>
\ No newline at end of file diff --git a/tests/index.html b/tests/index.html index 5a8775f..7649948 100644 --- a/tests/index.html +++ b/tests/index.html @@ -4,20 +4,34 @@ <head> <title></title> <link rel="stylesheet" href="../lib/qunit.css" type="text/css"/> + <style type="text/css"> + ul { font-family: 'trebuchet ms', verdana, arial; } + h2, ul {font-size: 10pt; } + h2 { + background-color:#EEEEEE; + color:black; + font-size:small; + font-weight:normal; + margin:0; + padding:10px; + } + </style> </head> <body> -<h1 id="qunit-header">QUnit Test Suite</h1> + +<h1 id="qunit-header">jQuery UI Unit Tests</h1> <h2 id="qunit-banner"></h2> -<div id="qunit-testrunner-toolbar"></div> -<h2 id="qunit-userAgent"></h2> -<ol id="qunit-tests"></ol> +<h2>Slick.Data</h2> +<ul> + <li><a href="dataview/index.html">DataView</a></li> +</ul> -<script type="text/javascript" src="../lib/qunit.js"></script> -<script type="text/javascript" src="../lib/jquery-1.4.2.min.js"></script> -<script type="text/javascript" src="../slick.model.js"></script> +<h2>Slick</h2> +<ul> + <li><a href="grid/index.html">Grid</a></li> +</ul> -<script type="text/javascript" src="dataview.js"></script> </body> </html>
\ No newline at end of file |