tableling-rails 0.0.23 → 0.0.24
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 +8 -8
- data/LICENSE.txt +1 -1
- data/VERSION +1 -1
- data/lib/tableling-rails/version.rb +1 -1
- data/vendor/assets/javascripts/tableling.backbone.js +795 -730
- data/vendor/assets/javascripts/tableling.js +727 -704
- data/vendor/assets/javascripts/tableling.world.js +6315 -5968
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
ZTUxMzMyYjBkZDk5OGVhMTQwZTljNzNjNDE2ZTNkOGE1ZDllMzU2NA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZGMzZjA0ODRiZTEzZTZlNjVjMWQzYmQyOWZmNGI2NDgwY2ZmMzY0YQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NTE4NGRjZjVhMzBhMGM4NWE5MmZkZGI3NTMwYmExNTA3NDg2ZDNkN2JlYzBj
|
10
|
+
YzNhNmY3M2ZlNWY0ZmVkNzljYzg1YjgwNzZmMzA3OWMyYWMzZWRkYzZlMDM3
|
11
|
+
NDUxMzliNDM4Nzk0Y2U2ODRhMjI1Zjk0ZmYzZWI5MTgxODI1MDI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YTMwYjEwNTQwYzY4ZTQ4ZWVmZmVmZmU2NmI4OWRmMWNhZmI5OTA3NmI4ZGI0
|
14
|
+
OGQzMmJkY2YxZjM0YzMyYjNmOTBiN2U3NTAxZGE1MTZhM2ZiNWI0Y2IwMWU4
|
15
|
+
MjNmOGQ0M2FkNmIzNTE0MmYxNGE5MWZlY2U5MDc4ODJiMzIyY2U=
|
data/LICENSE.txt
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.24
|
@@ -1582,9 +1582,9 @@
|
|
1582
1582
|
|
1583
1583
|
// MarionetteJS (Backbone.Marionette)
|
1584
1584
|
// ----------------------------------
|
1585
|
-
// v1.
|
1585
|
+
// v1.5.1
|
1586
1586
|
//
|
1587
|
-
// Copyright (c)
|
1587
|
+
// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
|
1588
1588
|
// Distributed under MIT license
|
1589
1589
|
//
|
1590
1590
|
// http://marionettejs.com
|
@@ -2078,11 +2078,11 @@ Marionette.getOption = function(target, optionName){
|
|
2078
2078
|
// `this.triggerMethod("foo")` will trigger the "foo" event and
|
2079
2079
|
// call the "onFoo" method.
|
2080
2080
|
//
|
2081
|
-
// `this.triggerMethod("foo:bar") will trigger the "foo:bar" event and
|
2081
|
+
// `this.triggerMethod("foo:bar")` will trigger the "foo:bar" event and
|
2082
2082
|
// call the "onFooBar" method.
|
2083
2083
|
Marionette.triggerMethod = (function(){
|
2084
2084
|
|
2085
|
-
// split the event name on the :
|
2085
|
+
// split the event name on the ":"
|
2086
2086
|
var splitter = /(^|:)(\w)/gi;
|
2087
2087
|
|
2088
2088
|
// take the event section ("section1:section2:section3")
|
@@ -2091,7 +2091,7 @@ Marionette.triggerMethod = (function(){
|
|
2091
2091
|
return eventName.toUpperCase();
|
2092
2092
|
}
|
2093
2093
|
|
2094
|
-
// actual triggerMethod
|
2094
|
+
// actual triggerMethod implementation
|
2095
2095
|
var triggerMethod = function(event) {
|
2096
2096
|
// get the method name from the event name
|
2097
2097
|
var methodName = 'on' + event.replace(splitter, getEventName);
|
@@ -2119,7 +2119,7 @@ Marionette.triggerMethod = (function(){
|
|
2119
2119
|
// in the DOM, trigger a "dom:refresh" event every time it is
|
2120
2120
|
// re-rendered.
|
2121
2121
|
|
2122
|
-
Marionette.MonitorDOMRefresh = (function(){
|
2122
|
+
Marionette.MonitorDOMRefresh = (function(documentElement){
|
2123
2123
|
// track when the view has been shown in the DOM,
|
2124
2124
|
// using a Marionette.Region (or by other means of triggering "show")
|
2125
2125
|
function handleShow(view){
|
@@ -2135,13 +2135,17 @@ Marionette.MonitorDOMRefresh = (function(){
|
|
2135
2135
|
|
2136
2136
|
// Trigger the "dom:refresh" event and corresponding "onDomRefresh" method
|
2137
2137
|
function triggerDOMRefresh(view){
|
2138
|
-
if (view._isShown && view._isRendered){
|
2138
|
+
if (view._isShown && view._isRendered && isInDOM(view)){
|
2139
2139
|
if (_.isFunction(view.triggerMethod)){
|
2140
2140
|
view.triggerMethod("dom:refresh");
|
2141
2141
|
}
|
2142
2142
|
}
|
2143
2143
|
}
|
2144
2144
|
|
2145
|
+
function isInDOM(view) {
|
2146
|
+
return documentElement.contains(view.el);
|
2147
|
+
}
|
2148
|
+
|
2145
2149
|
// Export public API
|
2146
2150
|
return function(view){
|
2147
2151
|
view.listenTo(view, "show", function(){
|
@@ -2152,7 +2156,7 @@ Marionette.MonitorDOMRefresh = (function(){
|
|
2152
2156
|
handleRender(view);
|
2153
2157
|
});
|
2154
2158
|
};
|
2155
|
-
})();
|
2159
|
+
})(document.documentElement);
|
2156
2160
|
|
2157
2161
|
|
2158
2162
|
// Marionette.bindEntityEvents & unbindEntityEvents
|
@@ -2386,6 +2390,7 @@ _.extend(Marionette.Region, {
|
|
2386
2390
|
|
2387
2391
|
if (regionConfig.selector) {
|
2388
2392
|
selector = regionConfig.selector;
|
2393
|
+
delete regionConfig.selector;
|
2389
2394
|
}
|
2390
2395
|
|
2391
2396
|
// get the type for the region
|
@@ -2400,12 +2405,17 @@ _.extend(Marionette.Region, {
|
|
2400
2405
|
|
2401
2406
|
if (regionConfig.regionType) {
|
2402
2407
|
RegionType = regionConfig.regionType;
|
2408
|
+
delete regionConfig.regionType;
|
2403
2409
|
}
|
2404
2410
|
|
2411
|
+
if (regionIsString || regionIsType) {
|
2412
|
+
regionConfig = {};
|
2413
|
+
}
|
2414
|
+
|
2415
|
+
regionConfig.el = selector;
|
2416
|
+
|
2405
2417
|
// build the region instance
|
2406
|
-
var region = new RegionType(
|
2407
|
-
el: selector
|
2408
|
-
});
|
2418
|
+
var region = new RegionType(regionConfig);
|
2409
2419
|
|
2410
2420
|
// override the `getEl` function if we have a parentEl
|
2411
2421
|
// this must be overridden to ensure the selector is found
|
@@ -2491,7 +2501,7 @@ _.extend(Marionette.Region.prototype, Backbone.Events, {
|
|
2491
2501
|
if (view.close) { view.close(); }
|
2492
2502
|
else if (view.remove) { view.remove(); }
|
2493
2503
|
|
2494
|
-
Marionette.triggerMethod.call(this, "close");
|
2504
|
+
Marionette.triggerMethod.call(this, "close", view);
|
2495
2505
|
|
2496
2506
|
delete this.currentView;
|
2497
2507
|
},
|
@@ -2634,9 +2644,9 @@ Marionette.RegionManager = (function(Marionette){
|
|
2634
2644
|
//
|
2635
2645
|
// Mix in methods from Underscore, for iteration, and other
|
2636
2646
|
// collection related features.
|
2637
|
-
var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
|
2638
|
-
'select', 'reject', 'every', 'all', 'some', 'any', 'include',
|
2639
|
-
'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
|
2647
|
+
var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
|
2648
|
+
'select', 'reject', 'every', 'all', 'some', 'any', 'include',
|
2649
|
+
'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
|
2640
2650
|
'last', 'without', 'isEmpty', 'pluck'];
|
2641
2651
|
|
2642
2652
|
_.each(methods, function(method) {
|
@@ -2661,7 +2671,7 @@ Marionette.TemplateCache = function(templateId){
|
|
2661
2671
|
};
|
2662
2672
|
|
2663
2673
|
// TemplateCache object-level methods. Manage the template
|
2664
|
-
// caches from these method calls instead of creating
|
2674
|
+
// caches from these method calls instead of creating
|
2665
2675
|
// your own TemplateCache instances
|
2666
2676
|
_.extend(Marionette.TemplateCache, {
|
2667
2677
|
templateCaches: {},
|
@@ -2684,7 +2694,7 @@ _.extend(Marionette.TemplateCache, {
|
|
2684
2694
|
// are specified, clears all templates:
|
2685
2695
|
// `clear()`
|
2686
2696
|
//
|
2687
|
-
// If arguments are specified, clears each of the
|
2697
|
+
// If arguments are specified, clears each of the
|
2688
2698
|
// specified templates from the cache:
|
2689
2699
|
// `clear("#t1", "#t2", "...")`
|
2690
2700
|
clear: function(){
|
@@ -2724,7 +2734,7 @@ _.extend(Marionette.TemplateCache.prototype, {
|
|
2724
2734
|
// Load a template from the DOM, by default. Override
|
2725
2735
|
// this method to provide your own template retrieval
|
2726
2736
|
// For asynchronous loading with AMD/RequireJS, consider
|
2727
|
-
// using a template-loader plugin as described here:
|
2737
|
+
// using a template-loader plugin as described here:
|
2728
2738
|
// https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs
|
2729
2739
|
loadTemplate: function(templateId){
|
2730
2740
|
var template = Marionette.$(templateId).html();
|
@@ -2793,7 +2803,7 @@ Marionette.View = Backbone.View.extend({
|
|
2793
2803
|
// this is a backfill since backbone removed the assignment
|
2794
2804
|
// of this.options
|
2795
2805
|
// at some point however this may be removed
|
2796
|
-
this.options = _.extend({}, this
|
2806
|
+
this.options = _.extend({}, _.result(this, 'options'), _.isFunction(options) ? options.call(this) : options);
|
2797
2807
|
|
2798
2808
|
// parses out the @ui DSL for events
|
2799
2809
|
this.events = this.normalizeUIKeys(_.result(this, 'events'));
|
@@ -3091,7 +3101,8 @@ Marionette.CollectionView = Marionette.View.extend({
|
|
3091
3101
|
// it's much more performant to insert elements into a document
|
3092
3102
|
// fragment and then insert that document fragment into the page
|
3093
3103
|
initRenderBuffer: function() {
|
3094
|
-
this.elBuffer
|
3104
|
+
this.elBuffer = document.createDocumentFragment();
|
3105
|
+
this._bufferedChildren = [];
|
3095
3106
|
},
|
3096
3107
|
|
3097
3108
|
startBuffering: function() {
|
@@ -3100,9 +3111,19 @@ Marionette.CollectionView = Marionette.View.extend({
|
|
3100
3111
|
},
|
3101
3112
|
|
3102
3113
|
endBuffering: function() {
|
3114
|
+
this.isBuffering = false;
|
3103
3115
|
this.appendBuffer(this, this.elBuffer);
|
3116
|
+
this._triggerShowBufferedChildren();
|
3104
3117
|
this.initRenderBuffer();
|
3105
|
-
|
3118
|
+
},
|
3119
|
+
|
3120
|
+
_triggerShowBufferedChildren: function () {
|
3121
|
+
if (this._isShown) {
|
3122
|
+
_.each(this._bufferedChildren, function (child) {
|
3123
|
+
Marionette.triggerMethod.call(child, "show");
|
3124
|
+
});
|
3125
|
+
this._bufferedChildren = [];
|
3126
|
+
}
|
3106
3127
|
},
|
3107
3128
|
|
3108
3129
|
// Configured the initial events that the collection view
|
@@ -3253,12 +3274,14 @@ Marionette.CollectionView = Marionette.View.extend({
|
|
3253
3274
|
|
3254
3275
|
// call the "show" method if the collection view
|
3255
3276
|
// has already been shown
|
3256
|
-
if (this._isShown){
|
3277
|
+
if (this._isShown && !this.isBuffering){
|
3257
3278
|
Marionette.triggerMethod.call(view, "show");
|
3258
3279
|
}
|
3259
3280
|
|
3260
3281
|
// this view was added
|
3261
3282
|
this.triggerMethod("after:item:added", view);
|
3283
|
+
|
3284
|
+
return view;
|
3262
3285
|
},
|
3263
3286
|
|
3264
3287
|
// Set up the child view event forwarding. Uses an "itemview:"
|
@@ -3270,13 +3293,30 @@ Marionette.CollectionView = Marionette.View.extend({
|
|
3270
3293
|
// prepending "itemview:" to the event name
|
3271
3294
|
this.listenTo(view, "all", function(){
|
3272
3295
|
var args = slice(arguments);
|
3273
|
-
|
3296
|
+
var rootEvent = args[0];
|
3297
|
+
var itemEvents = this.getItemEvents();
|
3298
|
+
|
3299
|
+
args[0] = prefix + ":" + rootEvent;
|
3274
3300
|
args.splice(1, 0, view);
|
3275
3301
|
|
3302
|
+
// call collectionView itemEvent if defined
|
3303
|
+
if (typeof itemEvents !== "undefined" && _.isFunction(itemEvents[rootEvent])) {
|
3304
|
+
itemEvents[rootEvent].apply(this, args);
|
3305
|
+
}
|
3306
|
+
|
3276
3307
|
Marionette.triggerMethod.apply(this, args);
|
3277
3308
|
}, this);
|
3278
3309
|
},
|
3279
3310
|
|
3311
|
+
// returns the value of itemEvents depending on if a function
|
3312
|
+
getItemEvents: function() {
|
3313
|
+
if (_.isFunction(this.itemEvents)) {
|
3314
|
+
return this.itemEvents.call(this);
|
3315
|
+
}
|
3316
|
+
|
3317
|
+
return this.itemEvents;
|
3318
|
+
},
|
3319
|
+
|
3280
3320
|
// render the item view
|
3281
3321
|
renderItemView: function(view, index) {
|
3282
3322
|
view.render();
|
@@ -3337,6 +3377,7 @@ Marionette.CollectionView = Marionette.View.extend({
|
|
3337
3377
|
// in order to reduce the number of inserts into the
|
3338
3378
|
// document, which are expensive.
|
3339
3379
|
collectionView.elBuffer.appendChild(itemView.el);
|
3380
|
+
collectionView._bufferedChildren.push(itemView);
|
3340
3381
|
}
|
3341
3382
|
else {
|
3342
3383
|
// If we've already rendered the main collection, just
|
@@ -3489,6 +3530,7 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
|
|
3489
3530
|
appendHtml: function(compositeView, itemView, index){
|
3490
3531
|
if (compositeView.isBuffering) {
|
3491
3532
|
compositeView.elBuffer.appendChild(itemView.el);
|
3533
|
+
compositeView._bufferedChildren.push(itemView);
|
3492
3534
|
}
|
3493
3535
|
else {
|
3494
3536
|
// If we've already rendered the main collection, just
|
@@ -3510,7 +3552,7 @@ Marionette.CompositeView = Marionette.CollectionView.extend({
|
|
3510
3552
|
var itemViewContainer = Marionette.getOption(containerView, "itemViewContainer");
|
3511
3553
|
if (itemViewContainer){
|
3512
3554
|
|
3513
|
-
var selector = _.isFunction(itemViewContainer) ? itemViewContainer() : itemViewContainer;
|
3555
|
+
var selector = _.isFunction(itemViewContainer) ? itemViewContainer.call(this) : itemViewContainer;
|
3514
3556
|
container = containerView.$(selector);
|
3515
3557
|
if (container.length <= 0) {
|
3516
3558
|
throwError("The specified `itemViewContainer` was not found: " + containerView.itemViewContainer, "ItemViewContainerMissingError");
|
@@ -3674,7 +3716,7 @@ Marionette.Layout = Marionette.ItemView.extend({
|
|
3674
3716
|
//
|
3675
3717
|
// Configure an AppRouter with `appRoutes`.
|
3676
3718
|
//
|
3677
|
-
// App routers can only take one `controller` object.
|
3719
|
+
// App routers can only take one `controller` object.
|
3678
3720
|
// It is recommended that you divide your controller
|
3679
3721
|
// objects in to smaller pieces of related functionality
|
3680
3722
|
// and have multiple routers / controllers, instead of
|
@@ -3686,7 +3728,7 @@ Marionette.AppRouter = Backbone.Router.extend({
|
|
3686
3728
|
|
3687
3729
|
constructor: function(options){
|
3688
3730
|
Backbone.Router.prototype.constructor.apply(this, slice(arguments));
|
3689
|
-
|
3731
|
+
|
3690
3732
|
this.options = options || {};
|
3691
3733
|
|
3692
3734
|
var appRoutes = Marionette.getOption(this, "appRoutes");
|
@@ -4048,7 +4090,7 @@ _.extend(Marionette.Module, {
|
|
4048
4090
|
})(this, Backbone, _);
|
4049
4091
|
|
4050
4092
|
/*!
|
4051
|
-
* Tableling v0.0.
|
4093
|
+
* Tableling v0.0.24
|
4052
4094
|
* Copyright (c) 2012-2014 Simon Oulevay (Alpha Hydrae) <hydrae.alpha@gmail.com>
|
4053
4095
|
* Distributed under MIT license
|
4054
4096
|
* https://github.com/AlphaHydrae/tableling
|
@@ -4056,729 +4098,752 @@ _.extend(Marionette.Module, {
|
|
4056
4098
|
Backbone.Tableling = Tableling = (function(Backbone, _, $){
|
4057
4099
|
|
4058
4100
|
var Tableling = {
|
4059
|
-
version : "0.0.
|
4101
|
+
version : "0.0.24"
|
4060
4102
|
};
|
4061
4103
|
|
4062
|
-
|
4063
|
-
|
4064
|
-
|
4065
|
-
|
4066
|
-
|
4067
|
-
|
4068
|
-
|
4069
|
-
|
4070
|
-
|
4071
|
-
|
4072
|
-
|
4073
|
-
|
4074
|
-
|
4075
|
-
|
4076
|
-
|
4077
|
-
|
4078
|
-
|
4079
|
-
|
4080
|
-
|
4081
|
-
|
4082
|
-
|
4083
|
-
|
4084
|
-
|
4085
|
-
|
4086
|
-
|
4087
|
-
|
4088
|
-
|
4089
|
-
|
4090
|
-
|
4091
|
-
|
4092
|
-
// the table (e.g. change page size, sort) and fetch the new data.
|
4093
|
-
this.vent.on('table:update', this.onUpdate, this);
|
4094
|
-
|
4095
|
-
this.on('item:rendered', this.setup, this);
|
4096
|
-
},
|
4097
|
-
|
4098
|
-
// Called once rendering is complete. By default, it updates the table.
|
4099
|
-
setup : function() {
|
4100
|
-
this.ventTrigger('table:setup', this.config);
|
4101
|
-
if (this.autoUpdate) {
|
4102
|
-
this.ventTrigger('table:update');
|
4103
|
-
}
|
4104
|
-
},
|
4105
|
-
|
4106
|
-
// Subclasses must return the Backbone.Collection used to fetch data.
|
4107
|
-
getCollection : function() {
|
4108
|
-
return this.collection;
|
4109
|
-
},
|
4110
|
-
|
4111
|
-
// ### Refreshing the table
|
4112
|
-
update : function(config, options) {
|
4113
|
-
this.ventTrigger('table:update', config, options);
|
4114
|
-
},
|
4115
|
-
|
4116
|
-
onUpdate : function(config, options) {
|
4117
|
-
|
4118
|
-
_.each(config || {}, _.bind(this.updateValue, this));
|
4119
|
-
|
4120
|
-
// Set the `refresh` option to false to update the table configuration
|
4121
|
-
// without refreshing.
|
4122
|
-
if (!options || typeof(options.refresh) == 'undefined' || options.refresh) {
|
4123
|
-
this.refresh();
|
4124
|
-
}
|
4125
|
-
},
|
4126
|
-
|
4127
|
-
updateValue : function(value, key) {
|
4128
|
-
if (value && value.toString().length) {
|
4129
|
-
this.config[key] = value;
|
4130
|
-
} else {
|
4131
|
-
// Blank values are deleted to avoid sending them in ajax requests.
|
4132
|
-
delete this.config[key];
|
4133
|
-
}
|
4134
|
-
},
|
4135
|
-
|
4136
|
-
refresh : function() {
|
4137
|
-
|
4138
|
-
// You can provide `fetchOptions` to add properties to the
|
4139
|
-
// fetch request.
|
4140
|
-
//
|
4141
|
-
// var MyTable = Tableling.Table.extend({
|
4142
|
-
// fetchOptions : {
|
4143
|
-
// type : 'POST' // fetch data with POST
|
4144
|
-
// }
|
4145
|
-
// });
|
4146
|
-
//
|
4147
|
-
// // You can also override for each instance.
|
4148
|
-
// new MyTable({
|
4149
|
-
// fetchOptions : {
|
4150
|
-
// type : 'GET'
|
4151
|
-
// }
|
4152
|
-
// });
|
4153
|
-
var options = _.clone(this.fetchOptions);
|
4154
|
-
options.data = this.requestData();
|
4155
|
-
options.success = _.bind(this.processResponse, this);
|
4156
|
-
options.reset = true;
|
4157
|
-
|
4158
|
-
// `table:refreshing` is triggered every time new data is being fetched.
|
4159
|
-
// The first argument is the request data.
|
4160
|
-
this.ventTrigger('table:refreshing', options.data);
|
4161
|
-
|
4162
|
-
this.getCollection().fetch(options);
|
4163
|
-
},
|
4164
|
-
|
4165
|
-
// ### Request
|
4166
|
-
requestData : function() {
|
4167
|
-
return this.config;
|
4168
|
-
},
|
4169
|
-
|
4170
|
-
// ### Response
|
4171
|
-
processResponse : function(collection, response) {
|
4172
|
-
|
4173
|
-
this.config.length = collection.length;
|
4174
|
-
|
4175
|
-
// Tableling expects the response from a fetch to have a `total` property
|
4176
|
-
// which is the total number of items (not just in the current page).
|
4177
|
-
this.config.total = response.total;
|
4178
|
-
|
4179
|
-
// The server may override the `page` property, for example if the
|
4180
|
-
// requested page was outside the range of available pages.
|
4181
|
-
if (response.page) {
|
4182
|
-
this.config.page = response.page;
|
4183
|
-
}
|
4184
|
-
|
4185
|
-
// `tableling:refreshed` is triggered after every refresh. The first argument
|
4186
|
-
// is the current table configuration with the following additional meta data:
|
4187
|
-
//
|
4188
|
-
// * `total` - the total number of items
|
4189
|
-
// * `length` - the number of items in the current page
|
4190
|
-
this.ventTrigger('table:refreshed', this.config);
|
4191
|
-
},
|
4192
|
-
|
4193
|
-
// Triggers an event in the event aggregator. If `Tableling.debug` is set, it also
|
4194
|
-
// logs the event and its arguments.
|
4195
|
-
ventTrigger : function() {
|
4196
|
-
|
4197
|
-
var args = Array.prototype.slice.call(arguments);
|
4198
|
-
if (Tableling.debug) {
|
4199
|
-
console.log(_.first(args) + ' - ' + JSON.stringify(args.slice(1)));
|
4200
|
-
}
|
4201
|
-
|
4202
|
-
this.vent.trigger.apply(this.vent, args);
|
4104
|
+
// Tableling
|
4105
|
+
// ---------
|
4106
|
+
//
|
4107
|
+
// A tableling table is a Marionette layout which fetches data
|
4108
|
+
// from a Backbone collection. It is controlled with an EventAggregator.
|
4109
|
+
Tableling.Table = Backbone.Marionette.Layout.extend({
|
4110
|
+
|
4111
|
+
className: 'tableling',
|
4112
|
+
|
4113
|
+
// Default table options can be overriden by subclasses.
|
4114
|
+
config: {
|
4115
|
+
page: 1
|
4116
|
+
},
|
4117
|
+
|
4118
|
+
initialize: function(options) {
|
4119
|
+
options = options || {};
|
4120
|
+
|
4121
|
+
this.collection = options.collection;
|
4122
|
+
|
4123
|
+
// Table options can also be overriden for each instance at construction.
|
4124
|
+
this.config = _.extend(_.clone(this.config || {}), _.result(options, 'config') || {});
|
4125
|
+
|
4126
|
+
// We use an event aggregator to manage the layout and its components.
|
4127
|
+
// You can use your own by passing a `vent` option.
|
4128
|
+
this.vent = options.vent || new Backbone.Wreqr.EventAggregator();
|
4129
|
+
|
4130
|
+
this.fetchOptions = _.extend(_.clone(this.fetchOptions || {}), _.result(options, 'fetchOptions') || {});
|
4131
|
+
|
4132
|
+
if (typeof(options.autoUpdate) != 'undefined') {
|
4133
|
+
this.autoUpdate = options.autoUpdate;
|
4203
4134
|
}
|
4204
|
-
|
4205
|
-
|
4206
|
-
|
4207
|
-
// --------------------
|
4208
|
-
//
|
4209
|
-
// Tableling expects fetch responses to have a `total` property in addition
|
4210
|
-
// to the model data. You can extend this Backbone.Collection subclass which
|
4211
|
-
// expects the following response format:
|
4212
|
-
//
|
4213
|
-
// {
|
4214
|
-
// "total": 12,
|
4215
|
-
// "data": [
|
4216
|
-
// { /* ... model data ... */ },
|
4217
|
-
// { /* ... model data ... */ }
|
4218
|
-
// ]
|
4219
|
-
// }
|
4220
|
-
Tableling.Collection = Backbone.Collection.extend({
|
4221
|
-
|
4222
|
-
parse : function(response) {
|
4223
|
-
return response.data;
|
4135
|
+
|
4136
|
+
if (typeof(this.autoUpdate) == 'undefined') {
|
4137
|
+
this.autoUpdate = true;
|
4224
4138
|
}
|
4225
|
-
|
4226
|
-
|
4227
|
-
|
4228
|
-
|
4229
|
-
|
4230
|
-
|
4231
|
-
|
4232
|
-
|
4233
|
-
|
4234
|
-
// -----------------
|
4235
|
-
//
|
4236
|
-
// Tableling subclass which splits functionality into *modules*
|
4237
|
-
// and handles rendering.
|
4238
|
-
Tableling.Modular = Tableling.Table.extend({
|
4239
|
-
|
4240
|
-
// The list of module names must be specified by subclasses.
|
4241
|
-
modules : [],
|
4242
|
-
|
4243
|
-
// Modules are set up after rendering, before refreshing.
|
4244
|
-
setup : function() {
|
4245
|
-
|
4246
|
-
this.moduleViews = {};
|
4247
|
-
_.each(this.modules, _.bind(this.setupModule, this));
|
4248
|
-
|
4249
|
-
Tableling.Table.prototype.setup.call(this);
|
4250
|
-
},
|
4251
|
-
|
4252
|
-
// ### Modules
|
4253
|
-
// Each module is identified by a name, for example `pageSize`.
|
4254
|
-
setupModule : function(name) {
|
4255
|
-
|
4256
|
-
// The layout must have a region named after the module, e.g. `pageSizeRegion`.
|
4257
|
-
var region = name + 'Region';
|
4258
|
-
|
4259
|
-
// It must have a view class, e.g. `pageSizeView`, which will be shown into
|
4260
|
-
// the region.
|
4261
|
-
var viewClass = this[name + 'View'];
|
4262
|
-
|
4263
|
-
// When instantiated, the view class will be passed the event
|
4264
|
-
// aggregator as the `vent` option. Additional options can be
|
4265
|
-
// given named after the view class, e.g. `pageSizeViewOptions`.
|
4266
|
-
var options = _.extend(this.getModuleOptions(name), { vent: this.vent });
|
4267
|
-
|
4268
|
-
var view = new viewClass(options);
|
4269
|
-
|
4270
|
-
// Module view instances are stored by name in the `moduleViews` property
|
4271
|
-
// for future reference.
|
4272
|
-
this.moduleViews[name] = view;
|
4273
|
-
|
4274
|
-
this[region].show(view);
|
4275
|
-
return view;
|
4276
|
-
},
|
4277
|
-
|
4278
|
-
// By default the collection is the one given at construction.
|
4279
|
-
// Otherwise, a modular table expects a `table` module which
|
4280
|
-
// should have a collection (e.g. a Marionette CompositeView or
|
4281
|
-
// CollectionView). If your subclass does not have either, it
|
4282
|
-
// should override this method to return the Backbone.Collection
|
4283
|
-
// used to fetch table data.
|
4284
|
-
getCollection : function() {
|
4285
|
-
return this.collection || (this.moduleViews && this.moduleViews.table ? this.moduleViews.table.collection : undefined);
|
4286
|
-
},
|
4287
|
-
|
4288
|
-
getModuleOptions : function(name) {
|
4289
|
-
var options = this[name + 'ViewOptions'] || {};
|
4290
|
-
options = typeof(options) == 'function' ? options.call(this) : options;
|
4291
|
-
return name == 'table' ? _.defaults(options, { collection : this.collection }) : options;
|
4139
|
+
|
4140
|
+
// Components should trigger the `table:update` event to update
|
4141
|
+
// the table (e.g. change page size, sort) and fetch the new data.
|
4142
|
+
this.vent.on('table:update', this.onUpdate, this);
|
4143
|
+
|
4144
|
+
this.on('item:rendered', this.setup, this);
|
4145
|
+
|
4146
|
+
if (typeof(this.initializeTable) == 'function') {
|
4147
|
+
this.initializeTable(options);
|
4292
4148
|
}
|
4293
|
-
}
|
4294
|
-
|
4295
|
-
//
|
4296
|
-
|
4297
|
-
|
4298
|
-
|
4299
|
-
|
4300
|
-
// modules : [ 'pageSize' ],
|
4301
|
-
//
|
4302
|
-
// pageSizeView : PageSizeView,
|
4303
|
-
// pageSizeViewOptions : {
|
4304
|
-
// itemView : PageSizeItem
|
4305
|
-
// },
|
4306
|
-
//
|
4307
|
-
// regions : {
|
4308
|
-
// pageSizeRegion : '.pageSize'
|
4309
|
-
// }
|
4310
|
-
// });
|
4311
|
-
|
4312
|
-
// Tableling.Module
|
4313
|
-
// ----------------
|
4314
|
-
//
|
4315
|
-
// A module is an item view that is automatically bound to the table's
|
4316
|
-
// event aggregator.
|
4317
|
-
Tableling.Module = Backbone.Marionette.ItemView.extend({
|
4318
|
-
|
4319
|
-
i18n : {},
|
4320
|
-
templateHelpers : function() {
|
4321
|
-
return this.i18n;
|
4322
|
-
},
|
4323
|
-
|
4324
|
-
initialize : function(options) {
|
4325
|
-
|
4326
|
-
this.vent = options.vent;
|
4327
|
-
|
4328
|
-
// The `setup` method of the view is called when the table
|
4329
|
-
// is first set up.
|
4330
|
-
this.vent.on('table:setup', this.setup, this);
|
4331
|
-
|
4332
|
-
// The `refresh` method of the view is called every time the table
|
4333
|
-
// is refreshed.
|
4334
|
-
this.vent.on('table:refreshed', this.refresh, this);
|
4335
|
-
|
4336
|
-
this.i18n = _.clone(options.i18n || this.i18n);
|
4337
|
-
},
|
4338
|
-
|
4339
|
-
// Call `update` to trigger an update of the table.
|
4340
|
-
update : function() {
|
4341
|
-
this.vent.trigger('table:update', this.config());
|
4342
|
-
},
|
4343
|
-
|
4344
|
-
// Implementations should override this to set initial values.
|
4345
|
-
setup : function(config) {
|
4346
|
-
},
|
4347
|
-
|
4348
|
-
// Implementations should override this to stay up to date with
|
4349
|
-
// the table state.
|
4350
|
-
refresh : function(config) {
|
4351
|
-
},
|
4352
|
-
|
4353
|
-
// New table configuration to be sent on updates. For example,
|
4354
|
-
// a page size view might update the `pageSize` property.
|
4355
|
-
config : function() {
|
4356
|
-
return {};
|
4149
|
+
},
|
4150
|
+
|
4151
|
+
// Called once rendering is complete. By default, it updates the table.
|
4152
|
+
setup: function() {
|
4153
|
+
this.ventTrigger('table:setup', this.config);
|
4154
|
+
if (this.autoUpdate) {
|
4155
|
+
this.ventTrigger('table:update');
|
4357
4156
|
}
|
4358
|
-
}
|
4359
|
-
|
4360
|
-
//
|
4361
|
-
|
4362
|
-
|
4363
|
-
|
4364
|
-
|
4365
|
-
|
4366
|
-
|
4367
|
-
|
4368
|
-
|
4369
|
-
|
4370
|
-
|
4371
|
-
|
4372
|
-
|
4373
|
-
|
4374
|
-
|
4375
|
-
|
4376
|
-
|
4377
|
-
|
4378
|
-
this.ui.field = '[name="' + this.name + '"]';
|
4379
|
-
|
4380
|
-
if (!this.events) {
|
4381
|
-
this.events = {};
|
4382
|
-
}
|
4383
|
-
this.events.submit = 'onSubmit';
|
4384
|
-
this.events['change [name="' + this.name + '"]'] = 'update';
|
4385
|
-
},
|
4386
|
-
|
4387
|
-
setup : function(config) {
|
4388
|
-
this.setupValue(config[this.name]);
|
4389
|
-
this.vent.trigger('table:update', this.config(), { refresh : false });
|
4390
|
-
},
|
4391
|
-
|
4392
|
-
setupValue : function(value) {
|
4393
|
-
this.ui.field.val(value);
|
4394
|
-
},
|
4395
|
-
|
4396
|
-
// The table property updated is the one with the same name as the module.
|
4397
|
-
config : function() {
|
4398
|
-
var config = {};
|
4399
|
-
config[this.name] = this.ui.field.val();
|
4400
|
-
return config;
|
4401
|
-
},
|
4402
|
-
|
4403
|
-
onSubmit : function(e) {
|
4404
|
-
e.preventDefault();
|
4405
|
-
return false;
|
4157
|
+
},
|
4158
|
+
|
4159
|
+
// Subclasses must return the Backbone.Collection used to fetch data.
|
4160
|
+
getCollection: function() {
|
4161
|
+
return this.collection;
|
4162
|
+
},
|
4163
|
+
|
4164
|
+
// ### Refreshing the table
|
4165
|
+
update: function(config, options) {
|
4166
|
+
this.ventTrigger('table:update', config, options);
|
4167
|
+
},
|
4168
|
+
|
4169
|
+
onUpdate: function(config, options) {
|
4170
|
+
|
4171
|
+
_.each(config || {}, _.bind(this.updateValue, this));
|
4172
|
+
|
4173
|
+
// Set the `refresh` option to false to update the table configuration
|
4174
|
+
// without refreshing.
|
4175
|
+
if (!options || typeof(options.refresh) == 'undefined' || options.refresh) {
|
4176
|
+
this.refresh();
|
4406
4177
|
}
|
4407
|
-
}
|
4408
|
-
|
4409
|
-
|
4410
|
-
|
4411
|
-
|
4412
|
-
|
4413
|
-
|
4414
|
-
|
4415
|
-
// template : _.template(html)
|
4416
|
-
// });
|
4417
|
-
//
|
4418
|
-
// When the value of the input field changes, the event aggregator will
|
4419
|
-
// receive a `tableling:update` event with the `pageSize` property set
|
4420
|
-
// to that value.
|
4421
|
-
|
4422
|
-
Tableling.Plain = {};
|
4423
|
-
|
4424
|
-
Tableling.Plain.Table = Tableling.Modular.extend({
|
4425
|
-
|
4426
|
-
className: 'tableling',
|
4427
|
-
modules : [ 'table', 'pageSize', 'quickSearch', 'info', 'page' ],
|
4428
|
-
template : _.template('<div class="header"><div class="pageSize" /><div class="quickSearch" /></div><div class="table" /><div class="footer"><div class="info" /><div class="page" /></div>'),
|
4429
|
-
|
4430
|
-
regions : {
|
4431
|
-
tableRegion : '.table',
|
4432
|
-
pageSizeRegion : '.pageSize',
|
4433
|
-
quickSearchRegion : '.quickSearch',
|
4434
|
-
infoRegion : '.info',
|
4435
|
-
pageRegion : '.page'
|
4178
|
+
},
|
4179
|
+
|
4180
|
+
updateValue: function(value, key) {
|
4181
|
+
if (value && value.toString().length) {
|
4182
|
+
this.config[key] = value;
|
4183
|
+
} else {
|
4184
|
+
// Blank values are deleted to avoid sending them in ajax requests.
|
4185
|
+
delete this.config[key];
|
4436
4186
|
}
|
4437
|
-
}
|
4438
|
-
|
4439
|
-
|
4440
|
-
|
4441
|
-
|
4442
|
-
|
4443
|
-
|
4444
|
-
|
4445
|
-
|
4446
|
-
|
4447
|
-
|
4448
|
-
|
4449
|
-
|
4450
|
-
|
4451
|
-
|
4452
|
-
|
4453
|
-
|
4454
|
-
|
4455
|
-
|
4456
|
-
|
4457
|
-
|
4458
|
-
|
4459
|
-
|
4460
|
-
|
4461
|
-
|
4462
|
-
|
4463
|
-
|
4464
|
-
|
4465
|
-
|
4466
|
-
|
4467
|
-
|
4468
|
-
|
4469
|
-
|
4470
|
-
|
4471
|
-
|
4472
|
-
|
4473
|
-
|
4474
|
-
|
4475
|
-
|
4476
|
-
|
4477
|
-
|
4478
|
-
|
4479
|
-
|
4480
|
-
|
4481
|
-
|
4482
|
-
|
4483
|
-
|
4484
|
-
|
4485
|
-
|
4486
|
-
this.sort.push(field + ' asc');
|
4487
|
-
|
4488
|
-
this.showSort();
|
4489
|
-
|
4490
|
-
this.vent.trigger('table:update', this.config());
|
4491
|
-
},
|
4492
|
-
|
4493
|
-
setSort : function(config) {
|
4494
|
-
if (config && config.sort) {
|
4495
|
-
this.sort = config.sort.slice(0);
|
4496
|
-
this.showSort();
|
4497
|
-
}
|
4498
|
-
},
|
4499
|
-
|
4500
|
-
showSort : function() {
|
4501
|
-
|
4502
|
-
this.$el.find('thead th.sorting, thead th.sorting-asc, thead th.sorting-desc').removeClass('sorting sorting-asc sorting-desc').addClass('sorting');
|
4503
|
-
|
4504
|
-
for (var i = 0; i < this.sort.length; i++) {
|
4505
|
-
|
4506
|
-
var parts = this.sort[i].split(' ');
|
4507
|
-
var name = parts[0];
|
4508
|
-
var direction = parts[1];
|
4509
|
-
|
4510
|
-
field = this.$el.find('thead [data-field="' + name + '"]');
|
4511
|
-
if (!field.length) {
|
4512
|
-
field = this.$el.find('thead th:contains("' + name + '")');
|
4513
|
-
}
|
4514
|
-
|
4515
|
-
if (field.length) {
|
4516
|
-
field.removeClass('sorting').addClass(direction == 'desc' ? 'sorting-desc' : 'sorting-asc');
|
4517
|
-
}
|
4518
|
-
}
|
4519
|
-
},
|
4520
|
-
|
4521
|
-
config : function() {
|
4522
|
-
return {
|
4523
|
-
page : 1,
|
4524
|
-
sort : this.sortConfig()
|
4525
|
-
};
|
4526
|
-
},
|
4527
|
-
|
4528
|
-
sortConfig : function() {
|
4529
|
-
return this.sort.length ? this.sort : null;
|
4530
|
-
},
|
4531
|
-
|
4532
|
-
fieldName : function(el) {
|
4533
|
-
return el.data('field') || el.text();
|
4187
|
+
},
|
4188
|
+
|
4189
|
+
refresh: function() {
|
4190
|
+
|
4191
|
+
// You can provide `fetchOptions` to add properties to the
|
4192
|
+
// fetch request.
|
4193
|
+
//
|
4194
|
+
// var MyTable = Tableling.Table.extend({
|
4195
|
+
// fetchOptions: {
|
4196
|
+
// type: 'POST' // fetch data with POST
|
4197
|
+
// }
|
4198
|
+
// });
|
4199
|
+
//
|
4200
|
+
// // You can also override for each instance.
|
4201
|
+
// new MyTable({
|
4202
|
+
// fetchOptions: {
|
4203
|
+
// type: 'GET'
|
4204
|
+
// }
|
4205
|
+
// });
|
4206
|
+
var options = _.clone(this.fetchOptions);
|
4207
|
+
options.data = this.requestData();
|
4208
|
+
options.success = _.bind(this.processResponse, this);
|
4209
|
+
options.reset = true;
|
4210
|
+
|
4211
|
+
// `table:refreshing` is triggered every time new data is being fetched.
|
4212
|
+
// The first argument is the request data.
|
4213
|
+
this.ventTrigger('table:refreshing', options.data);
|
4214
|
+
|
4215
|
+
this.getCollection().fetch(options);
|
4216
|
+
},
|
4217
|
+
|
4218
|
+
// ### Request
|
4219
|
+
requestData: function() {
|
4220
|
+
return this.config;
|
4221
|
+
},
|
4222
|
+
|
4223
|
+
// ### Response
|
4224
|
+
processResponse: function(collection, response) {
|
4225
|
+
|
4226
|
+
this.config.length = collection.length;
|
4227
|
+
|
4228
|
+
// Tableling expects the response from a fetch to have a `total` property
|
4229
|
+
// which is the total number of items (not just in the current page).
|
4230
|
+
this.config.total = response.total;
|
4231
|
+
|
4232
|
+
// The server may override the `page` property, for example if the
|
4233
|
+
// requested page was outside the range of available pages.
|
4234
|
+
if (response.page) {
|
4235
|
+
this.config.page = response.page;
|
4534
4236
|
}
|
4535
|
-
|
4536
|
-
|
4537
|
-
|
4538
|
-
|
4539
|
-
//
|
4540
|
-
|
4541
|
-
|
4542
|
-
|
4543
|
-
|
4544
|
-
|
4545
|
-
|
4546
|
-
|
4547
|
-
|
4548
|
-
|
4549
|
-
|
4550
|
-
|
4551
|
-
field : 'select'
|
4552
|
-
},
|
4553
|
-
|
4554
|
-
initialize : function(options) {
|
4555
|
-
Tableling.FieldModule.prototype.initialize.call(this, options);
|
4556
|
-
this.sizes = _.clone(options.sizes || this.sizes);
|
4557
|
-
},
|
4558
|
-
|
4559
|
-
onRender : function() {
|
4560
|
-
this.ui.field.empty();
|
4561
|
-
_.each(this.sizes, _.bind(this.addSize, this));
|
4562
|
-
},
|
4563
|
-
|
4564
|
-
addSize : function(size) {
|
4565
|
-
$('<option />').text(size).appendTo(this.ui.field);
|
4566
|
-
},
|
4567
|
-
|
4568
|
-
setupValue : function(value) {
|
4569
|
-
if (value) {
|
4570
|
-
Tableling.FieldModule.prototype.setupValue.apply(this, Array.prototype.slice.call(arguments));
|
4571
|
-
}
|
4572
|
-
},
|
4573
|
-
|
4574
|
-
config : function() {
|
4575
|
-
var config = Tableling.FieldModule.prototype.config.call(this);
|
4576
|
-
config.page = 1;
|
4577
|
-
return config;
|
4237
|
+
|
4238
|
+
// `tableling:refreshed` is triggered after every refresh. The first argument
|
4239
|
+
// is the current table configuration with the following additional meta data:
|
4240
|
+
//
|
4241
|
+
// * `total` - the total number of items
|
4242
|
+
// * `length` - the number of items in the current page
|
4243
|
+
this.ventTrigger('table:refreshed', this.config);
|
4244
|
+
},
|
4245
|
+
|
4246
|
+
// Triggers an event in the event aggregator. If `Tableling.debug` is set, it also
|
4247
|
+
// logs the event and its arguments.
|
4248
|
+
ventTrigger: function() {
|
4249
|
+
|
4250
|
+
var args = Array.prototype.slice.call(arguments);
|
4251
|
+
if (Tableling.debug) {
|
4252
|
+
console.log(_.first(args) + ' - ' + JSON.stringify(args.slice(1)));
|
4578
4253
|
}
|
4579
|
-
|
4580
|
-
|
4581
|
-
|
4582
|
-
|
4583
|
-
|
4584
|
-
|
4585
|
-
|
4586
|
-
|
4587
|
-
|
4588
|
-
|
4589
|
-
|
4590
|
-
|
4591
|
-
|
4592
|
-
|
4593
|
-
|
4594
|
-
|
4595
|
-
|
4254
|
+
|
4255
|
+
this.vent.trigger.apply(this.vent, args);
|
4256
|
+
}
|
4257
|
+
});
|
4258
|
+
|
4259
|
+
// Tableling.Collection
|
4260
|
+
// --------------------
|
4261
|
+
//
|
4262
|
+
// Tableling expects fetch responses to have a `total` property in addition
|
4263
|
+
// to the model data. You can extend this Backbone.Collection subclass which
|
4264
|
+
// expects the following response format:
|
4265
|
+
//
|
4266
|
+
// {
|
4267
|
+
// "total": 12,
|
4268
|
+
// "data": [
|
4269
|
+
// { /* ... model data ... */ },
|
4270
|
+
// { /* ... model data ... */ }
|
4271
|
+
// ]
|
4272
|
+
// }
|
4273
|
+
Tableling.Collection = Backbone.Collection.extend({
|
4274
|
+
|
4275
|
+
parse: function(response) {
|
4276
|
+
return response.data;
|
4277
|
+
}
|
4278
|
+
});
|
4279
|
+
|
4280
|
+
// Implementations
|
4281
|
+
// ---------------
|
4282
|
+
//
|
4283
|
+
// <a href="tableling.bootstrap.html">tableling.bootstrap</a> provides views styled
|
4284
|
+
// with [Twitter Bootstrap](http://twitter.github.com/bootstrap/) classes.
|
4285
|
+
|
4286
|
+
// Tableling.Modular
|
4287
|
+
// -----------------
|
4288
|
+
//
|
4289
|
+
// Tableling subclass which splits functionality into *modules*
|
4290
|
+
// and handles rendering.
|
4291
|
+
Tableling.Modular = Tableling.Table.extend({
|
4292
|
+
|
4293
|
+
// The list of module names must be specified by subclasses.
|
4294
|
+
modules: [],
|
4295
|
+
|
4296
|
+
// Modules are set up after rendering, before refreshing.
|
4297
|
+
setup: function() {
|
4298
|
+
|
4299
|
+
this.moduleViews = {};
|
4300
|
+
_.each(this.modules, this.setupModule, this);
|
4301
|
+
|
4302
|
+
Tableling.Table.prototype.setup.call(this);
|
4303
|
+
},
|
4304
|
+
|
4305
|
+
// ### Modules
|
4306
|
+
// Each module is identified by a name, for example `pageSize`.
|
4307
|
+
setupModule: function(name) {
|
4308
|
+
|
4309
|
+
// The layout must have a region named after the module, e.g. `pageSizeRegion`.
|
4310
|
+
var region = name + 'Region';
|
4311
|
+
|
4312
|
+
// It must have a view class, e.g. `pageSizeView`, which will be shown into
|
4313
|
+
// the region.
|
4314
|
+
var viewClass = this[name + 'View'];
|
4315
|
+
|
4316
|
+
// When instantiated, the view class will be passed the event
|
4317
|
+
// aggregator as the `vent` option. Additional options can be
|
4318
|
+
// given named after the view class, e.g. `pageSizeViewOptions`.
|
4319
|
+
var options = _.extend(this.getModuleOptions(name), { vent: this.vent });
|
4320
|
+
|
4321
|
+
// The collection is also passed to view classes.
|
4322
|
+
_.defaults(options, { collection: this.getCollection() });
|
4323
|
+
|
4324
|
+
var view = new viewClass(options);
|
4325
|
+
|
4326
|
+
// Module view instances are stored by name in the `moduleViews` property
|
4327
|
+
// for future reference.
|
4328
|
+
this.moduleViews[name] = view;
|
4329
|
+
|
4330
|
+
this[region].show(view);
|
4331
|
+
return view;
|
4332
|
+
},
|
4333
|
+
|
4334
|
+
// By default the collection is the one given at construction.
|
4335
|
+
// Otherwise, a modular table expects a `table` module which
|
4336
|
+
// should have a collection (e.g. a Marionette CompositeView or
|
4337
|
+
// CollectionView). If your subclass does not have either, it
|
4338
|
+
// should override this method to return the Backbone.Collection
|
4339
|
+
// used to fetch table data.
|
4340
|
+
getCollection: function() {
|
4341
|
+
return this.collection || (this.moduleViews && this.moduleViews.table ? this.moduleViews.table.collection : undefined);
|
4342
|
+
},
|
4343
|
+
|
4344
|
+
getModuleOptions: function(name) {
|
4345
|
+
return _.result(this, name + 'ViewOptions') || {};
|
4346
|
+
}
|
4347
|
+
});
|
4348
|
+
|
4349
|
+
// ### Example
|
4350
|
+
// This is how a `PageSizeView` module might be registered in a subclass:
|
4351
|
+
//
|
4352
|
+
// var MyTable = Tableling.Modular.extend({
|
4353
|
+
//
|
4354
|
+
// modules: [ 'pageSize' ],
|
4355
|
+
//
|
4356
|
+
// pageSizeView: PageSizeView,
|
4357
|
+
// pageSizeViewOptions: {
|
4358
|
+
// itemView: PageSizeItem
|
4359
|
+
// },
|
4360
|
+
//
|
4361
|
+
// regions: {
|
4362
|
+
// pageSizeRegion: '.pageSize'
|
4363
|
+
// }
|
4364
|
+
// });
|
4365
|
+
|
4366
|
+
// Tableling.Module
|
4367
|
+
// ----------------
|
4368
|
+
//
|
4369
|
+
// A module is an item view that is automatically bound to the table's
|
4370
|
+
// event aggregator.
|
4371
|
+
Tableling.Module = Backbone.Marionette.ItemView.extend({
|
4372
|
+
|
4373
|
+
i18n: {},
|
4374
|
+
templateHelpers: function() {
|
4375
|
+
return this.i18n;
|
4376
|
+
},
|
4377
|
+
|
4378
|
+
initialize: function(options) {
|
4379
|
+
|
4380
|
+
this.vent = options.vent;
|
4381
|
+
|
4382
|
+
// The `setup` method of the view is called when the table
|
4383
|
+
// is first set up.
|
4384
|
+
this.vent.on('table:setup', this.setup, this);
|
4385
|
+
|
4386
|
+
// The `refresh` method of the view is called every time the table
|
4387
|
+
// is refreshed.
|
4388
|
+
this.vent.on('table:refreshed', this.refresh, this);
|
4389
|
+
|
4390
|
+
this.i18n = _.clone(options.i18n || this.i18n);
|
4391
|
+
|
4392
|
+
if (typeof(this.initializeModule) == 'function') {
|
4393
|
+
this.initializeModule(options);
|
4596
4394
|
}
|
4597
|
-
}
|
4598
|
-
|
4599
|
-
|
4600
|
-
|
4601
|
-
|
4602
|
-
|
4603
|
-
|
4604
|
-
|
4605
|
-
|
4395
|
+
},
|
4396
|
+
|
4397
|
+
// Call `update` to trigger an update of the table.
|
4398
|
+
update: function() {
|
4399
|
+
this.vent.trigger('table:update', this.config());
|
4400
|
+
},
|
4401
|
+
|
4402
|
+
// Implementations should override this to set initial values.
|
4403
|
+
setup: function(config) {
|
4404
|
+
},
|
4405
|
+
|
4406
|
+
// Implementations should override this to stay up to date with
|
4407
|
+
// the table state.
|
4408
|
+
refresh: function(config) {
|
4409
|
+
},
|
4410
|
+
|
4411
|
+
// New table configuration to be sent on updates. For example,
|
4412
|
+
// a page size view might update the `pageSize` property.
|
4413
|
+
config: function() {
|
4414
|
+
return {};
|
4415
|
+
}
|
4416
|
+
});
|
4417
|
+
|
4418
|
+
// Tableling.FieldModule
|
4419
|
+
// ---------------------
|
4420
|
+
//
|
4421
|
+
// A basic module with a single form field. It comes with sensible
|
4422
|
+
// defaults and only requires a `name` and a `template` parameter.
|
4423
|
+
Tableling.FieldModule = Tableling.Module.extend({
|
4424
|
+
|
4425
|
+
initialize: function(options) {
|
4426
|
+
if (!_.isString(this.name)) {
|
4427
|
+
throw new Error("Tableling module must have a name property.");
|
4428
|
+
}
|
4429
|
+
|
4430
|
+
if (!this.ui) {
|
4431
|
+
this.ui = {};
|
4432
|
+
}
|
4433
|
+
// The name attribute of the form field is the same as the
|
4434
|
+
// module's, e.g. `pageSize`.
|
4435
|
+
this.ui.field = '[name="' + this.name + '"]';
|
4436
|
+
|
4437
|
+
if (!this.events) {
|
4438
|
+
this.events = {};
|
4439
|
+
}
|
4440
|
+
this.events.submit = 'onSubmit';
|
4441
|
+
this.events['change [name="' + this.name + '"]'] = 'update';
|
4442
|
+
|
4443
|
+
Tableling.Module.prototype.initialize.call(this, options);
|
4444
|
+
},
|
4445
|
+
|
4446
|
+
setup: function(config) {
|
4447
|
+
this.setupValue(config[this.name]);
|
4448
|
+
this.vent.trigger('table:update', this.config(), { refresh: false });
|
4449
|
+
},
|
4450
|
+
|
4451
|
+
setupValue: function(value) {
|
4452
|
+
this.ui.field.val(value);
|
4453
|
+
},
|
4454
|
+
|
4455
|
+
// The table property updated is the one with the same name as the module.
|
4456
|
+
config: function() {
|
4457
|
+
var config = {};
|
4458
|
+
config[this.name] = this.ui.field.val();
|
4459
|
+
return config;
|
4460
|
+
},
|
4461
|
+
|
4462
|
+
onSubmit: function(e) {
|
4463
|
+
e.preventDefault();
|
4464
|
+
return false;
|
4465
|
+
}
|
4466
|
+
});
|
4467
|
+
|
4468
|
+
// This is how a `PageSizeView` module might be implemented:
|
4469
|
+
//
|
4470
|
+
// var html = '<input type="text" name="pageSize" />';
|
4471
|
+
//
|
4472
|
+
// var PageSizeView = Tableling.FieldModule.extend({
|
4473
|
+
// name: 'pageSize'
|
4474
|
+
// template: _.template(html)
|
4475
|
+
// });
|
4476
|
+
//
|
4477
|
+
// When the value of the input field changes, the event aggregator will
|
4478
|
+
// receive a `tableling:update` event with the `pageSize` property set
|
4479
|
+
// to that value.
|
4480
|
+
|
4481
|
+
Tableling.Plain = {};
|
4482
|
+
|
4483
|
+
Tableling.Plain.Table = Tableling.Modular.extend({
|
4484
|
+
|
4485
|
+
className: 'tableling',
|
4486
|
+
modules: [ 'table', 'pageSize', 'quickSearch', 'info', 'page' ],
|
4487
|
+
template: _.template('<div class="header"><div class="pageSize" /><div class="quickSearch" /></div><div class="table" /><div class="footer"><div class="info" /><div class="page" /></div>'),
|
4488
|
+
|
4489
|
+
regions: {
|
4490
|
+
tableRegion: '.table',
|
4491
|
+
pageSizeRegion: '.pageSize',
|
4492
|
+
quickSearchRegion: '.quickSearch',
|
4493
|
+
infoRegion: '.info',
|
4494
|
+
pageRegion: '.page'
|
4495
|
+
}
|
4496
|
+
});
|
4497
|
+
|
4498
|
+
// TODO: make table view a module
|
4499
|
+
Tableling.Plain.TableView = Backbone.Marionette.CompositeView.extend({
|
4500
|
+
|
4501
|
+
moduleEvents: {
|
4502
|
+
'click thead th.sorting': 'updateSort',
|
4503
|
+
'click thead th.sorting-asc': 'updateSort',
|
4504
|
+
'click thead th.sorting-desc': 'updateSort'
|
4505
|
+
},
|
4506
|
+
|
4507
|
+
// TODO: add auto-sort
|
4508
|
+
initialize: function(options) {
|
4509
|
+
|
4510
|
+
this.vent = options.vent;
|
4511
|
+
this.sort = [];
|
4512
|
+
this.vent.on('table:setup', this.setSort, this);
|
4513
|
+
this.vent.on('table:refreshed', this.setSort, this);
|
4514
|
+
this.events = _.extend({}, this.events || {}, this.moduleEvents);
|
4515
|
+
|
4516
|
+
if (typeof(this.initializeModule) == 'function') {
|
4517
|
+
this.initializeModule(options);
|
4518
|
+
}
|
4519
|
+
},
|
4520
|
+
|
4521
|
+
updateSort: function(ev) {
|
4522
|
+
|
4523
|
+
var el = $(ev.currentTarget);
|
4524
|
+
if (!(el.hasClass('sorting') || el.hasClass('sorting-asc') || el.hasClass('sorting-desc'))) {
|
4525
|
+
return;
|
4526
|
+
}
|
4527
|
+
|
4528
|
+
var field = this.fieldName(el);
|
4529
|
+
|
4530
|
+
if (ev.shiftKey || this.sort.length == 1) {
|
4531
|
+
|
4532
|
+
var index = -1;
|
4533
|
+
_.find(this.sort, function(item, i) {
|
4534
|
+
if (item.split(' ')[0] == field) {
|
4535
|
+
index = i;
|
4536
|
+
}
|
4606
4537
|
});
|
4607
|
-
|
4608
|
-
|
4609
|
-
|
4610
|
-
|
4611
|
-
|
4612
|
-
|
4613
|
-
|
4614
|
-
first: '.first',
|
4615
|
-
last: '.last',
|
4616
|
-
total: '.total'
|
4617
|
-
},
|
4618
|
-
|
4619
|
-
refresh : function(data) {
|
4620
|
-
if (data) {
|
4621
|
-
this.ui.first.text(this.firstRecord(data));
|
4622
|
-
this.ui.last.text(this.lastRecord(data));
|
4623
|
-
this.ui.total.text(data.total);
|
4538
|
+
|
4539
|
+
if (index >= 0) {
|
4540
|
+
|
4541
|
+
var parts = this.sort[index].split(' ');
|
4542
|
+
this.sort[index] = parts[0] + ' ' + (parts[1] == 'asc' ? 'desc' : 'asc');
|
4543
|
+
this.showSort();
|
4544
|
+
return this.vent.trigger('table:update', this.config());
|
4624
4545
|
}
|
4625
|
-
},
|
4626
|
-
|
4627
|
-
firstRecord : function(data) {
|
4628
|
-
return data.length ? ((data.page || 1) - 1) * data.pageSize + 1 : 0;
|
4629
|
-
},
|
4630
|
-
|
4631
|
-
lastRecord : function(data) {
|
4632
|
-
return data.length ? this.firstRecord(data) + data.length - 1 : 0;
|
4633
4546
|
}
|
4634
|
-
|
4635
|
-
|
4636
|
-
|
4547
|
+
|
4548
|
+
if (!ev.shiftKey) {
|
4549
|
+
this.sort.length = 0;
|
4550
|
+
}
|
4551
|
+
|
4552
|
+
this.sort.push(field + ' asc');
|
4553
|
+
|
4554
|
+
this.showSort();
|
4555
|
+
|
4556
|
+
this.vent.trigger('table:update', this.config());
|
4557
|
+
},
|
4558
|
+
|
4559
|
+
setSort: function(config) {
|
4560
|
+
if (config && config.sort) {
|
4561
|
+
this.sort = config.sort.slice(0);
|
4562
|
+
this.showSort();
|
4563
|
+
}
|
4564
|
+
},
|
4565
|
+
|
4566
|
+
showSort: function() {
|
4567
|
+
|
4568
|
+
this.$el.find('thead th.sorting, thead th.sorting-asc, thead th.sorting-desc').removeClass('sorting sorting-asc sorting-desc').addClass('sorting');
|
4569
|
+
|
4570
|
+
for (var i = 0; i < this.sort.length; i++) {
|
4571
|
+
|
4572
|
+
var parts = this.sort[i].split(' ');
|
4573
|
+
var name = parts[0];
|
4574
|
+
var direction = parts[1];
|
4637
4575
|
|
4638
|
-
|
4639
|
-
|
4640
|
-
|
4641
|
-
ui : {
|
4642
|
-
first : '.first',
|
4643
|
-
previous : '.previous',
|
4644
|
-
next : '.next',
|
4645
|
-
last : '.last'
|
4646
|
-
},
|
4647
|
-
|
4648
|
-
events : {
|
4649
|
-
'click .first:not(.disabled)' : 'goToFirstPage',
|
4650
|
-
'click .previous:not(.disabled)' : 'goToPreviousPage',
|
4651
|
-
'click .page:not(.disabled)' : 'goToPage',
|
4652
|
-
'click .next:not(.disabled)' : 'goToNextPage',
|
4653
|
-
'click .last:not(.disabled)' : 'goToLastPage'
|
4654
|
-
},
|
4655
|
-
|
4656
|
-
refresh : function(data) {
|
4657
|
-
this.$el.find('.page').remove();
|
4658
|
-
if (!data || !data.length) {
|
4659
|
-
this.ui.first.addClass('disabled');
|
4660
|
-
this.ui.previous.addClass('disabled');
|
4661
|
-
this.ui.next.addClass('disabled');
|
4662
|
-
this.ui.last.addClass('disabled');
|
4663
|
-
} else {
|
4664
|
-
this.data = data;
|
4665
|
-
this.enable(this.ui.first, this.getPage(data) > 1);
|
4666
|
-
this.enable(this.ui.previous, this.getPage(data) > 1);
|
4667
|
-
this.setupPages();
|
4668
|
-
this.enable(this.ui.next, this.getPage(data) < this.numberOfPages(data));
|
4669
|
-
this.enable(this.ui.last, this.getPage(data) < this.numberOfPages(data));
|
4670
|
-
}
|
4671
|
-
},
|
4672
|
-
|
4673
|
-
setupPages : function() {
|
4674
|
-
|
4675
|
-
var page = this.getPage(this.data);
|
4676
|
-
var total = this.numberOfPages();
|
4677
|
-
|
4678
|
-
var first = page - 2;
|
4679
|
-
if (total - first < 4) {
|
4680
|
-
first = total - 4;
|
4681
|
-
}
|
4682
|
-
|
4683
|
-
if (first < 1) {
|
4684
|
-
first = 1;
|
4576
|
+
field = this.$el.find('thead [data-field="' + name + '"]');
|
4577
|
+
if (!field.length) {
|
4578
|
+
field = this.$el.find('thead th:contains("' + name + '")');
|
4685
4579
|
}
|
4686
|
-
|
4687
|
-
|
4688
|
-
|
4689
|
-
n = total - first + 1;
|
4690
|
-
}
|
4691
|
-
|
4692
|
-
_.times(n, function(i) {
|
4693
|
-
$(this.pageTemplate({ number : first + i })).insertBefore(this.ui.next);
|
4694
|
-
}, this);
|
4695
|
-
|
4696
|
-
var i = page - first;
|
4697
|
-
this.$el.find('.page').slice(i, i + 1).addClass('disabled');
|
4698
|
-
},
|
4699
|
-
|
4700
|
-
enable : function(el, enabled) {
|
4701
|
-
el.removeClass('disabled');
|
4702
|
-
if (!enabled) {
|
4703
|
-
el.addClass('disabled');
|
4580
|
+
|
4581
|
+
if (field.length) {
|
4582
|
+
field.removeClass('sorting').addClass(direction == 'desc' ? 'sorting-desc' : 'sorting-asc');
|
4704
4583
|
}
|
4705
|
-
},
|
4706
|
-
|
4707
|
-
numberOfPages : function() {
|
4708
|
-
return Math.ceil(this.data.total / this.data.pageSize);
|
4709
|
-
},
|
4710
|
-
|
4711
|
-
goToFirstPage : function(e) {
|
4712
|
-
e.preventDefault();
|
4713
|
-
this.goToPageNumber(1);
|
4714
|
-
},
|
4715
|
-
|
4716
|
-
goToPreviousPage : function(e) {
|
4717
|
-
e.preventDefault();
|
4718
|
-
this.goToPageNumber(this.getPage(this.data) - 1);
|
4719
|
-
},
|
4720
|
-
|
4721
|
-
goToPage : function(e) {
|
4722
|
-
e.preventDefault();
|
4723
|
-
this.goToPageNumber(parseInt($(e.target).text(), 10));
|
4724
|
-
},
|
4725
|
-
|
4726
|
-
goToNextPage : function(e) {
|
4727
|
-
e.preventDefault();
|
4728
|
-
this.goToPageNumber(this.getPage(this.data) + 1);
|
4729
|
-
},
|
4730
|
-
|
4731
|
-
goToLastPage : function(e) {
|
4732
|
-
e.preventDefault();
|
4733
|
-
this.goToPageNumber(this.numberOfPages());
|
4734
|
-
},
|
4735
|
-
|
4736
|
-
goToPageNumber : function(n) {
|
4737
|
-
this.vent.trigger('table:update', { page : n });
|
4738
|
-
},
|
4739
|
-
|
4740
|
-
getPage : function(data) {
|
4741
|
-
return data.page || 1;
|
4742
4584
|
}
|
4743
|
-
}
|
4744
|
-
|
4745
|
-
|
4746
|
-
|
4747
|
-
|
4748
|
-
|
4749
|
-
|
4750
|
-
|
4751
|
-
|
4752
|
-
|
4753
|
-
|
4754
|
-
|
4755
|
-
|
4756
|
-
|
4757
|
-
|
4758
|
-
|
4759
|
-
|
4760
|
-
|
4761
|
-
|
4585
|
+
},
|
4586
|
+
|
4587
|
+
config: function() {
|
4588
|
+
return {
|
4589
|
+
page: 1,
|
4590
|
+
sort: this.sortConfig()
|
4591
|
+
};
|
4592
|
+
},
|
4593
|
+
|
4594
|
+
sortConfig: function() {
|
4595
|
+
return this.sort.length ? this.sort : null;
|
4596
|
+
},
|
4597
|
+
|
4598
|
+
fieldName: function(el) {
|
4599
|
+
return el.data('field') || el.text();
|
4600
|
+
}
|
4601
|
+
});
|
4602
|
+
|
4603
|
+
Tableling.Plain.PageSizeView = Tableling.Plain.Table.prototype.pageSizeView = Tableling.FieldModule.extend({
|
4604
|
+
|
4605
|
+
// TODO: update current page intelligently
|
4606
|
+
name: 'pageSize',
|
4607
|
+
template: function(data) {
|
4608
|
+
return _.template('<select name="pageSize" /> <%- entries %>', data);
|
4609
|
+
},
|
4610
|
+
|
4611
|
+
i18n: {
|
4612
|
+
entries: 'entries per page'
|
4613
|
+
},
|
4614
|
+
sizes: [ 10, 15, 20, 25, 50 ],
|
4615
|
+
|
4616
|
+
ui: {
|
4617
|
+
field: 'select'
|
4618
|
+
},
|
4619
|
+
|
4620
|
+
initialize: function(options) {
|
4621
|
+
this.sizes = _.clone(options.sizes || this.sizes);
|
4622
|
+
Tableling.FieldModule.prototype.initialize.call(this, options);
|
4623
|
+
},
|
4624
|
+
|
4625
|
+
onRender: function() {
|
4626
|
+
this.ui.field.empty();
|
4627
|
+
_.each(this.sizes, _.bind(this.addSize, this));
|
4628
|
+
},
|
4629
|
+
|
4630
|
+
addSize: function(size) {
|
4631
|
+
$('<option />').text(size).appendTo(this.ui.field);
|
4632
|
+
},
|
4633
|
+
|
4634
|
+
setupValue: function(value) {
|
4635
|
+
if (value) {
|
4636
|
+
Tableling.FieldModule.prototype.setupValue.apply(this, Array.prototype.slice.call(arguments));
|
4762
4637
|
}
|
4763
|
-
}
|
4764
|
-
|
4765
|
-
|
4766
|
-
|
4767
|
-
|
4768
|
-
|
4769
|
-
|
4770
|
-
|
4771
|
-
|
4772
|
-
|
4773
|
-
|
4638
|
+
},
|
4639
|
+
|
4640
|
+
config: function() {
|
4641
|
+
var config = Tableling.FieldModule.prototype.config.call(this);
|
4642
|
+
config.page = 1;
|
4643
|
+
return config;
|
4644
|
+
}
|
4645
|
+
});
|
4646
|
+
|
4647
|
+
Tableling.Plain.QuickSearchView = Tableling.Plain.Table.prototype.quickSearchView = Tableling.FieldModule.extend({
|
4648
|
+
|
4649
|
+
name: 'quickSearch',
|
4650
|
+
template: function(data) {
|
4651
|
+
return _.template('<input type="text" name="quickSearch" placeholder="<%- quickSearch %>" />', data);
|
4652
|
+
},
|
4653
|
+
|
4654
|
+
i18n: {
|
4655
|
+
quickSearch: 'Quick search...'
|
4656
|
+
},
|
4657
|
+
|
4658
|
+
config: function() {
|
4659
|
+
var config = Tableling.FieldModule.prototype.config.call(this);
|
4660
|
+
config.page = 1;
|
4661
|
+
return config;
|
4662
|
+
}
|
4663
|
+
});
|
4664
|
+
|
4665
|
+
Tableling.Plain.InfoView = Tableling.Plain.Table.prototype.infoView = Tableling.Module.extend({
|
4666
|
+
|
4667
|
+
template: function(data) {
|
4668
|
+
return _.template(data.template, {
|
4669
|
+
first: '<span class="first">0</span>',
|
4670
|
+
last: '<span class="last">0</span>',
|
4671
|
+
total: '<span class="total">0</span>'
|
4672
|
+
});
|
4673
|
+
},
|
4674
|
+
|
4675
|
+
i18n: {
|
4676
|
+
template: 'Showing <%= first %> to <%= last %> of <%= total %> entries'
|
4677
|
+
},
|
4678
|
+
|
4679
|
+
ui: {
|
4680
|
+
first: '.first',
|
4681
|
+
last: '.last',
|
4682
|
+
total: '.total'
|
4683
|
+
},
|
4684
|
+
|
4685
|
+
refresh: function(data) {
|
4686
|
+
if (data) {
|
4687
|
+
this.ui.first.text(this.firstRecord(data));
|
4688
|
+
this.ui.last.text(this.lastRecord(data));
|
4689
|
+
this.ui.total.text(data.total);
|
4774
4690
|
}
|
4775
|
-
}
|
4776
|
-
|
4777
|
-
|
4778
|
-
|
4779
|
-
|
4780
|
-
|
4691
|
+
},
|
4692
|
+
|
4693
|
+
firstRecord: function(data) {
|
4694
|
+
return data.length ? ((data.page || 1) - 1) * data.pageSize + 1 : 0;
|
4695
|
+
},
|
4696
|
+
|
4697
|
+
lastRecord: function(data) {
|
4698
|
+
return data.length ? this.firstRecord(data) + data.length - 1 : 0;
|
4699
|
+
}
|
4700
|
+
});
|
4701
|
+
|
4702
|
+
Tableling.Plain.PageView = Tableling.Plain.Table.prototype.pageView = Tableling.Module.extend({
|
4703
|
+
|
4704
|
+
template: _.template('<ul class="pagination"><li class="first"><a href="#"><<</a></li><li class="previous"><a href="#"><</a></li><li class="next"><a href="#">></a></li><li class="last"><a href="#">>></a></li></ul>'),
|
4705
|
+
pageTemplate: _.template('<li class="page"><a href="#"><%- number %></a></li>'),
|
4706
|
+
|
4707
|
+
ui: {
|
4708
|
+
first: '.first',
|
4709
|
+
previous: '.previous',
|
4710
|
+
next: '.next',
|
4711
|
+
last: '.last'
|
4712
|
+
},
|
4713
|
+
|
4714
|
+
events: {
|
4715
|
+
'click .first:not(.disabled)': 'goToFirstPage',
|
4716
|
+
'click .previous:not(.disabled)': 'goToPreviousPage',
|
4717
|
+
'click .page:not(.disabled)': 'goToPage',
|
4718
|
+
'click .next:not(.disabled)': 'goToNextPage',
|
4719
|
+
'click .last:not(.disabled)': 'goToLastPage'
|
4720
|
+
},
|
4721
|
+
|
4722
|
+
refresh: function(data) {
|
4723
|
+
this.$el.find('.page').remove();
|
4724
|
+
if (!data || !data.length) {
|
4725
|
+
this.ui.first.addClass('disabled');
|
4726
|
+
this.ui.previous.addClass('disabled');
|
4727
|
+
this.ui.next.addClass('disabled');
|
4728
|
+
this.ui.last.addClass('disabled');
|
4729
|
+
} else {
|
4730
|
+
this.data = data;
|
4731
|
+
this.enable(this.ui.first, this.getPage(data) > 1);
|
4732
|
+
this.enable(this.ui.previous, this.getPage(data) > 1);
|
4733
|
+
this.setupPages();
|
4734
|
+
this.enable(this.ui.next, this.getPage(data) < this.numberOfPages(data));
|
4735
|
+
this.enable(this.ui.last, this.getPage(data) < this.numberOfPages(data));
|
4736
|
+
}
|
4737
|
+
},
|
4738
|
+
|
4739
|
+
setupPages: function() {
|
4740
|
+
|
4741
|
+
var page = this.getPage(this.data);
|
4742
|
+
var total = this.numberOfPages();
|
4743
|
+
|
4744
|
+
var first = page - 2;
|
4745
|
+
if (total - first < 4) {
|
4746
|
+
first = total - 4;
|
4747
|
+
}
|
4748
|
+
|
4749
|
+
if (first < 1) {
|
4750
|
+
first = 1;
|
4751
|
+
}
|
4752
|
+
|
4753
|
+
var n = 5;
|
4754
|
+
if (first + n - 1 > total) {
|
4755
|
+
n = total - first + 1;
|
4756
|
+
}
|
4757
|
+
|
4758
|
+
_.times(n, function(i) {
|
4759
|
+
$(this.pageTemplate({ number: first + i })).insertBefore(this.ui.next);
|
4760
|
+
}, this);
|
4761
|
+
|
4762
|
+
var i = page - first;
|
4763
|
+
this.$el.find('.page').slice(i, i + 1).addClass('disabled');
|
4764
|
+
},
|
4765
|
+
|
4766
|
+
enable: function(el, enabled) {
|
4767
|
+
el.removeClass('disabled');
|
4768
|
+
if (!enabled) {
|
4769
|
+
el.addClass('disabled');
|
4770
|
+
}
|
4771
|
+
},
|
4772
|
+
|
4773
|
+
numberOfPages: function() {
|
4774
|
+
return Math.ceil(this.data.total / this.data.pageSize);
|
4775
|
+
},
|
4776
|
+
|
4777
|
+
goToFirstPage: function(e) {
|
4778
|
+
e.preventDefault();
|
4779
|
+
this.goToPageNumber(1);
|
4780
|
+
},
|
4781
|
+
|
4782
|
+
goToPreviousPage: function(e) {
|
4783
|
+
e.preventDefault();
|
4784
|
+
this.goToPageNumber(this.getPage(this.data) - 1);
|
4785
|
+
},
|
4786
|
+
|
4787
|
+
goToPage: function(e) {
|
4788
|
+
e.preventDefault();
|
4789
|
+
this.goToPageNumber(parseInt($(e.target).text(), 10));
|
4790
|
+
},
|
4791
|
+
|
4792
|
+
goToNextPage: function(e) {
|
4793
|
+
e.preventDefault();
|
4794
|
+
this.goToPageNumber(this.getPage(this.data) + 1);
|
4795
|
+
},
|
4796
|
+
|
4797
|
+
goToLastPage: function(e) {
|
4798
|
+
e.preventDefault();
|
4799
|
+
this.goToPageNumber(this.numberOfPages());
|
4800
|
+
},
|
4801
|
+
|
4802
|
+
goToPageNumber: function(n) {
|
4803
|
+
this.vent.trigger('table:update', { page: n });
|
4804
|
+
},
|
4805
|
+
|
4806
|
+
getPage: function(data) {
|
4807
|
+
return data.page || 1;
|
4808
|
+
}
|
4809
|
+
});
|
4810
|
+
|
4811
|
+
Tableling.Bootstrap = {};
|
4812
|
+
|
4813
|
+
Tableling.Bootstrap.Table = Tableling.Plain.Table.extend({
|
4814
|
+
template: _.template('<div class="header clearfix"><div class="pageSize pull-left" /><div class="quickSearch pull-right" /></div><div class="table" /><div class="footer clearfix"><div class="info pull-left" /><div class="page pull-right" /></div>')
|
4815
|
+
});
|
4816
|
+
|
4817
|
+
Tableling.Bootstrap.TableView = Tableling.Plain.TableView.extend({});
|
4818
|
+
|
4819
|
+
Tableling.Bootstrap.PageSizeView = Tableling.Bootstrap.Table.prototype.pageSizeView = Tableling.Plain.PageSizeView.extend({
|
4820
|
+
|
4821
|
+
tagName: 'form',
|
4822
|
+
className: 'form-inline',
|
4823
|
+
attributes: {
|
4824
|
+
role: 'form'
|
4825
|
+
},
|
4826
|
+
template: function(data) {
|
4827
|
+
return _.template('<div class="formGroup"><select name="pageSize" class="form-control"><option>5</option><option>10</option><option>15</option></select> <%- entries %></div>', data);
|
4828
|
+
}
|
4829
|
+
});
|
4830
|
+
|
4831
|
+
Tableling.Bootstrap.QuickSearchView = Tableling.Bootstrap.Table.prototype.quickSearchView = Tableling.Plain.QuickSearchView.extend({
|
4832
|
+
|
4833
|
+
tagName: 'form',
|
4834
|
+
className: 'form-inline',
|
4835
|
+
attributes: {
|
4836
|
+
role: 'form'
|
4837
|
+
},
|
4838
|
+
template: function(data) {
|
4839
|
+
return _.template('<div class="formGroup"><input type="text" name="quickSearch" class="form-control" placeholder="<%- quickSearch %>" /></div>', data);
|
4840
|
+
}
|
4841
|
+
});
|
4842
|
+
|
4843
|
+
Tableling.Bootstrap.InfoView = Tableling.Bootstrap.Table.prototype.infoView = Tableling.Plain.InfoView.extend({});
|
4844
|
+
|
4845
|
+
Tableling.Bootstrap.PageView = Tableling.Bootstrap.Table.prototype.pageView = Tableling.Plain.PageView.extend({});
|
4781
4846
|
|
4782
4847
|
return Tableling;
|
4783
4848
|
|
4784
|
-
})(Backbone, _, $ || window.jQuery || window.Zepto || window.ender);
|
4849
|
+
})(Backbone, _, $ || window.jQuery || window.Zepto || window.ender);
|