bastion 4.3.1 → 5.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d51f22893a276196b2ddf87221c5f4d3690a9b13
4
- data.tar.gz: 6fc3afe5f918a577dab6860644f87cc6364ebfde
3
+ metadata.gz: 53eb3be4777021eaac12603429045c2b6a75dfcc
4
+ data.tar.gz: 00a4c50f7065293da92e5f921713c2e0b1579964
5
5
  SHA512:
6
- metadata.gz: fa1bf691ed2d238091e8f59f83d044bbbf5d5e288dbdfcf221181f4f3ea25e99249dd9262210ef64b4b6b7de1c646e6bfb9f682a22af2a75b9afd4c63df7330d
7
- data.tar.gz: ed1f7879352f95741e8ca93ee8cf0799b93adf20fa1a3fc25d0a09b0e777d4a18a7965abca3734606dd79e20b172a8224eb4e4125b17fc27c033a5773bdeab61
6
+ metadata.gz: aec99b88057a13f935fa09711fe332585a229937685cff963f384c327323b5b4c991883ce8764b8ae1391addbbf037095ff119465f2a0b633d5b145397d064c0
7
+ data.tar.gz: ad1e8891be0ba0a795ce733630ade101b0a326c595d40e1b70802b528a9247ef5dcf836070ffb60cb7ca409f8b36bf137e17e08b5c26ca6c7162da62d7736f16
@@ -6,7 +6,6 @@ BASTION_MODULES = [
6
6
  'angular-blocks',
7
7
  'ngAnimate',
8
8
  'ngSanitize',
9
- 'infinite-scroll',
10
9
  'templates',
11
10
  'ui.bootstrap',
12
11
  'ui.bootstrap.tpls',
@@ -5,7 +5,6 @@
5
5
  //= require "bastion/angular-ui-router/angular-ui-router"
6
6
  //= require "bastion/angular-uuid4/angular-uuid4.js"
7
7
  //= require "bastion/ngUpload/ng-upload"
8
- //= require "bastion/ngInfiniteScroll/ng-infinite-scroll.js"
9
8
  //= require "bastion/angular-gettext/angular-gettext"
10
9
  //= require "bastion/angular-blocks/angular-blocks"
11
10
  //= require "bastion/angular-breadcrumb/angular-breadcrumb"
@@ -15,6 +15,7 @@
15
15
  element.bind('keydown keypress', function (event) {
16
16
  if (event.which === 13) {
17
17
  scope.$apply(attrs.bstOnEnter);
18
+ event.preventDefault();
18
19
  }
19
20
  });
20
21
  }
@@ -4,8 +4,7 @@
4
4
  *
5
5
  * @requires $location
6
6
  * @requires $q
7
- * @requires $timeout
8
- * @requires $rootScope
7
+ * @requires entriesPerPage
9
8
  * @requires TableCache
10
9
  * @requires GlobalNotification
11
10
  *
@@ -31,10 +30,9 @@
31
30
  </pre>
32
31
  */
33
32
  angular.module('Bastion.components').factory('Nutupane',
34
- ['$location', '$q', '$timeout', '$rootScope', 'TableCache', 'GlobalNotification', function ($location, $q, $timeout, $rootScope, TableCache, GlobalNotification) {
33
+ ['$location', '$q', 'entriesPerPage', 'TableCache', 'GlobalNotification', function ($location, $q, entriesPerPage, TableCache, GlobalNotification) {
35
34
  var Nutupane = function (resource, params, action) {
36
- var self = this,
37
- orgSwitcherRegex = new RegExp("/(organizations|locations)/(.+/)*(select|clear)");
35
+ var self = this;
38
36
 
39
37
  // TODO: remove me
40
38
  // http://projects.theforeman.org/issues/18079
@@ -44,7 +42,29 @@ angular.module('Bastion.components').factory('Nutupane',
44
42
  return $location.path().split('/').join('-').slice(1);
45
43
  }
46
44
 
45
+ function setQueryStrings() {
46
+ if (params.paged) {
47
+ $location.search("page", params.page).replace();
48
+ $location.search("per_page", params['per_page']).replace();
49
+ }
50
+
51
+ if (params.search) {
52
+ $location.search(self.searchKey, params.search).replace();
53
+ }
54
+
55
+ if (params.sort_by) {
56
+ $location.search("sortBy", params['sort_by']).replace();
57
+ }
58
+
59
+ if (params['sort_order']) {
60
+ $location.search("sortOrder", params['sort_order']).replace();
61
+ }
62
+ }
63
+
47
64
  params = params || {};
65
+ params.paged = true;
66
+ params.page = $location.search().page || 1;
67
+ params['per_page'] = $location.search().perPage || entriesPerPage;
48
68
 
49
69
  self.searchKey = action ? action + 'Search' : 'search';
50
70
 
@@ -57,17 +77,10 @@ angular.module('Bastion.components').factory('Nutupane',
57
77
  initialLoad: true
58
78
  };
59
79
 
60
- // Set default resource values
61
- resource.page = 0;
62
- resource.subtotal = "0";
63
- resource.total = "0";
64
- resource.results = [];
65
-
66
- self.load = function (replace) {
80
+ self.load = function () {
67
81
  var deferred = $q.defer(),
68
82
  table = self.table;
69
83
 
70
- replace = replace || false;
71
84
  table.working = true;
72
85
 
73
86
  if (table.initialLoad) {
@@ -76,7 +89,6 @@ angular.module('Bastion.components').factory('Nutupane',
76
89
  table.searchCompleted = false;
77
90
  }
78
91
 
79
- params.page = table.resource.page + 1;
80
92
  params.search = table.searchTerm || "";
81
93
  params.search = self.searchTransform(params.search);
82
94
 
@@ -90,11 +102,7 @@ angular.module('Bastion.components').factory('Nutupane',
90
102
  row.selected = table.allResultsSelected;
91
103
  });
92
104
 
93
- if (replace) {
94
- table.rows = response.results;
95
- } else {
96
- table.rows = table.rows.concat(response.results);
97
- }
105
+ table.rows = response.results;
98
106
  table.resource.page = parseInt(response.page, 10);
99
107
 
100
108
  if (table.initialSelectAll) {
@@ -102,21 +110,23 @@ angular.module('Bastion.components').factory('Nutupane',
102
110
  table.initialSelectAll = false;
103
111
  }
104
112
 
105
- // This $timeout is necessary to cause a digest cycle
106
- // in order to prevent loading two sets of results.
107
- $timeout(function () {
108
- deferred.resolve(response);
109
- table.resource = response;
110
- table.resource.page = parseInt(response.page, 10);
113
+ deferred.resolve(response);
114
+ table.resource = response;
115
+ table.resource.page = parseInt(response.page, 10);
111
116
 
112
- if (self.selectAllMode) {
113
- table.selectAll(true);
114
- }
115
- table.resource.offset = table.rows.length;
117
+ if (self.selectAllMode) {
118
+ table.selectAll(true);
119
+ }
120
+
121
+ if (table.resource.page > 1) {
122
+ table.resource.offset = (table.resource.page - 1) * table.resource['per_page'] + 1;
123
+ } else {
124
+ table.resource.offset = 1;
125
+ }
126
+
127
+ TableCache.setTable(getTableName(), table);
128
+ setQueryStrings();
116
129
 
117
- TableCache.setTable(getTableName(), table);
118
- $rootScope.$emit('nutupane:loaded');
119
- }, 0);
120
130
  table.working = false;
121
131
  table.refreshing = false;
122
132
  });
@@ -271,8 +281,8 @@ angular.module('Bastion.components').factory('Nutupane',
271
281
  $location.search(self.searchKey, searchTerm);
272
282
  self.table.searchTerm = searchTerm;
273
283
  self.table.resource.page = 1;
284
+ self.table.params.page = 1;
274
285
  self.table.rows = [];
275
- self.table.closeItem();
276
286
  self.table.selectAllResults(false);
277
287
 
278
288
  if (!self.table.working) {
@@ -291,13 +301,6 @@ angular.module('Bastion.components').factory('Nutupane',
291
301
  self.table.searchCompleted = true;
292
302
  };
293
303
 
294
- // Must be overridden
295
- self.table.closeItem = function () {
296
- if (!self.masterOnly) {
297
- throw "Nutupane closeItem not implemented. If you are using Nutupane functionality with master-detail please pass 'masterOnly' to your Nutupane declaration";
298
- }
299
- };
300
-
301
304
  self.table.replaceRow = function (row) {
302
305
  var index, selected;
303
306
  index = null;
@@ -320,27 +323,60 @@ angular.module('Bastion.components').factory('Nutupane',
320
323
  self.table.resource.total += 1;
321
324
  };
322
325
 
323
- self.table.nextPage = function () {
324
- var table = self.table;
325
- if (table.working || !table.hasMore()) {
326
- return false;
326
+ self.table.onFirstPage = function () {
327
+ return self.table.resource.page === 1;
328
+ };
329
+
330
+ self.table.onLastPage = function () {
331
+ return self.table.resource.page >= self.table.resource.subtotal / self.table.resource.per_page;
332
+ };
333
+
334
+ self.table.getPageEnd = function () {
335
+ var table = self.table, pageEnd;
336
+
337
+ pageEnd = table.resource.offset + table.rows.length - 1;
338
+
339
+ if (pageEnd > table.resource.subtotal) {
340
+ pageEnd = table.resource.subtotal;
327
341
  }
328
- return self.query();
342
+
343
+ return pageEnd;
329
344
  };
330
345
 
331
- self.table.hasMore = function () {
332
- var length = self.table.rows.length,
333
- subtotal = self.table.resource.subtotal,
334
- hasMore = false,
335
- justBegun;
346
+ self.table.firstPage = function () {
347
+ return self.table.changePage(1);
348
+ };
336
349
 
337
- if (!subtotal) {
338
- hasMore = false;
339
- } else {
340
- justBegun = (length === 0 && subtotal !== 0);
341
- hasMore = (length < subtotal) || justBegun;
350
+ self.table.previousPage = function () {
351
+ var previousPage = parseInt(params.page, 10) - 1;
352
+ return self.table.changePage(previousPage);
353
+ };
354
+
355
+ self.table.nextPage = function () {
356
+ var nextPage = parseInt(params.page, 10) + 1;
357
+ return self.table.changePage(nextPage);
358
+ };
359
+
360
+ self.table.lastPage = function () {
361
+ var table = self.table,
362
+ lastPage = Math.ceil(table.resource.subtotal / table.resource.per_page);
363
+ return table.changePage(lastPage);
364
+ };
365
+
366
+ self.table.changePage = function (pageNumber) {
367
+ if (pageNumber) {
368
+ params.page = pageNumber;
369
+ self.table.resource.page = pageNumber;
342
370
  }
343
- return hasMore;
371
+
372
+ return self.load();
373
+ };
374
+
375
+ self.table.pageSizes = _.uniq(_([25, 50, 75, 100, entriesPerPage]).sortBy().value());
376
+
377
+ self.table.updatePageSize = function () {
378
+ params.page = 1;
379
+ self.query();
344
380
  };
345
381
 
346
382
  // Wraps the table.selectAll() function if selectAllResultsEnabled is not set
@@ -394,12 +430,10 @@ angular.module('Bastion.components').factory('Nutupane',
394
430
  self.table.searchTerm = $location.search()[self.searchKey];
395
431
  };
396
432
 
397
- $rootScope.$on('$locationChangeStart', function (event, newUrl) {
398
- if (newUrl.match(orgSwitcherRegex)) {
399
- self.table.closeItem();
400
- }
401
- });
433
+ // Load initial set of results
434
+ self.load();
402
435
  };
436
+
403
437
  return Nutupane;
404
438
  }]
405
439
  );
@@ -1,11 +1,11 @@
1
1
  <div class="row toolbar-pf table-view-pf-toolbar-external" ng-class="{'empty-table': table.rows.length === 0}">
2
2
  <div class="col-sm-12">
3
3
  <form class="toolbar-pf-actions">
4
- <div class="form-group toolbar-pf-filter">
5
- <div class="form-group toolbar-pf-search-filter">
6
- <span data-block="search-filter"></span>
7
- </div>
4
+ <div class="form-group toolbar-pf-search-filter">
5
+ <span data-block="search-filter"></span>
6
+ </div>
8
7
 
8
+ <div class="form-group toolbar-pf-filter">
9
9
  <div data-block="search">
10
10
  <div class="input-group">
11
11
  <input type="text"
@@ -23,7 +23,7 @@
23
23
  <button class="btn btn-default"
24
24
  type="button"
25
25
  ng-click='table.search("") && (table.searchCompleted = false)'
26
- ng-show="table.searchCompleted && table.searchTerm">
26
+ ng-show="table.searchTerm">
27
27
  <i class="fa fa-times"></i>
28
28
  </button>
29
29
  <button ng-click="table.search(table.searchTerm)" class="btn btn-default" type="button">
@@ -48,25 +48,17 @@
48
48
  </form>
49
49
 
50
50
  <div class="row toolbar-pf-results" ng-show="table.rows.length > 0">
51
- <div class="col-sm-9">
52
- <span translate>Showing {{ table.rows.length }} of {{ table.resource.subtotal }} ({{ table.resource.total }} Total)</span>
53
- </div>
54
-
51
+ <div class="col-sm-9"></div>
55
52
  <div class="col-sm-3 table-view-pf-select-results" ng-show="table.rowSelect">
56
- <span translate>{{ table.numSelected }} Selected</span>
53
+ <span translate>{{ table.numSelected }} of {{ table.resource.total }} Selected</span>
57
54
  </div>
58
55
  </div>
59
56
  </div>
60
57
  </div>
61
58
 
62
- <div bst-table="table" nutupane-table>
59
+ <div bst-table="table">
63
60
  <div class="row">
64
61
  <div class="col-sm-12">
65
- <div class="loading-mask" ng-show="table.refreshing || table.working" >
66
- <i class="fa fa-spinner fa-spin"></i>
67
- <span>{{ "Loading..." | translate }}</span>
68
- </div>
69
-
70
62
  <p bst-alert="info" ng-show="table.rows.length === 0 && !table.working && !table.searchTerm && !table.searchCompleted">
71
63
  <span data-block="no-rows-message"></span>
72
64
  </p>
@@ -74,11 +66,61 @@
74
66
  <span data-block="no-search-results-message"></span>
75
67
  </p>
76
68
 
77
- <div ng-show="table.rows.length > 0 && !(table.refreshing || table.working)" bst-container-scroll data="table.rows">
78
- <div infinite-scroll="table.nextPage()" infinite-scroll-container="'.container-scroll-wrapper'"
79
- infinite-scroll-listen-for-event="nutupane:loaded">
80
- <div data-block="table"></div>
81
- </div>
69
+ <div ng-show="table.rows.length > 0" ng-class="{'table-mask': table.refreshing || table.working}">
70
+ <div data-block="table"></div>
71
+
72
+ <form class="content-view-pf-pagination table-view-pf-pagination clearfix">
73
+ <div class="form-group">
74
+ <div class="pagination-pf-pagesize">
75
+ <select class="form-control" ng-model="table.params.per_page" ng-change="table.updatePageSize()"
76
+ ng-options="value for value in table.pageSizes">
77
+ </select>
78
+ </div>
79
+ <span translate>per page</span>
80
+ </div>
81
+ <div class="form-group">
82
+ <span>
83
+ <span class="pagination-pf-items-current">{{ table.resource.offset }} - {{ table.getPageEnd() }}</span>
84
+ <span translate>of </span>
85
+ <span class="pagination-pf-items-total">{{ table.resource.subtotal }}</span>
86
+ </span>
87
+ <ul class="pagination pagination-pf-back">
88
+ <li ng-class="{ disabled: table.onFirstPage() }">
89
+ <a ng-click="table.onFirstPage() || table.firstPage()" title="{{ 'First Page' | translate }}">
90
+ <span class="i fa fa-angle-double-left"></span>
91
+ </a>
92
+ </li>
93
+ <li ng-class="{ disabled: table.onFirstPage() }">
94
+ <a ng-click="table.onFirstPage() || table.previousPage()" title="{{ 'Previous Page' | translate }}">
95
+ <span class="i fa fa-angle-left"></span>
96
+ </a>
97
+ </li>
98
+ </ul>
99
+
100
+ <label for="currentPage" class="sr-only" translate>
101
+ Current Page
102
+ </label>
103
+ <input id="currentPage" class="pagination-pf-page" type="text" ng-model="table.params.page" ng-blur="table.changePage()" bst-on-enter="table.changePage()"/>
104
+
105
+ <span translate>of
106
+ <span class="pagination-pf-pages">{{ (table.resource.subtotal / table.resource.per_page) | roundUp }}</span>
107
+ </span>
108
+
109
+ <ul class="pagination pagination-pf-forward">
110
+ <li ng-class="{ disabled: table.onLastPage() }">
111
+ <a ng-click="table.onLastPage() || table.nextPage()" title=" {{ 'Next Page' | translate }}">
112
+ <span class="i fa fa-angle-right"></span>
113
+ </a>
114
+ </li>
115
+
116
+ <li ng-class="{ disabled: table.onLastPage() }">
117
+ <a ng-click="table.onLastPage() || table.lastPage()" title="{{ 'Last Page' | translate }}">
118
+ <span class="i fa fa-angle-double-right"></span>
119
+ </a>
120
+ </li>
121
+ </ul>
122
+ </div>
123
+ </form>
82
124
  </div>
83
125
  </div>
84
126
  </div>
@@ -0,0 +1,20 @@
1
+ (function () {
2
+ /**
3
+ * @ngdoc filter
4
+ * @name Bastion.utils.filter:roundUp
5
+ *
6
+ * @description
7
+ * Converts an ng-model to a number.
8
+ *
9
+ * @example
10
+ * {{ 107.5 | roundUp }}
11
+ */
12
+
13
+ function roundUp() {
14
+ return function (value) {
15
+ return Math.ceil(value);
16
+ };
17
+ }
18
+
19
+ angular.module('Bastion.utils').filter('roundUp', roundUp);
20
+ })();
@@ -28,10 +28,6 @@
28
28
  overflow-y: auto;
29
29
  }
30
30
 
31
- .table-mask {
32
- opacity: 0.4;
33
- }
34
-
35
31
  th.row-select,
36
32
  td.row-select {
37
33
  width: 25px;
@@ -79,4 +79,9 @@ html .toolbar-pf.table-view-pf-toolbar-external .toolbar-pf-filter {
79
79
  .modal-body {
80
80
  overflow-x: hidden;
81
81
  overflow-y: scroll;
82
+ }
83
+
84
+ // Add some margin to the bottom of the table footer
85
+ .content-view-pf-pagination {
86
+ margin-bottom: 20px;
82
87
  }
@@ -59,3 +59,11 @@
59
59
  width: 150px;
60
60
  }
61
61
  }
62
+
63
+ .table-mask {
64
+ opacity: 0.4;
65
+ }
66
+
67
+ .pagination-pf-pagesize {
68
+ margin-right: 5px;
69
+ }
@@ -18,6 +18,7 @@
18
18
  angular.module('Bastion').value('CurrentOrganization', "<%= Organization.current.id if Organization.current %>");
19
19
  angular.module('Bastion').value('contentAccessMode', "<%= Organization.current.try(:content_access_mode) if Organization.current %>");
20
20
  angular.module('Bastion').value('markActiveMenu', mark_active_menu);
21
+ angular.module('Bastion').value('entriesPerPage', "<%= Setting[:entries_per_page] %>");
21
22
  angular.module('Bastion').constant('BastionConfig', angular.fromJson('<%= Bastion.config.to_json.html_safe %>'));
22
23
  angular.module('Bastion.auth').value('CurrentUser', {
23
24
  id: <%= User.current.id %>,
data/bower.json CHANGED
@@ -17,7 +17,6 @@
17
17
  "angular-ui-router": "=0.3.1",
18
18
  "angular-uuid4": "0.1.0",
19
19
  "json3": "~3.2.4",
20
- "ngInfiniteScroll": "1.2.1",
21
20
  "ngUpload": "0.5.18"
22
21
  },
23
22
  "devDependencies": {
@@ -79,9 +78,6 @@
79
78
  },
80
79
  "ngUpload": {
81
80
  "javascripts/bastion/ngUpload": "ng-upload.js"
82
- },
83
- "ngInfiniteScroll": {
84
- "javascripts/bastion/ngInfiniteScroll": "build/ng-infinite-scroll.js"
85
81
  }
86
82
  }
87
83
  }
data/grunt/karma.js CHANGED
@@ -29,7 +29,6 @@ module.exports = {
29
29
  basePath + 'vendor/assets/javascripts/bastion/angular-ui-router/angular-ui-router.js',
30
30
  basePath + 'vendor/assets/javascripts/bastion/angular-gettext/angular-gettext.js',
31
31
  basePath + 'vendor/assets/javascripts/bastion/ngUpload/ng-upload.js',
32
- basePath + 'vendor/assets/javascripts/bastion/ngInfiniteScroll/ng-infinite-scroll.js',
33
32
  basePath + 'vendor/assets/javascripts/bastion/angular-breadcrumb/angular-breadcrumb.js',
34
33
  basePath + '.tmp/bower_components/angular-mocks/angular-mocks.js',
35
34
  basePath + '.tmp/bower_components/lodash/lodash.js',
@@ -1,3 +1,3 @@
1
1
  module Bastion
2
- VERSION = "4.3.1"
2
+ VERSION = "5.0.0"
3
3
  end