backgridjs-rails 0.2.6 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +6 -14
- data/lib/backgridjs-rails/version.rb +1 -1
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-filter.js +192 -49
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-moment-cell.js +15 -5
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-paginator.js +341 -112
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-select-all.js +109 -32
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-select2-cell.js +42 -14
- data/vendor/assets/javascripts/backgrid-extensions/backgrid-text-cell.js +18 -9
- data/vendor/assets/javascripts/backgrid.js +689 -336
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-filter.css +181 -7
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-moment-cell.css +2 -1
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-paginator.css +5 -5
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select-all.css +2 -1
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-select2-cell.css +1 -1
- data/vendor/assets/stylesheets/backgrid-extensions/backgrid-text-cell.css +3 -3
- data/vendor/assets/stylesheets/backgrid.css +35 -10
- metadata +18 -21
- data/lib/backgridjs-rails.rb~ +0 -2
- data/lib/backgridjs-rails/engine.rb~ +0 -8
- data/lib/backgridjs-rails/version.rb~ +0 -3
@@ -5,7 +5,18 @@
|
|
5
5
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
6
6
|
Licensed under the MIT @license.
|
7
7
|
*/
|
8
|
-
(function (
|
8
|
+
(function (root, factory) {
|
9
|
+
|
10
|
+
// CommonJS
|
11
|
+
if (typeof exports == "object") {
|
12
|
+
module.exports = factory(require("backbone"), require("backgrid"), require("underscore"));
|
13
|
+
}
|
14
|
+
// Browser
|
15
|
+
else factory(root.Backbone, root.Backgrid, root._);
|
16
|
+
|
17
|
+
}(this, function (Backbone, Backgrid, _) {
|
18
|
+
|
19
|
+
"use strict";
|
9
20
|
|
10
21
|
/**
|
11
22
|
Renders a checkbox for row selection.
|
@@ -23,9 +34,9 @@
|
|
23
34
|
|
24
35
|
/** @property */
|
25
36
|
events: {
|
26
|
-
"keydown
|
27
|
-
"change
|
28
|
-
"click
|
37
|
+
"keydown input[type=checkbox]": "onKeydown",
|
38
|
+
"change input[type=checkbox]": "onChange",
|
39
|
+
"click input[type=checkbox]": "enterEditMode"
|
29
40
|
},
|
30
41
|
|
31
42
|
/**
|
@@ -37,31 +48,43 @@
|
|
37
48
|
@param {Backbone.Model} options.model
|
38
49
|
*/
|
39
50
|
initialize: function (options) {
|
40
|
-
Backgrid.requireOptions(options, ["model", "column"]);
|
41
51
|
|
42
52
|
this.column = options.column;
|
43
53
|
if (!(this.column instanceof Backgrid.Column)) {
|
44
54
|
this.column = new Backgrid.Column(this.column);
|
45
55
|
}
|
46
56
|
|
47
|
-
this.
|
48
|
-
|
57
|
+
var column = this.column, model = this.model, $el = this.$el;
|
58
|
+
this.listenTo(column, "change:renderable", function (column, renderable) {
|
59
|
+
$el.toggleClass("renderable", renderable);
|
49
60
|
});
|
50
61
|
|
62
|
+
if (Backgrid.callByNeed(column.renderable(), column, model)) $el.addClass("renderable");
|
63
|
+
|
64
|
+
this.listenTo(model, "backgrid:select", function (model, selected) {
|
65
|
+
this.checkbox().prop("checked", selected).change();
|
66
|
+
});
|
67
|
+
},
|
68
|
+
|
69
|
+
/**
|
70
|
+
Returns the checkbox.
|
71
|
+
*/
|
72
|
+
checkbox: function () {
|
73
|
+
return this.$el.find("input[type=checkbox]");
|
51
74
|
},
|
52
75
|
|
53
76
|
/**
|
54
77
|
Focuses the checkbox.
|
55
78
|
*/
|
56
79
|
enterEditMode: function () {
|
57
|
-
this
|
80
|
+
this.checkbox().focus();
|
58
81
|
},
|
59
82
|
|
60
83
|
/**
|
61
84
|
Unfocuses the checkbox.
|
62
85
|
*/
|
63
86
|
exitEditMode: function () {
|
64
|
-
this
|
87
|
+
this.checkbox().blur();
|
65
88
|
},
|
66
89
|
|
67
90
|
/**
|
@@ -72,7 +95,7 @@
|
|
72
95
|
if (command.passThru()) return true; // skip ahead to `change`
|
73
96
|
if (command.cancel()) {
|
74
97
|
e.stopPropagation();
|
75
|
-
this
|
98
|
+
this.checkbox().blur();
|
76
99
|
}
|
77
100
|
else if (command.save() || command.moveLeft() || command.moveRight() ||
|
78
101
|
command.moveUp() || command.moveDown()) {
|
@@ -87,8 +110,10 @@
|
|
87
110
|
`backgrid:selected` event with a reference of the model and the
|
88
111
|
checkbox's `checked` value.
|
89
112
|
*/
|
90
|
-
onChange: function (
|
91
|
-
|
113
|
+
onChange: function () {
|
114
|
+
var checked = this.checkbox().prop("checked");
|
115
|
+
this.$el.parent().toggleClass("selected", checked);
|
116
|
+
this.model.trigger("backgrid:selected", this.model, checked);
|
92
117
|
},
|
93
118
|
|
94
119
|
/**
|
@@ -135,7 +160,6 @@
|
|
135
160
|
@param {Backbone.Collection} options.collection
|
136
161
|
*/
|
137
162
|
initialize: function (options) {
|
138
|
-
Backgrid.requireOptions(options, ["column", "collection"]);
|
139
163
|
|
140
164
|
this.column = options.column;
|
141
165
|
if (!(this.column instanceof Backgrid.Column)) {
|
@@ -144,49 +168,86 @@
|
|
144
168
|
|
145
169
|
var collection = this.collection;
|
146
170
|
var selectedModels = this.selectedModels = {};
|
147
|
-
this.listenTo(collection
|
148
|
-
|
171
|
+
this.listenTo(collection.fullCollection || collection,
|
172
|
+
"backgrid:selected", function (model, selected) {
|
173
|
+
if (selected) selectedModels[model.id || model.cid] = 1;
|
149
174
|
else {
|
150
175
|
delete selectedModels[model.id || model.cid];
|
151
|
-
this
|
176
|
+
this.checkbox().prop("checked", false);
|
177
|
+
}
|
178
|
+
if (_.keys(selectedModels).length === (collection.fullCollection|| collection).length) {
|
179
|
+
this.checkbox().prop("checked", true);
|
152
180
|
}
|
153
181
|
});
|
154
182
|
|
155
|
-
this.listenTo(collection, "remove", function (model) {
|
156
|
-
delete selectedModels[model.cid];
|
183
|
+
this.listenTo(collection.fullCollection || collection, "remove", function (model) {
|
184
|
+
delete selectedModels[model.id || model.cid];
|
185
|
+
if ((collection.fullCollection || collection).length === 0) {
|
186
|
+
this.checkbox().prop("checked", false);
|
187
|
+
}
|
157
188
|
});
|
158
189
|
|
159
190
|
this.listenTo(collection, "backgrid:refresh", function () {
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
191
|
+
if ((collection.fullCollection || collection).length === 0) {
|
192
|
+
this.checkbox().prop("checked", false);
|
193
|
+
}
|
194
|
+
else {
|
195
|
+
var checked = this.checkbox().prop("checked");
|
196
|
+
for (var i = 0; i < collection.length; i++) {
|
197
|
+
var model = collection.at(i);
|
198
|
+
if (checked || selectedModels[model.id || model.cid]) {
|
199
|
+
model.trigger("backgrid:select", model, true);
|
200
|
+
}
|
165
201
|
}
|
166
202
|
}
|
167
203
|
});
|
204
|
+
|
205
|
+
var column = this.column, $el = this.$el;
|
206
|
+
this.listenTo(column, "change:renderable", function (column, renderable) {
|
207
|
+
$el.toggleClass("renderable", renderable);
|
208
|
+
});
|
209
|
+
|
210
|
+
if (Backgrid.callByNeed(column.renderable(), column, collection)) $el.addClass("renderable");
|
168
211
|
},
|
169
212
|
|
170
213
|
/**
|
171
|
-
|
214
|
+
Propagates the checked value of this checkbox to all the models of the
|
172
215
|
underlying collection by triggering a Backbone `backgrid:select` event on
|
173
|
-
the models
|
174
|
-
of the checkbox in each event.
|
216
|
+
the models on the current page, passing each model and the current
|
217
|
+
`checked` value of the checkbox in each event.
|
218
|
+
|
219
|
+
A `backgrid:selected` event will also be triggered with the current
|
220
|
+
`checked` value on all the models regardless of whether they are on the
|
221
|
+
current page.
|
222
|
+
|
223
|
+
This method triggers a 'backgrid:select-all' event on the collection
|
224
|
+
afterwards.
|
175
225
|
*/
|
176
|
-
onChange: function (
|
177
|
-
var checked =
|
226
|
+
onChange: function () {
|
227
|
+
var checked = this.checkbox().prop("checked");
|
178
228
|
|
179
229
|
var collection = this.collection;
|
180
230
|
collection.each(function (model) {
|
181
231
|
model.trigger("backgrid:select", model, checked);
|
182
232
|
});
|
233
|
+
|
234
|
+
if (collection.fullCollection) {
|
235
|
+
collection.fullCollection.each(function (model) {
|
236
|
+
if (!collection.get(model.cid)) {
|
237
|
+
model.trigger("backgrid:selected", model, checked);
|
238
|
+
}
|
239
|
+
});
|
240
|
+
}
|
241
|
+
|
242
|
+
this.collection.trigger("backgrid:select-all", this.collection, checked);
|
183
243
|
}
|
184
244
|
|
185
245
|
});
|
186
246
|
|
187
247
|
/**
|
188
248
|
Convenient method to retrieve a list of selected models. This method only
|
189
|
-
exists when the `SelectAll` extension has been included.
|
249
|
+
exists when the `SelectAll` extension has been included. Selected models
|
250
|
+
are retained across pagination.
|
190
251
|
|
191
252
|
@member Backgrid.Grid
|
192
253
|
@return {Array.<Backbone.Model>}
|
@@ -204,12 +265,28 @@
|
|
204
265
|
|
205
266
|
var result = [];
|
206
267
|
if (selectAllHeaderCell) {
|
207
|
-
|
208
|
-
|
268
|
+
var selectedModels = selectAllHeaderCell.selectedModels;
|
269
|
+
var collection = this.collection.fullCollection || this.collection;
|
270
|
+
for (var modelId in selectedModels) {
|
271
|
+
result.push(collection.get(modelId));
|
209
272
|
}
|
210
273
|
}
|
211
274
|
|
212
275
|
return result;
|
213
276
|
};
|
214
277
|
|
215
|
-
|
278
|
+
/**
|
279
|
+
Convenient method to deselect the selected models. This method is only
|
280
|
+
available when the `SelectAll` extension has been included.
|
281
|
+
|
282
|
+
@member Backgrid.Grid
|
283
|
+
*/
|
284
|
+
Backgrid.Grid.prototype.clearSelectedModels = function () {
|
285
|
+
var selectedModels = this.getSelectedModels();
|
286
|
+
for (var i = 0, l = selectedModels.length; i < l; i++) {
|
287
|
+
var model = selectedModels[i];
|
288
|
+
model.trigger("backgrid:select", model, false);
|
289
|
+
}
|
290
|
+
};
|
291
|
+
|
292
|
+
}));
|
@@ -5,8 +5,21 @@
|
|
5
5
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
6
6
|
Licensed under the MIT @license.
|
7
7
|
*/
|
8
|
+
(function (root, factory) {
|
8
9
|
|
9
|
-
|
10
|
+
// CommonJS
|
11
|
+
if (typeof exports == "object") {
|
12
|
+
require("select2");
|
13
|
+
module.exports = factory(root,
|
14
|
+
require("underscore"),
|
15
|
+
require("backgrid"));
|
16
|
+
}
|
17
|
+
// Browser
|
18
|
+
else factory(root, root._, root.Backgrid);
|
19
|
+
|
20
|
+
}(this, function (root, _, Backgrid) {
|
21
|
+
|
22
|
+
"use strict";
|
10
23
|
|
11
24
|
/**
|
12
25
|
Select2CellEditor is a cell editor that renders a `select2` select box
|
@@ -23,12 +36,13 @@
|
|
23
36
|
|
24
37
|
/** @property */
|
25
38
|
events: {
|
26
|
-
"close": "save",
|
27
39
|
"change": "save"
|
28
40
|
},
|
29
41
|
|
30
42
|
/** @property */
|
31
|
-
select2Options:
|
43
|
+
select2Options: {
|
44
|
+
openOnEnter: false
|
45
|
+
},
|
32
46
|
|
33
47
|
initialize: function () {
|
34
48
|
Backgrid.SelectCellEditor.prototype.initialize.apply(this, arguments);
|
@@ -40,8 +54,7 @@
|
|
40
54
|
edit mode.
|
41
55
|
*/
|
42
56
|
setSelect2Options: function (options) {
|
43
|
-
this.select2Options = _.extend({
|
44
|
-
options || {});
|
57
|
+
this.select2Options = _.extend(options || {});
|
45
58
|
},
|
46
59
|
|
47
60
|
/**
|
@@ -53,7 +66,6 @@
|
|
53
66
|
render: function () {
|
54
67
|
Backgrid.SelectCellEditor.prototype.render.apply(this, arguments);
|
55
68
|
this.$el.select2(this.select2Options);
|
56
|
-
this.delegateEvents();
|
57
69
|
return this;
|
58
70
|
},
|
59
71
|
|
@@ -62,13 +74,29 @@
|
|
62
74
|
*/
|
63
75
|
postRender: function () {
|
64
76
|
var self = this;
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
77
|
+
if (self.multiple) self.$el.select2("container").keydown(self.close);
|
78
|
+
else self.$el.data("select2").focusser.keydown(self.close);
|
79
|
+
|
80
|
+
self.$el.on("select2-blur", function (e) {
|
81
|
+
if (!self.multiple) {
|
82
|
+
e.type = "blur";
|
83
|
+
self.close(e);
|
84
|
+
}
|
85
|
+
else {
|
86
|
+
// HACK to get around https://github.com/ivaynberg/select2/issues/2011
|
87
|
+
// select2-blur is triggered from blur and is fired repeatibly under
|
88
|
+
// multiple select. Since blue is fired before everything, but focus
|
89
|
+
// is set in focus and click, we need to wait for a while so other
|
90
|
+
// event handlers may have a chance to run.
|
91
|
+
var id = root.setTimeout(function () {
|
92
|
+
root.clearTimeout(id);
|
93
|
+
if (!self.$el.select2("isFocused")) {
|
94
|
+
e.type = "blur";
|
95
|
+
self.close(e);
|
96
|
+
}
|
97
|
+
}, 200);
|
98
|
+
}
|
99
|
+
}).select2("focus");
|
72
100
|
},
|
73
101
|
|
74
102
|
remove: function () {
|
@@ -118,4 +146,4 @@
|
|
118
146
|
|
119
147
|
});
|
120
148
|
|
121
|
-
}
|
149
|
+
}));
|
@@ -5,8 +5,17 @@
|
|
5
5
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
6
6
|
Licensed under the MIT @license.
|
7
7
|
*/
|
8
|
+
(function (root, factory) {
|
8
9
|
|
9
|
-
|
10
|
+
// CommonJS
|
11
|
+
if (typeof exports == "object") {
|
12
|
+
module.exports = factory(require("underscore"),
|
13
|
+
require("backgrid"));
|
14
|
+
}
|
15
|
+
// Browser
|
16
|
+
else factory(root._, root.Backgrid);
|
17
|
+
|
18
|
+
}(this, function (_, Backgrid) {
|
10
19
|
|
11
20
|
/**
|
12
21
|
Renders a form with a text area and a save button in a modal dialog.
|
@@ -20,10 +29,10 @@
|
|
20
29
|
tagName: "div",
|
21
30
|
|
22
31
|
/** @property */
|
23
|
-
className: "modal
|
32
|
+
className: "modal fade",
|
24
33
|
|
25
34
|
/** @property {function(Object, ?Object=): string} template */
|
26
|
-
template: _.template('<form><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h3><%- column.get("label") %></h3></div><div class="modal-body"><textarea cols="<%= cols %>" rows="<%= rows %>"><%- content %></textarea></div><div class="modal-footer"><input class="btn" type="submit" value="Save"/></div></form>'),
|
35
|
+
template: _.template('<div class="modal-dialog"><div class="modal-content"><form><div class="modal-header"><button type="button" class="close" data-dismiss="modal">×</button><h3><%- column.get("label") %></h3></div><div class="modal-body"><textarea cols="<%= cols %>" rows="<%= rows %>"><%- content %></textarea></div><div class="modal-footer"><input class="btn btn-primary" type="submit" value="Save"/></div></form></div></div>', null, {variable: null}),
|
27
36
|
|
28
37
|
/** @property */
|
29
38
|
cols: 80,
|
@@ -35,9 +44,9 @@
|
|
35
44
|
events: {
|
36
45
|
"keydown textarea": "clearError",
|
37
46
|
"submit": "saveOrCancel",
|
38
|
-
"hide": "saveOrCancel",
|
39
|
-
"hidden": "close",
|
40
|
-
"shown": "focus"
|
47
|
+
"hide.bs.modal": "saveOrCancel",
|
48
|
+
"hidden.bs.modal": "close",
|
49
|
+
"shown.bs.modal": "focus"
|
41
50
|
},
|
42
51
|
|
43
52
|
/**
|
@@ -100,7 +109,7 @@
|
|
100
109
|
else if (!e || e.type == "submit" ||
|
101
110
|
(e.type == "hide" &&
|
102
111
|
newValue !== (this.model.get(this.column.get("name")) || '').replace(/\r/g, '') &&
|
103
|
-
|
112
|
+
confirm("Would you like to save your changes?"))) {
|
104
113
|
|
105
114
|
model.set(column.get("name"), newValue);
|
106
115
|
this.$el.modal("hide");
|
@@ -146,7 +155,7 @@
|
|
146
155
|
@class Backgrid.Extension.TextCell
|
147
156
|
@extends Backgrid.StringCell
|
148
157
|
*/
|
149
|
-
|
158
|
+
Backgrid.Extension.TextCell = Backgrid.StringCell.extend({
|
150
159
|
|
151
160
|
/** @property */
|
152
161
|
className: "text-cell",
|
@@ -156,4 +165,4 @@
|
|
156
165
|
|
157
166
|
});
|
158
167
|
|
159
|
-
}
|
168
|
+
}));
|
@@ -1,23 +1,36 @@
|
|
1
|
-
|
2
|
-
backgrid
|
1
|
+
/*!
|
2
|
+
backgrid 0.3.5
|
3
3
|
http://github.com/wyuenho/backgrid
|
4
4
|
|
5
|
-
Copyright (c)
|
6
|
-
Licensed under the MIT
|
5
|
+
Copyright (c) 2014 Jimmy Yuen Ho Wong and contributors <wyuenho@gmail.com>
|
6
|
+
Licensed under the MIT license.
|
7
7
|
*/
|
8
|
-
|
8
|
+
|
9
|
+
(function (root, factory) {
|
10
|
+
|
11
|
+
if (typeof define === "function" && define.amd) {
|
12
|
+
// AMD (+ global for extensions)
|
13
|
+
define(["underscore", "backbone"], function (_, Backbone) {
|
14
|
+
return (root.Backgrid = factory(_, Backbone));
|
15
|
+
});
|
16
|
+
} else if (typeof exports === "object") {
|
17
|
+
// CommonJS
|
18
|
+
module.exports = factory(require("underscore"), require("backbone"));
|
19
|
+
} else {
|
20
|
+
// Browser
|
21
|
+
root.Backgrid = factory(root._, root.Backbone);
|
22
|
+
}}(this, function (_, Backbone) {
|
9
23
|
|
10
24
|
"use strict";
|
25
|
+
|
11
26
|
/*
|
12
27
|
backgrid
|
13
28
|
http://github.com/wyuenho/backgrid
|
14
29
|
|
15
30
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
16
|
-
Licensed under the MIT
|
31
|
+
Licensed under the MIT license.
|
17
32
|
*/
|
18
33
|
|
19
|
-
var window = root;
|
20
|
-
|
21
34
|
// Copyright 2009, 2010 Kristopher Michael Kowal
|
22
35
|
// https://github.com/kriskowal/es5-shim
|
23
36
|
// ES5 15.5.4.20
|
@@ -41,10 +54,6 @@ if (!String.prototype.trim || ws.trim()) {
|
|
41
54
|
};
|
42
55
|
}
|
43
56
|
|
44
|
-
function capitalize(s) {
|
45
|
-
return String.fromCharCode(s.charCodeAt(0) - 32) + s.slice(1);
|
46
|
-
}
|
47
|
-
|
48
57
|
function lpad(str, length, padstr) {
|
49
58
|
var paddingLen = length - (str + '').length;
|
50
59
|
paddingLen = paddingLen < 0 ? 0 : paddingLen;
|
@@ -55,24 +64,17 @@ function lpad(str, length, padstr) {
|
|
55
64
|
return padding + str;
|
56
65
|
}
|
57
66
|
|
58
|
-
var
|
67
|
+
var $ = Backbone.$;
|
59
68
|
|
60
|
-
|
69
|
+
var Backgrid = {
|
61
70
|
|
62
71
|
Extension: {},
|
63
72
|
|
64
|
-
requireOptions: function (options, requireOptionKeys) {
|
65
|
-
for (var i = 0; i < requireOptionKeys.length; i++) {
|
66
|
-
var key = requireOptionKeys[i];
|
67
|
-
if (_.isUndefined(options[key])) {
|
68
|
-
throw new TypeError("'" + key + "' is required");
|
69
|
-
}
|
70
|
-
}
|
71
|
-
},
|
72
|
-
|
73
73
|
resolveNameToClass: function (name, suffix) {
|
74
74
|
if (_.isString(name)) {
|
75
|
-
var key = _.map(name.split('-'), function (e) {
|
75
|
+
var key = _.map(name.split('-'), function (e) {
|
76
|
+
return e.slice(0, 1).toUpperCase() + e.slice(1);
|
77
|
+
}).join('') + suffix;
|
76
78
|
var klass = Backgrid[key] || Backgrid.Extension[key];
|
77
79
|
if (_.isUndefined(klass)) {
|
78
80
|
throw new ReferenceError("Class '" + key + "' not found");
|
@@ -81,7 +83,17 @@ var Backgrid = root.Backgrid = {
|
|
81
83
|
}
|
82
84
|
|
83
85
|
return name;
|
86
|
+
},
|
87
|
+
|
88
|
+
callByNeed: function () {
|
89
|
+
var value = arguments[0];
|
90
|
+
if (!_.isFunction(value)) return value;
|
91
|
+
|
92
|
+
var context = arguments[1];
|
93
|
+
var args = [].slice.call(arguments, 2);
|
94
|
+
return value.apply(context, !!(args + '') ? args : []);
|
84
95
|
}
|
96
|
+
|
85
97
|
};
|
86
98
|
_.extend(Backgrid, Backbone.Events);
|
87
99
|
|
@@ -99,7 +111,7 @@ _.extend(Backgrid, Backbone.Events);
|
|
99
111
|
var Command = Backgrid.Command = function (evt) {
|
100
112
|
_.extend(this, {
|
101
113
|
altKey: !!evt.altKey,
|
102
|
-
char: evt
|
114
|
+
"char": evt["char"],
|
103
115
|
charCode: evt.charCode,
|
104
116
|
ctrlKey: !!evt.ctrlKey,
|
105
117
|
key: evt.key,
|
@@ -165,7 +177,7 @@ _.extend(Command.prototype, {
|
|
165
177
|
http://github.com/wyuenho/backgrid
|
166
178
|
|
167
179
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
168
|
-
Licensed under the MIT
|
180
|
+
Licensed under the MIT license.
|
169
181
|
*/
|
170
182
|
|
171
183
|
/**
|
@@ -189,9 +201,10 @@ _.extend(CellFormatter.prototype, {
|
|
189
201
|
|
190
202
|
@member Backgrid.CellFormatter
|
191
203
|
@param {*} rawData
|
204
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
192
205
|
@return {*}
|
193
206
|
*/
|
194
|
-
fromRaw: function (rawData) {
|
207
|
+
fromRaw: function (rawData, model) {
|
195
208
|
return rawData;
|
196
209
|
},
|
197
210
|
|
@@ -204,16 +217,18 @@ _.extend(CellFormatter.prototype, {
|
|
204
217
|
|
205
218
|
@member Backgrid.CellFormatter
|
206
219
|
@param {string} formattedData
|
220
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
207
221
|
@return {*|undefined}
|
208
222
|
*/
|
209
|
-
toRaw: function (formattedData) {
|
223
|
+
toRaw: function (formattedData, model) {
|
210
224
|
return formattedData;
|
211
225
|
}
|
212
226
|
|
213
227
|
});
|
214
228
|
|
215
229
|
/**
|
216
|
-
A floating point number formatter. Doesn't understand notation at
|
230
|
+
A floating point number formatter. Doesn't understand scientific notation at
|
231
|
+
the moment.
|
217
232
|
|
218
233
|
@class Backgrid.NumberFormatter
|
219
234
|
@extends Backgrid.CellFormatter
|
@@ -221,8 +236,7 @@ _.extend(CellFormatter.prototype, {
|
|
221
236
|
@throws {RangeError} If decimals < 0 or > 20.
|
222
237
|
*/
|
223
238
|
var NumberFormatter = Backgrid.NumberFormatter = function (options) {
|
224
|
-
|
225
|
-
_.extend(this, this.defaults, options);
|
239
|
+
_.extend(this, this.defaults, options || {});
|
226
240
|
|
227
241
|
if (this.decimals < 0 || this.decimals > 20) {
|
228
242
|
throw new RangeError("decimals must be between 0 and 20");
|
@@ -259,9 +273,10 @@ _.extend(NumberFormatter.prototype, {
|
|
259
273
|
|
260
274
|
@member Backgrid.NumberFormatter
|
261
275
|
@param {number} number
|
276
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
262
277
|
@return {string}
|
263
278
|
*/
|
264
|
-
fromRaw: function (number) {
|
279
|
+
fromRaw: function (number, model) {
|
265
280
|
if (_.isNull(number) || _.isUndefined(number)) return '';
|
266
281
|
|
267
282
|
number = number.toFixed(~~this.decimals);
|
@@ -279,13 +294,18 @@ _.extend(NumberFormatter.prototype, {
|
|
279
294
|
|
280
295
|
@member Backgrid.NumberFormatter
|
281
296
|
@param {string} formattedData
|
297
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
282
298
|
@return {number|undefined} Undefined if the string cannot be converted to
|
283
299
|
a number.
|
284
300
|
*/
|
285
|
-
toRaw: function (formattedData) {
|
301
|
+
toRaw: function (formattedData, model) {
|
302
|
+
formattedData = formattedData.trim();
|
303
|
+
|
304
|
+
if (formattedData === '') return null;
|
305
|
+
|
286
306
|
var rawData = '';
|
287
307
|
|
288
|
-
var thousands = formattedData.
|
308
|
+
var thousands = formattedData.split(this.orderSeparator);
|
289
309
|
for (var i = 0; i < thousands.length; i++) {
|
290
310
|
rawData += thousands[i];
|
291
311
|
}
|
@@ -306,6 +326,76 @@ _.extend(NumberFormatter.prototype, {
|
|
306
326
|
|
307
327
|
});
|
308
328
|
|
329
|
+
/**
|
330
|
+
A number formatter that converts a floating point number, optionally
|
331
|
+
multiplied by a multiplier, to a percentage string and vice versa.
|
332
|
+
|
333
|
+
@class Backgrid.PercentFormatter
|
334
|
+
@extends Backgrid.NumberFormatter
|
335
|
+
@constructor
|
336
|
+
@throws {RangeError} If decimals < 0 or > 20.
|
337
|
+
*/
|
338
|
+
var PercentFormatter = Backgrid.PercentFormatter = function () {
|
339
|
+
Backgrid.NumberFormatter.apply(this, arguments);
|
340
|
+
};
|
341
|
+
|
342
|
+
PercentFormatter.prototype = new Backgrid.NumberFormatter(),
|
343
|
+
|
344
|
+
_.extend(PercentFormatter.prototype, {
|
345
|
+
|
346
|
+
/**
|
347
|
+
@member Backgrid.PercentFormatter
|
348
|
+
@cfg {Object} options
|
349
|
+
|
350
|
+
@cfg {number} [options.multiplier=1] The number used to multiply the model
|
351
|
+
value for display.
|
352
|
+
|
353
|
+
@cfg {string} [options.symbol='%'] The symbol to append to the percentage
|
354
|
+
string.
|
355
|
+
*/
|
356
|
+
defaults: _.extend({}, NumberFormatter.prototype.defaults, {
|
357
|
+
multiplier: 1,
|
358
|
+
symbol: "%"
|
359
|
+
}),
|
360
|
+
|
361
|
+
/**
|
362
|
+
Takes a floating point number, where the number is first multiplied by
|
363
|
+
`multiplier`, then converted to a formatted string like
|
364
|
+
NumberFormatter#fromRaw, then finally append `symbol` to the end.
|
365
|
+
|
366
|
+
@member Backgrid.PercentFormatter
|
367
|
+
@param {number} rawValue
|
368
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
369
|
+
@return {string}
|
370
|
+
*/
|
371
|
+
fromRaw: function (number, model) {
|
372
|
+
var args = [].slice.call(arguments, 1);
|
373
|
+
args.unshift(number * this.multiplier);
|
374
|
+
return (NumberFormatter.prototype.fromRaw.apply(this, args) || "0") + this.symbol;
|
375
|
+
},
|
376
|
+
|
377
|
+
/**
|
378
|
+
Takes a string, possibly appended with `symbol` and/or `decimalSeparator`,
|
379
|
+
and convert it back to a number for the model like NumberFormatter#toRaw,
|
380
|
+
and then dividing it by `multiplier`.
|
381
|
+
|
382
|
+
@member Backgrid.PercentFormatter
|
383
|
+
@param {string} formattedData
|
384
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
385
|
+
@return {number|undefined} Undefined if the string cannot be converted to
|
386
|
+
a number.
|
387
|
+
*/
|
388
|
+
toRaw: function (formattedValue, model) {
|
389
|
+
var tokens = formattedValue.split(this.symbol);
|
390
|
+
if (tokens && tokens[0] && tokens[1] === "" || tokens[1] == null) {
|
391
|
+
var rawValue = NumberFormatter.prototype.toRaw.call(this, tokens[0]);
|
392
|
+
if (_.isUndefined(rawValue)) return rawValue;
|
393
|
+
return rawValue / this.multiplier;
|
394
|
+
}
|
395
|
+
}
|
396
|
+
|
397
|
+
});
|
398
|
+
|
309
399
|
/**
|
310
400
|
Formatter to converts between various datetime formats.
|
311
401
|
|
@@ -320,8 +410,7 @@ _.extend(NumberFormatter.prototype, {
|
|
320
410
|
@throws {Error} If both `includeDate` and `includeTime` are false.
|
321
411
|
*/
|
322
412
|
var DatetimeFormatter = Backgrid.DatetimeFormatter = function (options) {
|
323
|
-
|
324
|
-
_.extend(this, this.defaults, options);
|
413
|
+
_.extend(this, this.defaults, options || {});
|
325
414
|
|
326
415
|
if (!this.includeDate && !this.includeTime) {
|
327
416
|
throw new Error("Either includeDate or includeTime must be true");
|
@@ -355,6 +444,8 @@ _.extend(DatetimeFormatter.prototype, {
|
|
355
444
|
ISO_SPLITTER_RE: /T|Z| +/,
|
356
445
|
|
357
446
|
_convert: function (data, validate) {
|
447
|
+
if ((data + '').trim() === '') return null;
|
448
|
+
|
358
449
|
var date, time = null;
|
359
450
|
if (_.isNumber(data)) {
|
360
451
|
var jsDate = new Date(data);
|
@@ -413,10 +504,11 @@ _.extend(DatetimeFormatter.prototype, {
|
|
413
504
|
|
414
505
|
@member Backgrid.DatetimeFormatter
|
415
506
|
@param {string} rawData
|
507
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
416
508
|
@return {string|null|undefined} ISO-8601 string in UTC. Null and undefined
|
417
509
|
values are returned as is.
|
418
510
|
*/
|
419
|
-
fromRaw: function (rawData) {
|
511
|
+
fromRaw: function (rawData, model) {
|
420
512
|
if (_.isNull(rawData) || _.isUndefined(rawData)) return '';
|
421
513
|
return this._convert(rawData);
|
422
514
|
},
|
@@ -430,12 +522,13 @@ _.extend(DatetimeFormatter.prototype, {
|
|
430
522
|
|
431
523
|
@member Backgrid.DatetimeFormatter
|
432
524
|
@param {string} formattedData
|
525
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
433
526
|
@return {string|undefined} ISO-8601 string in UTC. Undefined if a date is
|
434
527
|
found when `includeDate` is false, or a time is found when `includeTime` is
|
435
528
|
false, or if `includeDate` is true and a date is not found, or if
|
436
529
|
`includeTime` is true and a time is not found.
|
437
530
|
*/
|
438
|
-
toRaw: function (formattedData) {
|
531
|
+
toRaw: function (formattedData, model) {
|
439
532
|
return this._convert(formattedData, true);
|
440
533
|
}
|
441
534
|
|
@@ -458,9 +551,10 @@ _.extend(StringFormatter.prototype, {
|
|
458
551
|
|
459
552
|
@member Backgrid.StringFormatter
|
460
553
|
@param {*} rawValue
|
554
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
461
555
|
@return {string}
|
462
556
|
*/
|
463
|
-
fromRaw: function (rawValue) {
|
557
|
+
fromRaw: function (rawValue, model) {
|
464
558
|
if (_.isUndefined(rawValue) || _.isNull(rawValue)) return '';
|
465
559
|
return rawValue + '';
|
466
560
|
}
|
@@ -483,9 +577,10 @@ _.extend(EmailFormatter.prototype, {
|
|
483
577
|
|
484
578
|
@member Backgrid.EmailFormatter
|
485
579
|
@param {*} formattedData
|
580
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
486
581
|
@return {string|undefined}
|
487
582
|
*/
|
488
|
-
toRaw: function (formattedData) {
|
583
|
+
toRaw: function (formattedData, model) {
|
489
584
|
var parts = formattedData.trim().split("@");
|
490
585
|
if (parts.length === 2 && _.all(parts)) {
|
491
586
|
return formattedData;
|
@@ -496,6 +591,11 @@ _.extend(EmailFormatter.prototype, {
|
|
496
591
|
/**
|
497
592
|
Formatter for SelectCell.
|
498
593
|
|
594
|
+
If the type of a model value is not a string, it is expected that a subclass
|
595
|
+
of this formatter is provided to the SelectCell, with #toRaw overridden to
|
596
|
+
convert the string value returned from the DOM back to whatever value is
|
597
|
+
expected in the model.
|
598
|
+
|
499
599
|
@class Backgrid.SelectFormatter
|
500
600
|
@extends Backgrid.CellFormatter
|
501
601
|
@constructor
|
@@ -509,9 +609,10 @@ _.extend(SelectFormatter.prototype, {
|
|
509
609
|
|
510
610
|
@member Backgrid.SelectFormatter
|
511
611
|
@param {*} rawValue
|
612
|
+
@param {Backbone.Model} model Used for more complicated formatting
|
512
613
|
@return {Array.<*>}
|
513
614
|
*/
|
514
|
-
fromRaw: function (rawValue) {
|
615
|
+
fromRaw: function (rawValue, model) {
|
515
616
|
return _.isArray(rawValue) ? rawValue : rawValue != null ? [rawValue] : [];
|
516
617
|
}
|
517
618
|
});
|
@@ -521,7 +622,7 @@ _.extend(SelectFormatter.prototype, {
|
|
521
622
|
http://github.com/wyuenho/backgrid
|
522
623
|
|
523
624
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
524
|
-
Licensed under the MIT
|
625
|
+
Licensed under the MIT license.
|
525
626
|
*/
|
526
627
|
|
527
628
|
/**
|
@@ -546,7 +647,6 @@ var CellEditor = Backgrid.CellEditor = Backbone.View.extend({
|
|
546
647
|
`model` or `column` are undefined.
|
547
648
|
*/
|
548
649
|
initialize: function (options) {
|
549
|
-
Backgrid.requireOptions(options, ["formatter", "column", "model"]);
|
550
650
|
this.formatter = options.formatter;
|
551
651
|
this.column = options.column;
|
552
652
|
if (!(this.column instanceof Column)) {
|
@@ -605,7 +705,7 @@ var InputCellEditor = Backgrid.InputCellEditor = CellEditor.extend({
|
|
605
705
|
@param {string} [options.placeholder]
|
606
706
|
*/
|
607
707
|
initialize: function (options) {
|
608
|
-
|
708
|
+
InputCellEditor.__super__.initialize.apply(this, arguments);
|
609
709
|
|
610
710
|
if (options.placeholder) {
|
611
711
|
this.$el.attr("placeholder", options.placeholder);
|
@@ -617,7 +717,8 @@ var InputCellEditor = Backgrid.InputCellEditor = CellEditor.extend({
|
|
617
717
|
exists.
|
618
718
|
*/
|
619
719
|
render: function () {
|
620
|
-
this
|
720
|
+
var model = this.model;
|
721
|
+
this.$el.val(this.formatter.fromRaw(model.get(this.column.get("name")), model));
|
621
722
|
return this;
|
622
723
|
},
|
623
724
|
|
@@ -654,7 +755,7 @@ var InputCellEditor = Backgrid.InputCellEditor = CellEditor.extend({
|
|
654
755
|
e.stopPropagation();
|
655
756
|
|
656
757
|
var val = this.$el.val();
|
657
|
-
var newValue = formatter.toRaw(val);
|
758
|
+
var newValue = formatter.toRaw(val, model);
|
658
759
|
if (_.isUndefined(newValue)) {
|
659
760
|
model.trigger("backgrid:error", model, column, val);
|
660
761
|
}
|
@@ -703,9 +804,9 @@ var Cell = Backgrid.Cell = Backbone.View.extend({
|
|
703
804
|
tagName: "td",
|
704
805
|
|
705
806
|
/**
|
706
|
-
@property {Backgrid.CellFormatter|Object|string} [formatter=
|
807
|
+
@property {Backgrid.CellFormatter|Object|string} [formatter=CellFormatter]
|
707
808
|
*/
|
708
|
-
formatter:
|
809
|
+
formatter: CellFormatter,
|
709
810
|
|
710
811
|
/**
|
711
812
|
@property {Backgrid.CellEditor} [editor=Backgrid.InputCellEditor] The
|
@@ -732,17 +833,43 @@ var Cell = Backgrid.Cell = Backbone.View.extend({
|
|
732
833
|
said name cannot be found in the Backgrid module.
|
733
834
|
*/
|
734
835
|
initialize: function (options) {
|
735
|
-
Backgrid.requireOptions(options, ["model", "column"]);
|
736
836
|
this.column = options.column;
|
737
837
|
if (!(this.column instanceof Column)) {
|
738
838
|
this.column = new Column(this.column);
|
739
839
|
}
|
740
|
-
|
840
|
+
|
841
|
+
var column = this.column, model = this.model, $el = this.$el;
|
842
|
+
|
843
|
+
var formatter = Backgrid.resolveNameToClass(column.get("formatter") ||
|
844
|
+
this.formatter, "Formatter");
|
845
|
+
|
846
|
+
if (!_.isFunction(formatter.fromRaw) && !_.isFunction(formatter.toRaw)) {
|
847
|
+
formatter = new formatter();
|
848
|
+
}
|
849
|
+
|
850
|
+
this.formatter = formatter;
|
851
|
+
|
741
852
|
this.editor = Backgrid.resolveNameToClass(this.editor, "CellEditor");
|
742
|
-
|
743
|
-
|
853
|
+
|
854
|
+
this.listenTo(model, "change:" + column.get("name"), function () {
|
855
|
+
if (!$el.hasClass("editor")) this.render();
|
744
856
|
});
|
745
|
-
|
857
|
+
|
858
|
+
this.listenTo(model, "backgrid:error", this.renderError);
|
859
|
+
|
860
|
+
this.listenTo(column, "change:editable change:sortable change:renderable",
|
861
|
+
function (column) {
|
862
|
+
var changed = column.changedAttributes();
|
863
|
+
for (var key in changed) {
|
864
|
+
if (changed.hasOwnProperty(key)) {
|
865
|
+
$el.toggleClass(key, changed[key]);
|
866
|
+
}
|
867
|
+
}
|
868
|
+
});
|
869
|
+
|
870
|
+
if (Backgrid.callByNeed(column.editable(), column, model)) $el.addClass("editable");
|
871
|
+
if (Backgrid.callByNeed(column.sortable(), column, model)) $el.addClass("sortable");
|
872
|
+
if (Backgrid.callByNeed(column.renderable(), column, model)) $el.addClass("renderable");
|
746
873
|
},
|
747
874
|
|
748
875
|
/**
|
@@ -751,7 +878,8 @@ var Cell = Backgrid.Cell = Backbone.View.extend({
|
|
751
878
|
*/
|
752
879
|
render: function () {
|
753
880
|
this.$el.empty();
|
754
|
-
this
|
881
|
+
var model = this.model;
|
882
|
+
this.$el.text(this.formatter.fromRaw(model.get(this.column.get("name")), model));
|
755
883
|
this.delegateEvents();
|
756
884
|
return this;
|
757
885
|
},
|
@@ -779,7 +907,8 @@ var Cell = Backgrid.Cell = Backbone.View.extend({
|
|
779
907
|
var model = this.model;
|
780
908
|
var column = this.column;
|
781
909
|
|
782
|
-
|
910
|
+
var editable = Backgrid.callByNeed(column.editable(), column, model);
|
911
|
+
if (editable) {
|
783
912
|
|
784
913
|
this.currentEditor = new this.editor({
|
785
914
|
column: this.column,
|
@@ -828,10 +957,10 @@ var Cell = Backgrid.Cell = Backbone.View.extend({
|
|
828
957
|
*/
|
829
958
|
remove: function () {
|
830
959
|
if (this.currentEditor) {
|
831
|
-
this.currentEditor.remove.apply(this, arguments);
|
960
|
+
this.currentEditor.remove.apply(this.currentEditor, arguments);
|
832
961
|
delete this.currentEditor;
|
833
962
|
}
|
834
|
-
return
|
963
|
+
return Cell.__super__.remove.apply(this, arguments);
|
835
964
|
}
|
836
965
|
|
837
966
|
});
|
@@ -847,7 +976,7 @@ var StringCell = Backgrid.StringCell = Cell.extend({
|
|
847
976
|
/** @property */
|
848
977
|
className: "string-cell",
|
849
978
|
|
850
|
-
formatter:
|
979
|
+
formatter: StringFormatter
|
851
980
|
|
852
981
|
});
|
853
982
|
|
@@ -867,14 +996,33 @@ var UriCell = Backgrid.UriCell = Cell.extend({
|
|
867
996
|
/** @property */
|
868
997
|
className: "uri-cell",
|
869
998
|
|
999
|
+
/**
|
1000
|
+
@property {string} [title] The title attribute of the generated anchor. It
|
1001
|
+
uses the display value formatted by the `formatter.fromRaw` by default.
|
1002
|
+
*/
|
1003
|
+
title: null,
|
1004
|
+
|
1005
|
+
/**
|
1006
|
+
@property {string} [target="_blank"] The target attribute of the generated
|
1007
|
+
anchor.
|
1008
|
+
*/
|
1009
|
+
target: "_blank",
|
1010
|
+
|
1011
|
+
initialize: function (options) {
|
1012
|
+
UriCell.__super__.initialize.apply(this, arguments);
|
1013
|
+
this.title = options.title || this.title;
|
1014
|
+
this.target = options.target || this.target;
|
1015
|
+
},
|
1016
|
+
|
870
1017
|
render: function () {
|
871
1018
|
this.$el.empty();
|
872
|
-
var
|
1019
|
+
var rawValue = this.model.get(this.column.get("name"));
|
1020
|
+
var formattedValue = this.formatter.fromRaw(rawValue, this.model);
|
873
1021
|
this.$el.append($("<a>", {
|
874
1022
|
tabIndex: -1,
|
875
|
-
href:
|
876
|
-
title: formattedValue,
|
877
|
-
target:
|
1023
|
+
href: rawValue,
|
1024
|
+
title: this.title || formattedValue,
|
1025
|
+
target: this.target
|
878
1026
|
}).text(formattedValue));
|
879
1027
|
this.delegateEvents();
|
880
1028
|
return this;
|
@@ -895,11 +1043,12 @@ var EmailCell = Backgrid.EmailCell = StringCell.extend({
|
|
895
1043
|
/** @property */
|
896
1044
|
className: "email-cell",
|
897
1045
|
|
898
|
-
formatter:
|
1046
|
+
formatter: EmailFormatter,
|
899
1047
|
|
900
1048
|
render: function () {
|
901
1049
|
this.$el.empty();
|
902
|
-
var
|
1050
|
+
var model = this.model;
|
1051
|
+
var formattedValue = this.formatter.fromRaw(model.get(this.column.get("name")), model);
|
903
1052
|
this.$el.append($("<a>", {
|
904
1053
|
tabIndex: -1,
|
905
1054
|
href: "mailto:" + formattedValue,
|
@@ -945,12 +1094,11 @@ var NumberCell = Backgrid.NumberCell = Cell.extend({
|
|
945
1094
|
@param {Backgrid.Column} options.column
|
946
1095
|
*/
|
947
1096
|
initialize: function (options) {
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
});
|
1097
|
+
NumberCell.__super__.initialize.apply(this, arguments);
|
1098
|
+
var formatter = this.formatter;
|
1099
|
+
formatter.decimals = this.decimals;
|
1100
|
+
formatter.decimalSeparator = this.decimalSeparator;
|
1101
|
+
formatter.orderSeparator = this.orderSeparator;
|
954
1102
|
}
|
955
1103
|
|
956
1104
|
});
|
@@ -974,6 +1122,43 @@ var IntegerCell = Backgrid.IntegerCell = NumberCell.extend({
|
|
974
1122
|
decimals: 0
|
975
1123
|
});
|
976
1124
|
|
1125
|
+
/**
|
1126
|
+
A PercentCell is another Backgrid.NumberCell that takes a floating number,
|
1127
|
+
optionally multiplied by a multiplier and display it as a percentage.
|
1128
|
+
|
1129
|
+
@class Backgrid.PercentCell
|
1130
|
+
@extends Backgrid.NumberCell
|
1131
|
+
*/
|
1132
|
+
var PercentCell = Backgrid.PercentCell = NumberCell.extend({
|
1133
|
+
|
1134
|
+
/** @property */
|
1135
|
+
className: "percent-cell",
|
1136
|
+
|
1137
|
+
/** @property {number} [multiplier=1] */
|
1138
|
+
multiplier: PercentFormatter.prototype.defaults.multiplier,
|
1139
|
+
|
1140
|
+
/** @property {string} [symbol='%'] */
|
1141
|
+
symbol: PercentFormatter.prototype.defaults.symbol,
|
1142
|
+
|
1143
|
+
/** @property {Backgrid.CellFormatter} [formatter=Backgrid.PercentFormatter] */
|
1144
|
+
formatter: PercentFormatter,
|
1145
|
+
|
1146
|
+
/**
|
1147
|
+
Initializes this cell and the percent formatter.
|
1148
|
+
|
1149
|
+
@param {Object} options
|
1150
|
+
@param {Backbone.Model} options.model
|
1151
|
+
@param {Backgrid.Column} options.column
|
1152
|
+
*/
|
1153
|
+
initialize: function () {
|
1154
|
+
PercentCell.__super__.initialize.apply(this, arguments);
|
1155
|
+
var formatter = this.formatter;
|
1156
|
+
formatter.multiplier = this.multiplier;
|
1157
|
+
formatter.symbol = this.symbol;
|
1158
|
+
}
|
1159
|
+
|
1160
|
+
});
|
1161
|
+
|
977
1162
|
/**
|
978
1163
|
DatetimeCell is a basic cell that accepts datetime string values in RFC-2822
|
979
1164
|
or W3C's subset of ISO-8601 and displays them in ISO-8601 format. For a much
|
@@ -1019,12 +1204,11 @@ var DatetimeCell = Backgrid.DatetimeCell = Cell.extend({
|
|
1019
1204
|
@param {Backgrid.Column} options.column
|
1020
1205
|
*/
|
1021
1206
|
initialize: function (options) {
|
1022
|
-
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
});
|
1207
|
+
DatetimeCell.__super__.initialize.apply(this, arguments);
|
1208
|
+
var formatter = this.formatter;
|
1209
|
+
formatter.includeDate = this.includeDate;
|
1210
|
+
formatter.includeTime = this.includeTime;
|
1211
|
+
formatter.includeMilli = this.includeMilli;
|
1028
1212
|
|
1029
1213
|
var placeholder = this.includeDate ? "YYYY-MM-DD" : "";
|
1030
1214
|
placeholder += (this.includeDate && this.includeTime) ? "T" : "";
|
@@ -1107,7 +1291,8 @@ var BooleanCellEditor = Backgrid.BooleanCellEditor = CellEditor.extend({
|
|
1107
1291
|
uncheck otherwise.
|
1108
1292
|
*/
|
1109
1293
|
render: function () {
|
1110
|
-
var
|
1294
|
+
var model = this.model;
|
1295
|
+
var val = this.formatter.fromRaw(model.get(this.column.get("name")), model);
|
1111
1296
|
this.$el.prop("checked", val);
|
1112
1297
|
return this;
|
1113
1298
|
},
|
@@ -1145,12 +1330,12 @@ var BooleanCellEditor = Backgrid.BooleanCellEditor = CellEditor.extend({
|
|
1145
1330
|
command.moveDown()) {
|
1146
1331
|
e.preventDefault();
|
1147
1332
|
e.stopPropagation();
|
1148
|
-
var val = formatter.toRaw($el.prop("checked"));
|
1333
|
+
var val = formatter.toRaw($el.prop("checked"), model);
|
1149
1334
|
model.set(column.get("name"), val);
|
1150
1335
|
model.trigger("backgrid:edited", model, column, command);
|
1151
1336
|
}
|
1152
1337
|
else if (e.type == "change") {
|
1153
|
-
var val = formatter.toRaw($el.prop("checked"));
|
1338
|
+
var val = formatter.toRaw($el.prop("checked"), model);
|
1154
1339
|
model.set(column.get("name"), val);
|
1155
1340
|
$el.focus();
|
1156
1341
|
}
|
@@ -1184,10 +1369,13 @@ var BooleanCell = Backgrid.BooleanCell = Cell.extend({
|
|
1184
1369
|
*/
|
1185
1370
|
render: function () {
|
1186
1371
|
this.$el.empty();
|
1372
|
+
var model = this.model, column = this.column;
|
1373
|
+
var editable = Backgrid.callByNeed(column.editable(), column, model);
|
1187
1374
|
this.$el.append($("<input>", {
|
1188
1375
|
tabIndex: -1,
|
1189
1376
|
type: "checkbox",
|
1190
|
-
checked: this.formatter.fromRaw(
|
1377
|
+
checked: this.formatter.fromRaw(model.get(column.get("name")), model),
|
1378
|
+
disabled: !editable
|
1191
1379
|
}));
|
1192
1380
|
this.delegateEvents();
|
1193
1381
|
return this;
|
@@ -1214,10 +1402,11 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({
|
|
1214
1402
|
},
|
1215
1403
|
|
1216
1404
|
/** @property {function(Object, ?Object=): string} template */
|
1217
|
-
template: _.template('<option value="<%- value %>" <%= selected ? \'selected="selected"\' : "" %>><%- text %></option>'),
|
1405
|
+
template: _.template('<option value="<%- value %>" <%= selected ? \'selected="selected"\' : "" %>><%- text %></option>', null, {variable: null}),
|
1218
1406
|
|
1219
1407
|
setOptionValues: function (optionValues) {
|
1220
1408
|
this.optionValues = optionValues;
|
1409
|
+
this.optionValues = _.result(this, "optionValues");
|
1221
1410
|
},
|
1222
1411
|
|
1223
1412
|
setMultiple: function (multiple) {
|
@@ -1231,7 +1420,7 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({
|
|
1231
1420
|
options = options + this.template({
|
1232
1421
|
text: nvps[i][0],
|
1233
1422
|
value: nvps[i][1],
|
1234
|
-
selected:
|
1423
|
+
selected: _.indexOf(selectedValues, nvps[i][1]) > -1
|
1235
1424
|
});
|
1236
1425
|
}
|
1237
1426
|
return options;
|
@@ -1248,9 +1437,10 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({
|
|
1248
1437
|
this.$el.empty();
|
1249
1438
|
|
1250
1439
|
var optionValues = _.result(this, "optionValues");
|
1251
|
-
var
|
1440
|
+
var model = this.model;
|
1441
|
+
var selectedValues = this.formatter.fromRaw(model.get(this.column.get("name")), model);
|
1252
1442
|
|
1253
|
-
if (!_.isArray(optionValues)) throw TypeError("optionValues must be an array");
|
1443
|
+
if (!_.isArray(optionValues)) throw new TypeError("optionValues must be an array");
|
1254
1444
|
|
1255
1445
|
var optionValue = null;
|
1256
1446
|
var optionText = null;
|
@@ -1268,17 +1458,17 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({
|
|
1268
1458
|
this.$el.append(this.template({
|
1269
1459
|
text: optionText,
|
1270
1460
|
value: optionValue,
|
1271
|
-
selected:
|
1461
|
+
selected: _.indexOf(selectedValues, optionValue) > -1
|
1272
1462
|
}));
|
1273
1463
|
}
|
1274
1464
|
else if (_.isObject(optionValue)) {
|
1275
1465
|
optgroupName = optionValue.name;
|
1276
1466
|
optgroup = $("<optgroup></optgroup>", { label: optgroupName });
|
1277
|
-
optgroup.append(this._renderOptions(optionValue.values, selectedValues));
|
1467
|
+
optgroup.append(this._renderOptions.call(this, optionValue.values, selectedValues));
|
1278
1468
|
this.$el.append(optgroup);
|
1279
1469
|
}
|
1280
1470
|
else {
|
1281
|
-
throw TypeError("optionValues elements must be a name-value pair or an object hash of { name: 'optgroup label', value: [option name-value pairs] }");
|
1471
|
+
throw new TypeError("optionValues elements must be a name-value pair or an object hash of { name: 'optgroup label', value: [option name-value pairs] }");
|
1282
1472
|
}
|
1283
1473
|
}
|
1284
1474
|
|
@@ -1288,14 +1478,12 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({
|
|
1288
1478
|
},
|
1289
1479
|
|
1290
1480
|
/**
|
1291
|
-
Saves the value of the selected option to the model attribute.
|
1292
|
-
`backgrid:edited` Backbone event from the model.
|
1481
|
+
Saves the value of the selected option to the model attribute.
|
1293
1482
|
*/
|
1294
1483
|
save: function (e) {
|
1295
1484
|
var model = this.model;
|
1296
1485
|
var column = this.column;
|
1297
|
-
model.set(column.get("name"), this.formatter.toRaw(this.$el.val()));
|
1298
|
-
model.trigger("backgrid:edited", model, column, new Command(e));
|
1486
|
+
model.set(column.get("name"), this.formatter.toRaw(this.$el.val(), model));
|
1299
1487
|
},
|
1300
1488
|
|
1301
1489
|
/**
|
@@ -1314,9 +1502,7 @@ var SelectCellEditor = Backgrid.SelectCellEditor = CellEditor.extend({
|
|
1314
1502
|
command.moveUp() || command.moveDown() || e.type == "blur") {
|
1315
1503
|
e.preventDefault();
|
1316
1504
|
e.stopPropagation();
|
1317
|
-
|
1318
|
-
model.set(column.get("name"), this.formatter.toRaw(this.$el.val()));
|
1319
|
-
}
|
1505
|
+
this.save(e);
|
1320
1506
|
model.trigger("backgrid:edited", model, column, new Command(e));
|
1321
1507
|
}
|
1322
1508
|
}
|
@@ -1367,7 +1553,7 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({
|
|
1367
1553
|
multiple: false,
|
1368
1554
|
|
1369
1555
|
/** @property */
|
1370
|
-
formatter:
|
1556
|
+
formatter: SelectFormatter,
|
1371
1557
|
|
1372
1558
|
/**
|
1373
1559
|
@property {Array.<Array>|Array.<{name: string, values: Array.<Array>}>} optionValues
|
@@ -1387,8 +1573,7 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({
|
|
1387
1573
|
@throws {TypeError} If `optionsValues` is undefined.
|
1388
1574
|
*/
|
1389
1575
|
initialize: function (options) {
|
1390
|
-
|
1391
|
-
Backgrid.requireOptions(this, ["optionValues"]);
|
1576
|
+
SelectCell.__super__.initialize.apply(this, arguments);
|
1392
1577
|
this.listenTo(this.model, "backgrid:edit", function (model, column, cell, editor) {
|
1393
1578
|
if (column.get("name") == this.column.get("name")) {
|
1394
1579
|
editor.setOptionValues(this.optionValues);
|
@@ -1405,8 +1590,9 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({
|
|
1405
1590
|
render: function () {
|
1406
1591
|
this.$el.empty();
|
1407
1592
|
|
1408
|
-
var optionValues = this
|
1409
|
-
var
|
1593
|
+
var optionValues = _.result(this, "optionValues");
|
1594
|
+
var model = this.model;
|
1595
|
+
var rawData = this.formatter.fromRaw(model.get(this.column.get("name")), model);
|
1410
1596
|
|
1411
1597
|
var selectedText = [];
|
1412
1598
|
|
@@ -1445,7 +1631,7 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({
|
|
1445
1631
|
}
|
1446
1632
|
catch (ex) {
|
1447
1633
|
if (ex instanceof TypeError) {
|
1448
|
-
throw TypeError("'optionValues' must be of type {Array.<Array>|Array.<{name: string, values: Array.<Array>}>}");
|
1634
|
+
throw new TypeError("'optionValues' must be of type {Array.<Array>|Array.<{name: string, values: Array.<Array>}>}");
|
1449
1635
|
}
|
1450
1636
|
throw ex;
|
1451
1637
|
}
|
@@ -1456,12 +1642,13 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({
|
|
1456
1642
|
}
|
1457
1643
|
|
1458
1644
|
});
|
1645
|
+
|
1459
1646
|
/*
|
1460
1647
|
backgrid
|
1461
1648
|
http://github.com/wyuenho/backgrid
|
1462
1649
|
|
1463
1650
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
1464
|
-
Licensed under the MIT
|
1651
|
+
Licensed under the MIT license.
|
1465
1652
|
*/
|
1466
1653
|
|
1467
1654
|
/**
|
@@ -1473,9 +1660,77 @@ var SelectCell = Backgrid.SelectCell = Cell.extend({
|
|
1473
1660
|
|
1474
1661
|
@class Backgrid.Column
|
1475
1662
|
@extends Backbone.Model
|
1476
|
-
|
1663
|
+
*/
|
1477
1664
|
var Column = Backgrid.Column = Backbone.Model.extend({
|
1478
1665
|
|
1666
|
+
/**
|
1667
|
+
@cfg {Object} defaults Column defaults. To override any of these default
|
1668
|
+
values, you can either change the prototype directly to override
|
1669
|
+
Column.defaults globally or extend Column and supply the custom class to
|
1670
|
+
Backgrid.Grid:
|
1671
|
+
|
1672
|
+
// Override Column defaults globally
|
1673
|
+
Column.prototype.defaults.sortable = false;
|
1674
|
+
|
1675
|
+
// Override Column defaults locally
|
1676
|
+
var MyColumn = Column.extend({
|
1677
|
+
defaults: _.defaults({
|
1678
|
+
editable: false
|
1679
|
+
}, Column.prototype.defaults)
|
1680
|
+
});
|
1681
|
+
|
1682
|
+
var grid = new Backgrid.Grid(columns: new Columns([{...}, {...}], {
|
1683
|
+
model: MyColumn
|
1684
|
+
}));
|
1685
|
+
|
1686
|
+
@cfg {string} [defaults.name] The default name of the model attribute.
|
1687
|
+
|
1688
|
+
@cfg {string} [defaults.label] The default label to show in the header.
|
1689
|
+
|
1690
|
+
@cfg {string|Backgrid.Cell} [defaults.cell] The default cell type. If this
|
1691
|
+
is a string, the capitalized form will be used to look up a cell class in
|
1692
|
+
Backbone, i.e.: string => StringCell. If a Cell subclass is supplied, it is
|
1693
|
+
initialized with a hash of parameters. If a Cell instance is supplied, it
|
1694
|
+
is used directly.
|
1695
|
+
|
1696
|
+
@cfg {string|Backgrid.HeaderCell} [defaults.headerCell] The default header
|
1697
|
+
cell type.
|
1698
|
+
|
1699
|
+
@cfg {boolean|string|function(): boolean} [defaults.sortable=true] Whether
|
1700
|
+
this column is sortable. If the value is a string, a method will the same
|
1701
|
+
name will be looked up from the column instance to determine whether the
|
1702
|
+
column should be sortable. The method's signature must be `function
|
1703
|
+
(Backgrid.Column, Backbone.Model): boolean`.
|
1704
|
+
|
1705
|
+
@cfg {boolean|string|function(): boolean} [defaults.editable=true] Whether
|
1706
|
+
this column is editable. If the value is a string, a method will the same
|
1707
|
+
name will be looked up from the column instance to determine whether the
|
1708
|
+
column should be editable. The method's signature must be `function
|
1709
|
+
(Backgrid.Column, Backbone.Model): boolean`.
|
1710
|
+
|
1711
|
+
@cfg {boolean|string|function(): boolean} [defaults.renderable=true]
|
1712
|
+
Whether this column is renderable. If the value is a string, a method will
|
1713
|
+
the same name will be looked up from the column instance to determine
|
1714
|
+
whether the column should be renderable. The method's signature must be
|
1715
|
+
`function (Backrid.Column, Backbone.Model): boolean`.
|
1716
|
+
|
1717
|
+
@cfg {Backgrid.CellFormatter | Object | string} [defaults.formatter] The
|
1718
|
+
formatter to use to convert between raw model values and user input.
|
1719
|
+
|
1720
|
+
@cfg {"toggle"|"cycle"} [defaults.sortType="cycle"] Whether sorting will
|
1721
|
+
toggle between ascending and descending order, or cycle between insertion
|
1722
|
+
order, ascending and descending order.
|
1723
|
+
|
1724
|
+
@cfg {(function(Backbone.Model, string): *) | string} [defaults.sortValue]
|
1725
|
+
The function to use to extract a value from the model for comparison during
|
1726
|
+
sorting. If this value is a string, a method with the same name will be
|
1727
|
+
looked up from the column instance.
|
1728
|
+
|
1729
|
+
@cfg {"ascending"|"descending"|null} [defaults.direction=null] The initial
|
1730
|
+
sorting direction for this column. The default is ordered by
|
1731
|
+
Backbone.Model.cid, which usually means the collection is ordered by
|
1732
|
+
insertion order.
|
1733
|
+
*/
|
1479
1734
|
defaults: {
|
1480
1735
|
name: undefined,
|
1481
1736
|
label: undefined,
|
@@ -1483,6 +1738,9 @@ var Column = Backgrid.Column = Backbone.Model.extend({
|
|
1483
1738
|
editable: true,
|
1484
1739
|
renderable: true,
|
1485
1740
|
formatter: undefined,
|
1741
|
+
sortType: "cycle",
|
1742
|
+
sortValue: undefined,
|
1743
|
+
direction: null,
|
1486
1744
|
cell: undefined,
|
1487
1745
|
headerCell: undefined
|
1488
1746
|
},
|
@@ -1490,42 +1748,105 @@ var Column = Backgrid.Column = Backbone.Model.extend({
|
|
1490
1748
|
/**
|
1491
1749
|
Initializes this Column instance.
|
1492
1750
|
|
1493
|
-
@param {Object} attrs
|
1494
|
-
|
1495
|
-
@param {string
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
|
1500
|
-
|
1501
|
-
@param {string} [attrs.label]
|
1502
|
-
|
1503
|
-
@param {
|
1504
|
-
|
1505
|
-
@param {
|
1506
|
-
|
1751
|
+
@param {Object} attrs
|
1752
|
+
|
1753
|
+
@param {string} attrs.name The model attribute this column is responsible
|
1754
|
+
for.
|
1755
|
+
|
1756
|
+
@param {string|Backgrid.Cell} attrs.cell The cell type to use to render
|
1757
|
+
this column.
|
1758
|
+
|
1759
|
+
@param {string} [attrs.label]
|
1760
|
+
|
1761
|
+
@param {string|Backgrid.HeaderCell} [attrs.headerCell]
|
1762
|
+
|
1763
|
+
@param {boolean|string|function(): boolean} [attrs.sortable=true]
|
1764
|
+
|
1765
|
+
@param {boolean|string|function(): boolean} [attrs.editable=true]
|
1766
|
+
|
1767
|
+
@param {boolean|string|function(): boolean} [attrs.renderable=true]
|
1768
|
+
|
1769
|
+
@param {Backgrid.CellFormatter | Object | string} [attrs.formatter]
|
1770
|
+
|
1771
|
+
@param {"toggle"|"cycle"} [attrs.sortType="cycle"]
|
1772
|
+
|
1773
|
+
@param {(function(Backbone.Model, string): *) | string} [attrs.sortValue]
|
1507
1774
|
|
1508
1775
|
@throws {TypeError} If attrs.cell or attrs.options are not supplied.
|
1509
|
-
|
1776
|
+
|
1777
|
+
@throws {ReferenceError} If formatter is a string but a formatter class of
|
1510
1778
|
said name cannot be found in the Backgrid module.
|
1511
1779
|
|
1512
1780
|
See:
|
1513
1781
|
|
1782
|
+
- Backgrid.Column.defaults
|
1514
1783
|
- Backgrid.Cell
|
1515
1784
|
- Backgrid.CellFormatter
|
1516
1785
|
*/
|
1517
|
-
initialize: function (
|
1518
|
-
Backgrid.requireOptions(attrs, ["cell", "name"]);
|
1519
|
-
|
1786
|
+
initialize: function () {
|
1520
1787
|
if (!this.has("label")) {
|
1521
1788
|
this.set({ label: this.get("name") }, { silent: true });
|
1522
1789
|
}
|
1523
1790
|
|
1524
1791
|
var headerCell = Backgrid.resolveNameToClass(this.get("headerCell"), "HeaderCell");
|
1792
|
+
|
1525
1793
|
var cell = Backgrid.resolveNameToClass(this.get("cell"), "Cell");
|
1526
|
-
|
1794
|
+
|
1795
|
+
this.set({cell: cell, headerCell: headerCell}, { silent: true });
|
1796
|
+
},
|
1797
|
+
|
1798
|
+
/**
|
1799
|
+
Returns an appropriate value extraction function from a model for sorting.
|
1800
|
+
|
1801
|
+
If the column model contains an attribute `sortValue`, if it is a string, a
|
1802
|
+
method from the column instance identifified by the `sortValue` string is
|
1803
|
+
returned. If it is a function, it it returned as is. If `sortValue` isn't
|
1804
|
+
found from the column model's attributes, a default value extraction
|
1805
|
+
function is returned which will compare according to the natural order of
|
1806
|
+
the value's type.
|
1807
|
+
|
1808
|
+
@return {function(Backbone.Model, string): *}
|
1809
|
+
*/
|
1810
|
+
sortValue: function () {
|
1811
|
+
var sortValue = this.get("sortValue");
|
1812
|
+
if (_.isString(sortValue)) return this[sortValue];
|
1813
|
+
else if (_.isFunction(sortValue)) return sortValue;
|
1814
|
+
|
1815
|
+
return function (model, colName) {
|
1816
|
+
return model.get(colName);
|
1817
|
+
};
|
1527
1818
|
}
|
1528
1819
|
|
1820
|
+
/**
|
1821
|
+
@member Backgrid.Column
|
1822
|
+
@protected
|
1823
|
+
@method sortable
|
1824
|
+
@return {function(Backgrid.Column, Backbone.Model): boolean | boolean}
|
1825
|
+
*/
|
1826
|
+
|
1827
|
+
/**
|
1828
|
+
@member Backgrid.Column
|
1829
|
+
@protected
|
1830
|
+
@method editable
|
1831
|
+
@return {function(Backgrid.Column, Backbone.Model): boolean | boolean}
|
1832
|
+
*/
|
1833
|
+
|
1834
|
+
/**
|
1835
|
+
@member Backgrid.Column
|
1836
|
+
@protected
|
1837
|
+
@method renderable
|
1838
|
+
@return {function(Backgrid.Column, Backbone.Model): boolean | boolean}
|
1839
|
+
*/
|
1840
|
+
});
|
1841
|
+
|
1842
|
+
_.each(["sortable", "renderable", "editable"], function (key) {
|
1843
|
+
Column.prototype[key] = function () {
|
1844
|
+
var value = this.get(key);
|
1845
|
+
if (_.isString(value)) return this[value];
|
1846
|
+
else if (_.isFunction(value)) return value;
|
1847
|
+
|
1848
|
+
return !!value;
|
1849
|
+
};
|
1529
1850
|
});
|
1530
1851
|
|
1531
1852
|
/**
|
@@ -1541,12 +1862,13 @@ var Columns = Backgrid.Columns = Backbone.Collection.extend({
|
|
1541
1862
|
*/
|
1542
1863
|
model: Column
|
1543
1864
|
});
|
1865
|
+
|
1544
1866
|
/*
|
1545
1867
|
backgrid
|
1546
1868
|
http://github.com/wyuenho/backgrid
|
1547
1869
|
|
1548
1870
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
1549
|
-
Licensed under the MIT
|
1871
|
+
Licensed under the MIT license.
|
1550
1872
|
*/
|
1551
1873
|
|
1552
1874
|
/**
|
@@ -1562,8 +1884,6 @@ var Row = Backgrid.Row = Backbone.View.extend({
|
|
1562
1884
|
/** @property */
|
1563
1885
|
tagName: "tr",
|
1564
1886
|
|
1565
|
-
requiredOptions: ["columns", "model"],
|
1566
|
-
|
1567
1887
|
/**
|
1568
1888
|
Initializes a row view instance.
|
1569
1889
|
|
@@ -1575,8 +1895,6 @@ var Row = Backgrid.Row = Backbone.View.extend({
|
|
1575
1895
|
*/
|
1576
1896
|
initialize: function (options) {
|
1577
1897
|
|
1578
|
-
Backgrid.requireOptions(options, this.requiredOptions);
|
1579
|
-
|
1580
1898
|
var columns = this.columns = options.columns;
|
1581
1899
|
if (!(columns instanceof Backbone.Collection)) {
|
1582
1900
|
columns = this.columns = new Columns(columns);
|
@@ -1587,22 +1905,11 @@ var Row = Backgrid.Row = Backbone.View.extend({
|
|
1587
1905
|
cells.push(this.makeCell(columns.at(i), options));
|
1588
1906
|
}
|
1589
1907
|
|
1590
|
-
this.listenTo(columns, "change:renderable", function (column, renderable) {
|
1591
|
-
for (var i = 0; i < cells.length; i++) {
|
1592
|
-
var cell = cells[i];
|
1593
|
-
if (cell.column.get("name") == column.get("name")) {
|
1594
|
-
if (renderable) cell.$el.show(); else cell.$el.hide();
|
1595
|
-
}
|
1596
|
-
}
|
1597
|
-
});
|
1598
|
-
|
1599
1908
|
this.listenTo(columns, "add", function (column, columns) {
|
1600
1909
|
var i = columns.indexOf(column);
|
1601
1910
|
var cell = this.makeCell(column, options);
|
1602
1911
|
cells.splice(i, 0, cell);
|
1603
1912
|
|
1604
|
-
if (!cell.column.get("renderable")) cell.$el.hide();
|
1605
|
-
|
1606
1913
|
var $el = this.$el;
|
1607
1914
|
if (i === 0) {
|
1608
1915
|
$el.prepend(cell.render().$el);
|
@@ -1646,11 +1953,8 @@ var Row = Backgrid.Row = Backbone.View.extend({
|
|
1646
1953
|
this.$el.empty();
|
1647
1954
|
|
1648
1955
|
var fragment = document.createDocumentFragment();
|
1649
|
-
|
1650
1956
|
for (var i = 0; i < this.cells.length; i++) {
|
1651
|
-
|
1652
|
-
fragment.appendChild(cell.render().el);
|
1653
|
-
if (!cell.column.get("renderable")) cell.$el.hide();
|
1957
|
+
fragment.appendChild(this.cells[i].render().el);
|
1654
1958
|
}
|
1655
1959
|
|
1656
1960
|
this.el.appendChild(fragment);
|
@@ -1687,19 +1991,17 @@ var EmptyRow = Backgrid.EmptyRow = Backbone.View.extend({
|
|
1687
1991
|
/** @property */
|
1688
1992
|
tagName: "tr",
|
1689
1993
|
|
1690
|
-
/** @property */
|
1994
|
+
/** @property {string|function(): string} */
|
1691
1995
|
emptyText: null,
|
1692
1996
|
|
1693
1997
|
/**
|
1694
1998
|
Initializer.
|
1695
1999
|
|
1696
2000
|
@param {Object} options
|
1697
|
-
@param {string} options.emptyText
|
2001
|
+
@param {string|function(): string} options.emptyText
|
1698
2002
|
@param {Backbone.Collection.<Backgrid.Column>|Array.<Backgrid.Column>|Array.<Object>} options.columns Column metadata.
|
1699
2003
|
*/
|
1700
2004
|
initialize: function (options) {
|
1701
|
-
Backgrid.requireOptions(options, ["emptyText", "columns"]);
|
1702
|
-
|
1703
2005
|
this.emptyText = options.emptyText;
|
1704
2006
|
this.columns = options.columns;
|
1705
2007
|
},
|
@@ -1712,20 +2014,21 @@ var EmptyRow = Backgrid.EmptyRow = Backbone.View.extend({
|
|
1712
2014
|
|
1713
2015
|
var td = document.createElement("td");
|
1714
2016
|
td.setAttribute("colspan", this.columns.length);
|
1715
|
-
td.
|
2017
|
+
td.appendChild(document.createTextNode(_.result(this, "emptyText")));
|
1716
2018
|
|
1717
|
-
this.el.
|
2019
|
+
this.el.className = "empty";
|
1718
2020
|
this.el.appendChild(td);
|
1719
2021
|
|
1720
2022
|
return this;
|
1721
2023
|
}
|
1722
2024
|
});
|
2025
|
+
|
1723
2026
|
/*
|
1724
2027
|
backgrid
|
1725
2028
|
http://github.com/wyuenho/backgrid
|
1726
2029
|
|
1727
2030
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
1728
|
-
Licensed under the MIT
|
2031
|
+
Licensed under the MIT license.
|
1729
2032
|
*/
|
1730
2033
|
|
1731
2034
|
/**
|
@@ -1746,12 +2049,6 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({
|
|
1746
2049
|
"click a": "onClick"
|
1747
2050
|
},
|
1748
2051
|
|
1749
|
-
/**
|
1750
|
-
@property {null|"ascending"|"descending"} _direction The current sorting
|
1751
|
-
direction of this column.
|
1752
|
-
*/
|
1753
|
-
_direction: null,
|
1754
|
-
|
1755
2052
|
/**
|
1756
2053
|
Initializer.
|
1757
2054
|
|
@@ -1761,43 +2058,50 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({
|
|
1761
2058
|
@throws {TypeError} If options.column or options.collection is undefined.
|
1762
2059
|
*/
|
1763
2060
|
initialize: function (options) {
|
1764
|
-
Backgrid.requireOptions(options, ["column", "collection"]);
|
1765
2061
|
this.column = options.column;
|
1766
2062
|
if (!(this.column instanceof Column)) {
|
1767
2063
|
this.column = new Column(this.column);
|
1768
2064
|
}
|
1769
|
-
|
2065
|
+
|
2066
|
+
var column = this.column, collection = this.collection, $el = this.$el;
|
2067
|
+
|
2068
|
+
this.listenTo(column, "change:editable change:sortable change:renderable",
|
2069
|
+
function (column) {
|
2070
|
+
var changed = column.changedAttributes();
|
2071
|
+
for (var key in changed) {
|
2072
|
+
if (changed.hasOwnProperty(key)) {
|
2073
|
+
$el.toggleClass(key, changed[key]);
|
2074
|
+
}
|
2075
|
+
}
|
2076
|
+
});
|
2077
|
+
this.listenTo(column, "change:direction", this.setCellDirection);
|
2078
|
+
this.listenTo(column, "change:name change:label", this.render);
|
2079
|
+
|
2080
|
+
if (Backgrid.callByNeed(column.editable(), column, collection)) $el.addClass("editable");
|
2081
|
+
if (Backgrid.callByNeed(column.sortable(), column, collection)) $el.addClass("sortable");
|
2082
|
+
if (Backgrid.callByNeed(column.renderable(), column, collection)) $el.addClass("renderable");
|
2083
|
+
|
2084
|
+
this.listenTo(collection.fullCollection || collection, "sort", this.removeCellDirection);
|
1770
2085
|
},
|
1771
2086
|
|
1772
2087
|
/**
|
1773
|
-
|
1774
|
-
|
1775
|
-
it. If a `null` is given, sets this cell back to the default order.
|
1776
|
-
|
1777
|
-
@param {null|"ascending"|"descending"} dir
|
1778
|
-
@return {null|string} The current direction or the changed direction.
|
2088
|
+
Event handler for the collection's `sort` event. Removes all the CSS
|
2089
|
+
direction classes.
|
1779
2090
|
*/
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
if (dir) this.$el.addClass(dir);
|
1784
|
-
this._direction = dir;
|
1785
|
-
}
|
1786
|
-
|
1787
|
-
return this._direction;
|
2091
|
+
removeCellDirection: function () {
|
2092
|
+
this.$el.removeClass("ascending").removeClass("descending");
|
2093
|
+
this.column.set("direction", null);
|
1788
2094
|
},
|
1789
2095
|
|
1790
2096
|
/**
|
1791
|
-
Event handler for the
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
2097
|
+
Event handler for the column's `change:direction` event. If this
|
2098
|
+
HeaderCell's column is being sorted on, it applies the direction given as a
|
2099
|
+
CSS class to the header cell. Removes all the CSS direction classes
|
2100
|
+
otherwise.
|
1795
2101
|
*/
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
else this.direction(direction);
|
1800
|
-
}
|
2102
|
+
setCellDirection: function (column, direction) {
|
2103
|
+
this.$el.removeClass("ascending").removeClass("descending");
|
2104
|
+
if (column.cid == this.column.cid) this.$el.addClass(direction);
|
1801
2105
|
},
|
1802
2106
|
|
1803
2107
|
/**
|
@@ -1808,115 +2112,47 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({
|
|
1808
2112
|
onClick: function (e) {
|
1809
2113
|
e.preventDefault();
|
1810
2114
|
|
1811
|
-
var
|
1812
|
-
|
1813
|
-
if (this.column.get("sortable")) {
|
1814
|
-
if (this.direction() === "ascending") {
|
1815
|
-
this.sort(columnName, "descending", function (left, right) {
|
1816
|
-
var leftVal = left.get(columnName);
|
1817
|
-
var rightVal = right.get(columnName);
|
1818
|
-
if (leftVal === rightVal) {
|
1819
|
-
return 0;
|
1820
|
-
}
|
1821
|
-
else if (leftVal > rightVal) { return -1; }
|
1822
|
-
return 1;
|
1823
|
-
});
|
1824
|
-
}
|
1825
|
-
else if (this.direction() === "descending") {
|
1826
|
-
this.sort(columnName, null);
|
1827
|
-
}
|
1828
|
-
else {
|
1829
|
-
this.sort(columnName, "ascending", function (left, right) {
|
1830
|
-
var leftVal = left.get(columnName);
|
1831
|
-
var rightVal = right.get(columnName);
|
1832
|
-
if (leftVal === rightVal) {
|
1833
|
-
return 0;
|
1834
|
-
}
|
1835
|
-
else if (leftVal < rightVal) { return -1; }
|
1836
|
-
return 1;
|
1837
|
-
});
|
1838
|
-
}
|
1839
|
-
}
|
1840
|
-
},
|
1841
|
-
|
1842
|
-
/**
|
1843
|
-
If the underlying collection is a Backbone.PageableCollection in
|
1844
|
-
server-mode or infinite-mode, a page of models is fetched after sorting is
|
1845
|
-
done on the server.
|
1846
|
-
|
1847
|
-
If the underlying collection is a Backbone.PageableCollection in
|
1848
|
-
client-mode, or any
|
1849
|
-
[Backbone.Collection](http://backbonejs.org/#Collection) instance, sorting
|
1850
|
-
is done on the client side. If the collection is an instance of a
|
1851
|
-
Backbone.PageableCollection, sorting will be done globally on all the pages
|
1852
|
-
and the current page will then be returned.
|
1853
|
-
|
1854
|
-
Triggers a Backbone `backgrid:sort` event from the collection when done
|
1855
|
-
with the column name, direction, comparator and a reference to the
|
1856
|
-
collection.
|
1857
|
-
|
1858
|
-
@param {string} columnName
|
1859
|
-
@param {null|"ascending"|"descending"} direction
|
1860
|
-
@param {function(*, *): number} [comparator]
|
1861
|
-
|
1862
|
-
See [Backbone.Collection#comparator](http://backbonejs.org/#Collection-comparator)
|
1863
|
-
*/
|
1864
|
-
sort: function (columnName, direction, comparator) {
|
1865
|
-
|
1866
|
-
comparator = comparator || this._cidComparator;
|
1867
|
-
|
2115
|
+
var column = this.column;
|
1868
2116
|
var collection = this.collection;
|
2117
|
+
var event = "backgrid:sort";
|
1869
2118
|
|
1870
|
-
|
1871
|
-
|
1872
|
-
if (direction === "
|
1873
|
-
else
|
1874
|
-
else order = null;
|
1875
|
-
|
1876
|
-
collection.setSorting(order ? columnName : null, order);
|
1877
|
-
|
1878
|
-
if (collection.mode == "client") {
|
1879
|
-
if (!collection.fullCollection.comparator) {
|
1880
|
-
collection.fullCollection.comparator = comparator;
|
1881
|
-
}
|
1882
|
-
collection.fullCollection.sort();
|
1883
|
-
}
|
1884
|
-
else collection.fetch({reset: true});
|
1885
|
-
}
|
1886
|
-
else {
|
1887
|
-
collection.comparator = comparator;
|
1888
|
-
collection.sort();
|
2119
|
+
function cycleSort(header, col) {
|
2120
|
+
if (column.get("direction") === "ascending") collection.trigger(event, col, "descending");
|
2121
|
+
else if (column.get("direction") === "descending") collection.trigger(event, col, null);
|
2122
|
+
else collection.trigger(event, col, "ascending");
|
1889
2123
|
}
|
1890
2124
|
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
/**
|
1895
|
-
Default comparator for Backbone.Collections. Sorts cids in ascending
|
1896
|
-
order. The cids of the models are assumed to be in insertion order.
|
1897
|
-
|
1898
|
-
@private
|
1899
|
-
@param {*} left
|
1900
|
-
@param {*} right
|
1901
|
-
*/
|
1902
|
-
_cidComparator: function (left, right) {
|
1903
|
-
var lcid = left.cid, rcid = right.cid;
|
1904
|
-
if (!_.isUndefined(lcid) && !_.isUndefined(rcid)) {
|
1905
|
-
lcid = lcid.slice(1) * 1, rcid = rcid.slice(1) * 1;
|
1906
|
-
if (lcid < rcid) return -1;
|
1907
|
-
else if (lcid > rcid) return 1;
|
2125
|
+
function toggleSort(header, col) {
|
2126
|
+
if (column.get("direction") === "ascending") collection.trigger(event, col, "descending");
|
2127
|
+
else collection.trigger(event, col, "ascending");
|
1908
2128
|
}
|
1909
2129
|
|
1910
|
-
|
2130
|
+
var sortable = Backgrid.callByNeed(column.sortable(), column, this.collection);
|
2131
|
+
if (sortable) {
|
2132
|
+
var sortType = column.get("sortType");
|
2133
|
+
if (sortType === "toggle") toggleSort(this, column);
|
2134
|
+
else cycleSort(this, column);
|
2135
|
+
}
|
1911
2136
|
},
|
1912
2137
|
|
1913
2138
|
/**
|
1914
|
-
Renders a header cell with a sorter and a
|
2139
|
+
Renders a header cell with a sorter, a label, and a class name for this
|
2140
|
+
column.
|
1915
2141
|
*/
|
1916
2142
|
render: function () {
|
1917
2143
|
this.$el.empty();
|
1918
|
-
var
|
1919
|
-
|
2144
|
+
var column = this.column;
|
2145
|
+
var sortable = Backgrid.callByNeed(column.sortable(), column, this.collection);
|
2146
|
+
var label;
|
2147
|
+
if(sortable){
|
2148
|
+
label = $("<a>").text(column.get("label")).append("<b class='sort-caret'></b>");
|
2149
|
+
} else {
|
2150
|
+
label = document.createTextNode(column.get("label"));
|
2151
|
+
}
|
2152
|
+
|
2153
|
+
this.$el.append(label);
|
2154
|
+
this.$el.addClass(column.get("name"));
|
2155
|
+
this.$el.addClass(column.get("direction"));
|
1920
2156
|
this.delegateEvents();
|
1921
2157
|
return this;
|
1922
2158
|
}
|
@@ -1931,8 +2167,6 @@ var HeaderCell = Backgrid.HeaderCell = Backbone.View.extend({
|
|
1931
2167
|
*/
|
1932
2168
|
var HeaderRow = Backgrid.HeaderRow = Backgrid.Row.extend({
|
1933
2169
|
|
1934
|
-
requiredOptions: ["columns", "collection"],
|
1935
|
-
|
1936
2170
|
/**
|
1937
2171
|
Initializer.
|
1938
2172
|
|
@@ -1983,8 +2217,6 @@ var Header = Backgrid.Header = Backbone.View.extend({
|
|
1983
2217
|
@throws {TypeError} If options.columns or options.model is undefined.
|
1984
2218
|
*/
|
1985
2219
|
initialize: function (options) {
|
1986
|
-
Backgrid.requireOptions(options, ["columns", "collection"]);
|
1987
|
-
|
1988
2220
|
this.columns = options.columns;
|
1989
2221
|
if (!(this.columns instanceof Backbone.Collection)) {
|
1990
2222
|
this.columns = new Columns(this.columns);
|
@@ -2016,12 +2248,13 @@ var Header = Backgrid.Header = Backbone.View.extend({
|
|
2016
2248
|
}
|
2017
2249
|
|
2018
2250
|
});
|
2251
|
+
|
2019
2252
|
/*
|
2020
2253
|
backgrid
|
2021
2254
|
http://github.com/wyuenho/backgrid
|
2022
2255
|
|
2023
2256
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
2024
|
-
Licensed under the MIT
|
2257
|
+
Licensed under the MIT license.
|
2025
2258
|
*/
|
2026
2259
|
|
2027
2260
|
/**
|
@@ -2044,14 +2277,13 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2044
2277
|
@param {Backbone.Collection.<Backgrid.Column>|Array.<Backgrid.Column>|Array.<Object>} options.columns
|
2045
2278
|
Column metadata.
|
2046
2279
|
@param {Backgrid.Row} [options.row=Backgrid.Row] The Row class to use.
|
2047
|
-
@param {string} [options.emptyText] The text to display in the empty row.
|
2280
|
+
@param {string|function(): string} [options.emptyText] The text to display in the empty row.
|
2048
2281
|
|
2049
2282
|
@throws {TypeError} If options.columns or options.collection is undefined.
|
2050
2283
|
|
2051
2284
|
See Backgrid.Row.
|
2052
2285
|
*/
|
2053
2286
|
initialize: function (options) {
|
2054
|
-
Backgrid.requireOptions(options, ["columns", "collection"]);
|
2055
2287
|
|
2056
2288
|
this.columns = options.columns;
|
2057
2289
|
if (!(this.columns instanceof Backbone.Collection)) {
|
@@ -2076,6 +2308,7 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2076
2308
|
this.listenTo(collection, "remove", this.removeRow);
|
2077
2309
|
this.listenTo(collection, "sort", this.refresh);
|
2078
2310
|
this.listenTo(collection, "reset", this.refresh);
|
2311
|
+
this.listenTo(collection, "backgrid:sort", this.sort);
|
2079
2312
|
this.listenTo(collection, "backgrid:edited", this.moveToNextCell);
|
2080
2313
|
},
|
2081
2314
|
|
@@ -2121,8 +2354,6 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2121
2354
|
return;
|
2122
2355
|
}
|
2123
2356
|
|
2124
|
-
options = _.extend({render: true}, options || {});
|
2125
|
-
|
2126
2357
|
var row = new this.row({
|
2127
2358
|
columns: this.columns,
|
2128
2359
|
model: model
|
@@ -2135,14 +2366,14 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2135
2366
|
var $children = $el.children();
|
2136
2367
|
var $rowEl = row.render().$el;
|
2137
2368
|
|
2138
|
-
if (
|
2139
|
-
|
2140
|
-
$el.append($rowEl);
|
2141
|
-
}
|
2142
|
-
else {
|
2143
|
-
$children.eq(index).before($rowEl);
|
2144
|
-
}
|
2369
|
+
if (index >= $children.length) {
|
2370
|
+
$el.append($rowEl);
|
2145
2371
|
}
|
2372
|
+
else {
|
2373
|
+
$children.eq(index).before($rowEl);
|
2374
|
+
}
|
2375
|
+
|
2376
|
+
return this;
|
2146
2377
|
},
|
2147
2378
|
|
2148
2379
|
/**
|
@@ -2184,6 +2415,8 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2184
2415
|
|
2185
2416
|
this.rows.splice(options.index, 1);
|
2186
2417
|
this._unshiftEmptyRowMayBe();
|
2418
|
+
|
2419
|
+
return this;
|
2187
2420
|
},
|
2188
2421
|
|
2189
2422
|
/**
|
@@ -2247,18 +2480,115 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2247
2480
|
return Backbone.View.prototype.remove.apply(this, arguments);
|
2248
2481
|
},
|
2249
2482
|
|
2483
|
+
/**
|
2484
|
+
If the underlying collection is a Backbone.PageableCollection in
|
2485
|
+
server-mode or infinite-mode, a page of models is fetched after sorting is
|
2486
|
+
done on the server.
|
2487
|
+
|
2488
|
+
If the underlying collection is a Backbone.PageableCollection in
|
2489
|
+
client-mode, or any
|
2490
|
+
[Backbone.Collection](http://backbonejs.org/#Collection) instance, sorting
|
2491
|
+
is done on the client side. If the collection is an instance of a
|
2492
|
+
Backbone.PageableCollection, sorting will be done globally on all the pages
|
2493
|
+
and the current page will then be returned.
|
2494
|
+
|
2495
|
+
Triggers a Backbone `backgrid:sorted` event from the collection when done
|
2496
|
+
with the column, direction and a reference to the collection.
|
2497
|
+
|
2498
|
+
@param {Backgrid.Column|string} column
|
2499
|
+
@param {null|"ascending"|"descending"} direction
|
2500
|
+
|
2501
|
+
See [Backbone.Collection#comparator](http://backbonejs.org/#Collection-comparator)
|
2502
|
+
*/
|
2503
|
+
sort: function (column, direction) {
|
2504
|
+
|
2505
|
+
if (!_.contains(["ascending", "descending", null], direction)) {
|
2506
|
+
throw new RangeError('direction must be one of "ascending", "descending" or `null`');
|
2507
|
+
}
|
2508
|
+
|
2509
|
+
if (_.isString(column)) column = this.columns.findWhere({name: column});
|
2510
|
+
|
2511
|
+
var collection = this.collection;
|
2512
|
+
|
2513
|
+
var order;
|
2514
|
+
if (direction === "ascending") order = -1;
|
2515
|
+
else if (direction === "descending") order = 1;
|
2516
|
+
else order = null;
|
2517
|
+
|
2518
|
+
var comparator = this.makeComparator(column.get("name"), order,
|
2519
|
+
order ?
|
2520
|
+
column.sortValue() :
|
2521
|
+
function (model) {
|
2522
|
+
return model.cid.replace('c', '') * 1;
|
2523
|
+
});
|
2524
|
+
|
2525
|
+
if (Backbone.PageableCollection &&
|
2526
|
+
collection instanceof Backbone.PageableCollection) {
|
2527
|
+
|
2528
|
+
collection.setSorting(order && column.get("name"), order,
|
2529
|
+
{sortValue: column.sortValue()});
|
2530
|
+
|
2531
|
+
if (collection.fullCollection) {
|
2532
|
+
// If order is null, pageable will remove the comparator on both sides,
|
2533
|
+
// in this case the default insertion order comparator needs to be
|
2534
|
+
// attached to get back to the order before sorting.
|
2535
|
+
if (collection.fullCollection.comparator == null) {
|
2536
|
+
collection.fullCollection.comparator = comparator;
|
2537
|
+
}
|
2538
|
+
collection.fullCollection.sort();
|
2539
|
+
collection.trigger("backgrid:sorted", column, direction, collection);
|
2540
|
+
}
|
2541
|
+
else collection.fetch({reset: true, success: function () {
|
2542
|
+
collection.trigger("backgrid:sorted", column, direction, collection);
|
2543
|
+
}});
|
2544
|
+
}
|
2545
|
+
else {
|
2546
|
+
collection.comparator = comparator;
|
2547
|
+
collection.sort();
|
2548
|
+
collection.trigger("backgrid:sorted", column, direction, collection);
|
2549
|
+
}
|
2550
|
+
|
2551
|
+
column.set("direction", direction);
|
2552
|
+
|
2553
|
+
return this;
|
2554
|
+
},
|
2555
|
+
|
2556
|
+
makeComparator: function (attr, order, func) {
|
2557
|
+
|
2558
|
+
return function (left, right) {
|
2559
|
+
// extract the values from the models
|
2560
|
+
var l = func(left, attr), r = func(right, attr), t;
|
2561
|
+
|
2562
|
+
// if descending order, swap left and right
|
2563
|
+
if (order === 1) t = l, l = r, r = t;
|
2564
|
+
|
2565
|
+
// compare as usual
|
2566
|
+
if (l === r) return 0;
|
2567
|
+
else if (l < r) return -1;
|
2568
|
+
return 1;
|
2569
|
+
};
|
2570
|
+
},
|
2571
|
+
|
2250
2572
|
/**
|
2251
2573
|
Moves focus to the next renderable and editable cell and return the
|
2252
2574
|
currently editing cell to display mode.
|
2253
2575
|
|
2576
|
+
Triggers a `backgrid:next` event on the model with the indices of the row
|
2577
|
+
and column the user *intended* to move to, and whether the intended move
|
2578
|
+
was going to go out of bounds. Note that *out of bound* always means an
|
2579
|
+
attempt to go past the end of the last row.
|
2580
|
+
|
2254
2581
|
@param {Backbone.Model} model The originating model
|
2255
2582
|
@param {Backgrid.Column} column The originating model column
|
2256
2583
|
@param {Backgrid.Command} command The Command object constructed from a DOM
|
2257
|
-
|
2584
|
+
event
|
2258
2585
|
*/
|
2259
2586
|
moveToNextCell: function (model, column, command) {
|
2260
2587
|
var i = this.collection.indexOf(model);
|
2261
2588
|
var j = this.columns.indexOf(column);
|
2589
|
+
var cell, renderable, editable, m, n;
|
2590
|
+
|
2591
|
+
this.rows[i].cells[j].exitEditMode();
|
2262
2592
|
|
2263
2593
|
if (command.moveUp() || command.moveDown() || command.moveLeft() ||
|
2264
2594
|
command.moveRight() || command.save()) {
|
@@ -2266,34 +2596,50 @@ var Body = Backgrid.Body = Backbone.View.extend({
|
|
2266
2596
|
var maxOffset = l * this.collection.length;
|
2267
2597
|
|
2268
2598
|
if (command.moveUp() || command.moveDown()) {
|
2269
|
-
|
2270
|
-
|
2599
|
+
m = i + (command.moveUp() ? -1 : 1);
|
2600
|
+
var row = this.rows[m];
|
2601
|
+
if (row) {
|
2602
|
+
cell = row.cells[j];
|
2603
|
+
if (Backgrid.callByNeed(cell.column.editable(), cell.column, model)) {
|
2604
|
+
cell.enterEditMode();
|
2605
|
+
model.trigger("backgrid:next", m, j, false);
|
2606
|
+
}
|
2607
|
+
}
|
2608
|
+
else model.trigger("backgrid:next", m, j, true);
|
2271
2609
|
}
|
2272
2610
|
else if (command.moveLeft() || command.moveRight()) {
|
2273
2611
|
var right = command.moveRight();
|
2274
2612
|
for (var offset = i * l + j + (right ? 1 : -1);
|
2275
2613
|
offset >= 0 && offset < maxOffset;
|
2276
2614
|
right ? offset++ : offset--) {
|
2277
|
-
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
2615
|
+
m = ~~(offset / l);
|
2616
|
+
n = offset - m * l;
|
2617
|
+
cell = this.rows[m].cells[n];
|
2618
|
+
renderable = Backgrid.callByNeed(cell.column.renderable(), cell.column, cell.model);
|
2619
|
+
editable = Backgrid.callByNeed(cell.column.editable(), cell.column, model);
|
2620
|
+
if (renderable && editable) {
|
2281
2621
|
cell.enterEditMode();
|
2622
|
+
model.trigger("backgrid:next", m, n, false);
|
2282
2623
|
break;
|
2283
2624
|
}
|
2284
2625
|
}
|
2626
|
+
|
2627
|
+
if (offset == maxOffset) {
|
2628
|
+
model.trigger("backgrid:next", ~~(offset / l), offset - m * l, true);
|
2629
|
+
}
|
2285
2630
|
}
|
2286
2631
|
}
|
2287
2632
|
|
2288
|
-
this
|
2633
|
+
return this;
|
2289
2634
|
}
|
2290
2635
|
});
|
2636
|
+
|
2291
2637
|
/*
|
2292
2638
|
backgrid
|
2293
2639
|
http://github.com/wyuenho/backgrid
|
2294
2640
|
|
2295
2641
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
2296
|
-
Licensed under the MIT
|
2642
|
+
Licensed under the MIT license.
|
2297
2643
|
*/
|
2298
2644
|
|
2299
2645
|
/**
|
@@ -2313,7 +2659,6 @@ var Footer = Backgrid.Footer = Backbone.View.extend({
|
|
2313
2659
|
Initializer.
|
2314
2660
|
|
2315
2661
|
@param {Object} options
|
2316
|
-
@param {*} options.parent The parent view class of this footer.
|
2317
2662
|
@param {Backbone.Collection.<Backgrid.Column>|Array.<Backgrid.Column>|Array.<Object>} options.columns
|
2318
2663
|
Column metadata.
|
2319
2664
|
@param {Backbone.Collection} options.collection
|
@@ -2321,7 +2666,6 @@ var Footer = Backgrid.Footer = Backbone.View.extend({
|
|
2321
2666
|
@throws {TypeError} If options.columns or options.collection is undefined.
|
2322
2667
|
*/
|
2323
2668
|
initialize: function (options) {
|
2324
|
-
Backgrid.requireOptions(options, ["columns", "collection"]);
|
2325
2669
|
this.columns = options.columns;
|
2326
2670
|
if (!(this.columns instanceof Backbone.Collection)) {
|
2327
2671
|
this.columns = new Backgrid.Columns(this.columns);
|
@@ -2329,12 +2673,13 @@ var Footer = Backgrid.Footer = Backbone.View.extend({
|
|
2329
2673
|
}
|
2330
2674
|
|
2331
2675
|
});
|
2676
|
+
|
2332
2677
|
/*
|
2333
2678
|
backgrid
|
2334
2679
|
http://github.com/wyuenho/backgrid
|
2335
2680
|
|
2336
2681
|
Copyright (c) 2013 Jimmy Yuen Ho Wong and contributors
|
2337
|
-
Licensed under the MIT
|
2682
|
+
Licensed under the MIT license.
|
2338
2683
|
*/
|
2339
2684
|
|
2340
2685
|
/**
|
@@ -2405,7 +2750,7 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2405
2750
|
Initializes a Grid instance.
|
2406
2751
|
|
2407
2752
|
@param {Object} options
|
2408
|
-
@param {Backbone.Collection.<Backgrid.
|
2753
|
+
@param {Backbone.Collection.<Backgrid.Columns>|Array.<Backgrid.Column>|Array.<Object>} options.columns Column metadata.
|
2409
2754
|
@param {Backbone.Collection} options.collection The collection of tabular model data to display.
|
2410
2755
|
@param {Backgrid.Header} [options.header=Backgrid.Header] An optional Header class to override the default.
|
2411
2756
|
@param {Backgrid.Body} [options.body=Backgrid.Body] An optional Body class to override the default.
|
@@ -2413,34 +2758,37 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2413
2758
|
@param {Backgrid.Footer} [options.footer=Backgrid.Footer] An optional Footer class.
|
2414
2759
|
*/
|
2415
2760
|
initialize: function (options) {
|
2416
|
-
Backgrid.requireOptions(options, ["columns", "collection"]);
|
2417
|
-
|
2418
2761
|
// Convert the list of column objects here first so the subviews don't have
|
2419
2762
|
// to.
|
2420
2763
|
if (!(options.columns instanceof Backbone.Collection)) {
|
2421
|
-
options.columns = new Columns(options.columns);
|
2764
|
+
options.columns = new Columns(options.columns || this.columns);
|
2422
2765
|
}
|
2423
2766
|
this.columns = options.columns;
|
2424
2767
|
|
2425
|
-
var
|
2426
|
-
|
2427
|
-
|
2428
|
-
this.header = options.header || this.header;
|
2429
|
-
this.header = new this.header(passedThruOptions);
|
2768
|
+
var filteredOptions = _.omit(options, ["el", "id", "attributes",
|
2769
|
+
"className", "tagName", "events"]);
|
2430
2770
|
|
2771
|
+
// must construct body first so it listens to backgrid:sort first
|
2431
2772
|
this.body = options.body || this.body;
|
2432
|
-
this.body = new this.body(
|
2773
|
+
this.body = new this.body(filteredOptions);
|
2774
|
+
|
2775
|
+
this.header = options.header || this.header;
|
2776
|
+
if (this.header) {
|
2777
|
+
this.header = new this.header(filteredOptions);
|
2778
|
+
}
|
2433
2779
|
|
2434
2780
|
this.footer = options.footer || this.footer;
|
2435
2781
|
if (this.footer) {
|
2436
|
-
this.footer = new this.footer(
|
2782
|
+
this.footer = new this.footer(filteredOptions);
|
2437
2783
|
}
|
2438
2784
|
|
2439
2785
|
this.listenTo(this.columns, "reset", function () {
|
2440
|
-
|
2441
|
-
|
2786
|
+
if (this.header) {
|
2787
|
+
this.header = new (this.header.remove().constructor)(filteredOptions);
|
2788
|
+
}
|
2789
|
+
this.body = new (this.body.remove().constructor)(filteredOptions);
|
2442
2790
|
if (this.footer) {
|
2443
|
-
this.footer = new (this.footer.remove().constructor)(
|
2791
|
+
this.footer = new (this.footer.remove().constructor)(filteredOptions);
|
2444
2792
|
}
|
2445
2793
|
this.render();
|
2446
2794
|
});
|
@@ -2449,15 +2797,17 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2449
2797
|
/**
|
2450
2798
|
Delegates to Backgrid.Body#insertRow.
|
2451
2799
|
*/
|
2452
|
-
insertRow: function (
|
2453
|
-
|
2800
|
+
insertRow: function () {
|
2801
|
+
this.body.insertRow.apply(this.body, arguments);
|
2802
|
+
return this;
|
2454
2803
|
},
|
2455
2804
|
|
2456
2805
|
/**
|
2457
2806
|
Delegates to Backgrid.Body#removeRow.
|
2458
2807
|
*/
|
2459
|
-
removeRow: function (
|
2460
|
-
|
2808
|
+
removeRow: function () {
|
2809
|
+
this.body.removeRow.apply(this.body, arguments);
|
2810
|
+
return this;
|
2461
2811
|
},
|
2462
2812
|
|
2463
2813
|
/**
|
@@ -2466,14 +2816,9 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2466
2816
|
happen.
|
2467
2817
|
|
2468
2818
|
@param {Object} [options] Options for `Backgrid.Columns#add`.
|
2469
|
-
@param {boolean} [options.render=true] Whether to render the column
|
2470
|
-
immediately after insertion.
|
2471
|
-
|
2472
|
-
@chainable
|
2473
2819
|
*/
|
2474
|
-
insertColumn: function (
|
2475
|
-
|
2476
|
-
this.columns.add(column, options);
|
2820
|
+
insertColumn: function () {
|
2821
|
+
this.columns.add.apply(this.columns, arguments);
|
2477
2822
|
return this;
|
2478
2823
|
},
|
2479
2824
|
|
@@ -2483,11 +2828,17 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2483
2828
|
needs to happen.
|
2484
2829
|
|
2485
2830
|
@param {Object} [options] Options for `Backgrid.Columns#remove`.
|
2831
|
+
*/
|
2832
|
+
removeColumn: function () {
|
2833
|
+
this.columns.remove.apply(this.columns, arguments);
|
2834
|
+
return this;
|
2835
|
+
},
|
2486
2836
|
|
2487
|
-
|
2837
|
+
/**
|
2838
|
+
Delegates to Backgrid.Body#sort.
|
2488
2839
|
*/
|
2489
|
-
|
2490
|
-
this.
|
2840
|
+
sort: function () {
|
2841
|
+
this.body.sort.apply(this.body, arguments);
|
2491
2842
|
return this;
|
2492
2843
|
},
|
2493
2844
|
|
@@ -2499,7 +2850,9 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2499
2850
|
render: function () {
|
2500
2851
|
this.$el.empty();
|
2501
2852
|
|
2502
|
-
|
2853
|
+
if (this.header) {
|
2854
|
+
this.$el.append(this.header.render().$el);
|
2855
|
+
}
|
2503
2856
|
|
2504
2857
|
if (this.footer) {
|
2505
2858
|
this.$el.append(this.footer.render().$el);
|
@@ -2520,12 +2873,12 @@ var Grid = Backgrid.Grid = Backbone.View.extend({
|
|
2520
2873
|
@chainable
|
2521
2874
|
*/
|
2522
2875
|
remove: function () {
|
2523
|
-
this.header.remove.apply(this.header, arguments);
|
2876
|
+
this.header && this.header.remove.apply(this.header, arguments);
|
2524
2877
|
this.body.remove.apply(this.body, arguments);
|
2525
2878
|
this.footer && this.footer.remove.apply(this.footer, arguments);
|
2526
2879
|
return Backbone.View.prototype.remove.apply(this, arguments);
|
2527
2880
|
}
|
2528
2881
|
|
2529
2882
|
});
|
2530
|
-
|
2531
|
-
}
|
2883
|
+
return Backgrid;
|
2884
|
+
}));
|