Skip to content
This repository has been archived by the owner on Apr 2, 2019. It is now read-only.

Commit

Permalink
Fix #168 and #219
Browse files Browse the repository at this point in the history
  • Loading branch information
wyuenho committed Jun 15, 2013
1 parent 840a4b5 commit 7a0cbec
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 214 deletions.
76 changes: 59 additions & 17 deletions assets/js/backbone-pageable.js
@@ -1,5 +1,5 @@
/*
backbone-pageable 1.3.0
backbone-pageable 1.3.1
http://github.com/wyuenho/backbone-pageable
Copyright (c) 2013 Jimmy Yuen Ho Wong
Expand Down Expand Up @@ -574,6 +574,17 @@
/**
Change the page size of this collection.
Under most if not all circumstances, you should call this method to
change the page size of a pageable collection because it will keep the
pagination state sane. By default, the method will recalculate the
current page number to one that will retain the current page's models
when increasing the page size. When decreasing the page size, this method
will retain the last models to the current page that will fit into the
smaller page size.
If `options.first` is true, changing the page size will also reset the
current page back to the first page instead of trying to be smart.
For server mode operations, changing the page size will trigger a #fetch
and subsequently a `reset` event.
Expand All @@ -586,6 +597,8 @@
@param {number} pageSize The new page size to set to #state.
@param {Object} [options] {@link #fetch} options.
@param {boolean} [options.first=false] Reset the current page number to
the first page if `true`.
@param {boolean} [options.fetch] If `true`, force a fetch in client mode.
@throws {TypeError} If `pageSize` is not a finite integer.
Expand All @@ -598,14 +611,24 @@
setPageSize: function (pageSize, options) {
pageSize = finiteInt(pageSize, "pageSize");

options = options || {};
options = options || {first: false};

this.state = this._checkState(_extend({}, this.state, {
var state = this.state;
var totalPages = ceil(state.totalRecords / pageSize);
var currentPage = max(state.firstPage,
floor(totalPages *
(state.firstPage ?
state.currentPage :
state.currentPage + 1) /
state.totalPages));

state = this.state = this._checkState(_extend({}, state, {
pageSize: pageSize,
totalPages: ceil(this.state.totalRecords / pageSize)
currentPage: options.first ? state.firstPage : currentPage,
totalPages: totalPages
}));

return this.getPage(this.state.currentPage, options);
return this.getPage(state.currentPage, _omit(options, ["first"]));
},

/**
Expand Down Expand Up @@ -992,13 +1015,14 @@
encouraged to override #parseState and #parseRecords instead.
@param {Object} resp The deserialized response data from the server.
@param {Object} the options for the ajax request
@return {Array.<Object>} An array of model objects
*/
parse: function (resp) {
var newState = this.parseState(resp, _clone(this.queryParams), _clone(this.state));
parse: function (resp, options) {
var newState = this.parseState(resp, _clone(this.queryParams), _clone(this.state), options);
if (newState) this.state = this._checkState(_extend({}, this.state, newState));
return this.parseRecords(resp);
return this.parseRecords(resp, options);
},

/**
Expand All @@ -1016,21 +1040,29 @@
`totalRecords` value is enough to trigger a full pagination state
recalculation.
parseState: function (resp, queryParams, state) {
parseState: function (resp, queryParams, state, options) {
return {totalRecords: resp.total_entries};
}
If you want to use header fields use:
parseState: function (resp, queryParams, state, options) {
return {totalRecords: options.xhr.getResponseHeader("X-total")};
}
This method __MUST__ return a new state object instead of directly
modifying the #state object. The behavior of directly modifying #state is
undefined.
@param {Object} resp The deserialized response data from the server.
@param {Object} queryParams A copy of #queryParams.
@param {Object} state A copy of #state.
@param {Object} [options] The options passed through from
`parse`. (backbone >= 0.9.10 only)
@return {Object} A new (partial) state object.
*/
parseState: function (resp, queryParams, state) {
parseState: function (resp, queryParams, state, options) {
if (resp && resp.length === 2 && _isObject(resp[0]) && _isArray(resp[1])) {

var newState = _clone(state);
Expand Down Expand Up @@ -1059,10 +1091,12 @@
response is returned directly.
@param {Object} resp The deserialized response data from the server.
@param {Object} [options] The options passed through from the
`parse`. (backbone >= 0.9.10 only)
@return {Array.<Object>} An array of model objects
*/
parseRecords: function (resp) {
parseRecords: function (resp, options) {
if (resp && resp.length === 2 && _isObject(resp[0]) && _isArray(resp[1])) {
return resp[1];
}
Expand Down Expand Up @@ -1212,20 +1246,24 @@
@param {string} [sortKey=this.state.sortKey] See `state.sortKey`.
@param {number} [order=this.state.order] See `state.order`.
@param {(function(Backbone.Model, string): Object) | string} [sortValue] See #setSorting.
See [Backbone.Collection.comparator](http://backbonejs.org/#Collection-comparator).
*/
_makeComparator: function (sortKey, order) {

_makeComparator: function (sortKey, order, sortValue) {
var state = this.state;

sortKey = sortKey || state.sortKey;
order = order || state.order;

if (!sortKey || !order) return;

if (!sortValue) sortValue = function (model, attr) {
return model.get(attr);
};

return function (left, right) {
var l = left.get(sortKey), r = right.get(sortKey), t;
var l = sortValue(left, sortKey), r = sortValue(right, sortKey), t;
if (order === 1) t = l, l = r, r = t;
if (l === r) return 0;
else if (l < r) return -1;
Expand All @@ -1244,6 +1282,11 @@
`sortKey` to `null` removes the comparator from both the current page and
the full collection.
If a `sortValue` function is given, it will be passed the `(model,
sortKey)` arguments and is used to extract a value from the model during
comparison sorts. If `sortValue` is not given, `model.get(sortKey)` is
used for sorting.
@chainable
@param {string} sortKey See `state.sortKey`.
Expand All @@ -1252,6 +1295,7 @@
@param {"server"|"client"} [options.side] By default, `"client"` if
`mode` is `"client"`, `"server"` otherwise.
@param {boolean} [options.full=true]
@param {(function(Backbone.Model, string): Object) | string} [options.sortValue]
*/
setSorting: function (sortKey, order, options) {

Expand All @@ -1270,9 +1314,7 @@
options = _extend({side: mode == "client" ? mode : "server", full: true},
options);

var comparator = options.makeComparator ?
options.makeComparator(sortKey, order) :
this._makeComparator(sortKey, order);
var comparator = this._makeComparator(sortKey, order, options.sortValue);

var full = options.full, side = options.side;

Expand Down
14 changes: 10 additions & 4 deletions src/body.js
Expand Up @@ -241,6 +241,7 @@ var Body = Backgrid.Body = Backbone.View.extend({
moveToNextCell: function (model, column, command) {
var i = this.collection.indexOf(model);
var j = this.columns.indexOf(column);
var cell, renderable, editable;

this.rows[i].cells[j].exitEditMode();

Expand All @@ -251,7 +252,12 @@ var Body = Backgrid.Body = Backbone.View.extend({

if (command.moveUp() || command.moveDown()) {
var row = this.rows[i + (command.moveUp() ? -1 : 1)];
if (row) row.cells[j].enterEditMode();
if (row) {
cell = row.cells[j];
if (Backgrid.callByNeed(cell.column.get("editable"), cell.column, model)) {
cell.enterEditMode();
}
}
}
else if (command.moveLeft() || command.moveRight()) {
var right = command.moveRight();
Expand All @@ -260,9 +266,9 @@ var Body = Backgrid.Body = Backbone.View.extend({
right ? offset++ : offset--) {
var m = ~~(offset / l);
var n = offset - m * l;
var cell = this.rows[m].cells[n];
var renderable = Backgrid.callByNeed(cell.column.get("renderable"), cell.column, cell.model);
var editable = Backgrid.callByNeed(cell.column.get("editable"), cell.column, model);
cell = this.rows[m].cells[n];
renderable = Backgrid.callByNeed(cell.column.get("renderable"), cell.column, cell.model);
editable = Backgrid.callByNeed(cell.column.get("editable"), cell.column, model);
if (renderable && editable) {
cell.enterEditMode();
break;
Expand Down
51 changes: 45 additions & 6 deletions src/column.js
Expand Up @@ -25,6 +25,7 @@ var Column = Backgrid.Column = Backbone.Model.extend({
editable: true,
renderable: true,
formatter: undefined,
sortValue: undefined,
cell: undefined,
headerCell: undefined
},
Expand All @@ -33,22 +34,36 @@ var Column = Backgrid.Column = Backbone.Model.extend({
Initializes this Column instance.
@param {Object} attrs Column attributes.
@param {string} attrs.name The name of the model attribute.
@param {string|Backgrid.Cell} attrs.cell The cell type.
If this is a string, the capitalized form will be used to look up a
cell class in Backbone, i.e.: string => StringCell. If a Cell subclass
is supplied, it is initialized with a hash of parameters. If a Cell
instance is supplied, it is used directly.
@param {string|Backgrid.HeaderCell} [attrs.headerCell] The header cell type.
@param {string} [attrs.label] The label to show in the header.
@param {boolean} [attrs.sortable=true]
@param {boolean} [attrs.editable=true]
@param {boolean} [attrs.renderable=true]
@param {Backgrid.CellFormatter|Object|string} [attrs.formatter] The
@param {boolean|string} [attrs.sortable=true]
@param {boolean|string} [attrs.editable=true]
@param {boolean|string} [attrs.renderable=true]
@param {Backgrid.CellFormatter | Object | string} [attrs.formatter] The
formatter to use to convert between raw model values and user input.
@param {(function(Backbone.Model, string): Object) | string} [sortValue] The
function to use to extract a value from the model for comparison during
sorting. If this value is a string, a method with the same name will be
looked up from the column instance.
@throws {TypeError} If attrs.cell or attrs.options are not supplied.
@throws {ReferenceError} If attrs.cell is a string but a cell class of
@throws {ReferenceError} If formatter is a string but a formatter class of
said name cannot be found in the Backgrid module.
See:
Expand All @@ -64,8 +79,32 @@ var Column = Backgrid.Column = Backbone.Model.extend({
}

var headerCell = Backgrid.resolveNameToClass(this.get("headerCell"), "HeaderCell");

var cell = Backgrid.resolveNameToClass(this.get("cell"), "Cell");
this.set({ cell: cell, headerCell: headerCell }, { silent: true });

var sortValue = this.get("sortValue");
if (sortValue == null) sortValue = function (model, colName) {
return model.get(colName);
};
else if (_.isString(sortValue)) sortValue = this[sortValue];

var sortable = this.get("sortable");
if (_.isString(sortable)) sortable = this[sortable];

var editable = this.get("editable");
if (_.isString(editable)) editable = this[editable];

var renderable = this.get("renderable");
if (_.isString(renderable)) renderable = this[renderable];

this.set({
cell: cell,
headerCell: headerCell,
sortable: sortable,
editable: editable,
renderable: renderable,
sortValue: sortValue
}, { silent: true });
}

});
Expand Down

0 comments on commit 7a0cbec

Please sign in to comment.