tableling-rails 0.0.23 → 0.0.24
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|