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 +4 -4
- data/app/assets/javascripts/bastion/bastion-bootstrap.js +0 -1
- data/app/assets/javascripts/bastion/bastion.js +0 -1
- data/app/assets/javascripts/bastion/components/bst-on-enter.directive.js +1 -0
- data/app/assets/javascripts/bastion/components/nutupane.factory.js +95 -61
- data/app/assets/javascripts/bastion/layouts/partials/table.html +63 -21
- data/app/assets/javascripts/bastion/utils/round-up.filter.js +20 -0
- data/app/assets/stylesheets/bastion/nutupane.scss +0 -4
- data/app/assets/stylesheets/bastion/overrides.scss +5 -0
- data/app/assets/stylesheets/bastion/tables.scss +8 -0
- data/app/views/bastion/layouts/assets.html.erb +1 -0
- data/bower.json +0 -4
- data/grunt/karma.js +0 -1
- data/lib/bastion/version.rb +1 -1
- data/test/components/nutupane.factory.test.js +114 -48
- data/test/utils/round-up.filter.test.js +14 -0
- metadata +5 -11
- data/app/assets/javascripts/bastion/components/bst-container-scroll.directive.js +0 -74
- data/app/assets/javascripts/bastion/components/nutupane-table.directive.js +0 -69
- data/app/assets/javascripts/bastion/layouts/details-nutupane.html +0 -89
- data/app/assets/javascripts/bastion/layouts/nutupane.html +0 -93
- data/test/components/bst-container-scroll.directive.test.js +0 -63
- data/test/components/bst-nutupane-table.directive.test.js +0 -55
- data/vendor/assets/javascripts/bastion/ngInfiniteScroll/ng-infinite-scroll.js +0 -186
@@ -1,93 +0,0 @@
|
|
1
|
-
<section>
|
2
|
-
|
3
|
-
<div bst-global-notification></div>
|
4
|
-
|
5
|
-
<div class="row nutupane-bar">
|
6
|
-
<h2 class="col-sm-2">
|
7
|
-
<span data-block="header">
|
8
|
-
REPLACE ME
|
9
|
-
</span>
|
10
|
-
</h2>
|
11
|
-
</div>
|
12
|
-
|
13
|
-
<div class="row nutupane-bar">
|
14
|
-
|
15
|
-
<div class="row">
|
16
|
-
<div class="col-sm-12">
|
17
|
-
<div data-block="search-filter"></div>
|
18
|
-
</div>
|
19
|
-
</div>
|
20
|
-
|
21
|
-
<div class="col-sm-3 nutupane-info">
|
22
|
-
<form role="form" class="search-pf has-button">
|
23
|
-
<div class="form-group has-clear">
|
24
|
-
<div class="search-pf-input-group">
|
25
|
-
<label for="table-search" class="sr-only" translate>Search</label>
|
26
|
-
|
27
|
-
<input id="table-search"
|
28
|
-
type="search"
|
29
|
-
class="form-control"
|
30
|
-
placeholder="{{ 'Search...' | translate }}"
|
31
|
-
bst-on-enter="table.search(table.searchTerm)"
|
32
|
-
ng-model="table.searchTerm"
|
33
|
-
ng-trim="false"
|
34
|
-
uib-typeahead="item.label for item in table.autocomplete($viewValue)"
|
35
|
-
typeahead-template-url="components/views/autocomplete-scoped-search.html"/>
|
36
|
-
|
37
|
-
<button type="button" class="clear" aria-hidden="true" ng-show="table.searchTerm" ng-click='table.clearSearch()'>
|
38
|
-
<span class="pficon pficon-close"></span>
|
39
|
-
</button>
|
40
|
-
</div>
|
41
|
-
</div>
|
42
|
-
|
43
|
-
<div class="form-group">
|
44
|
-
<button class="btn btn-default" type="button" ng-click="table.search(table.searchTerm)" >
|
45
|
-
<span class="fa fa-search"></span>
|
46
|
-
</button>
|
47
|
-
</div>
|
48
|
-
<div uib-dropdown class="form-group">
|
49
|
-
<button uib-dropdown-toggle class="btn btn-default">
|
50
|
-
<i class="fa fa-caret-down"></i>
|
51
|
-
</button>
|
52
|
-
<ul bst-bookmark uib-dropdown-menu controller-name="controllerName" query="table.searchTerm" class="pull-right"></ul>
|
53
|
-
</div>
|
54
|
-
</form>
|
55
|
-
</div>
|
56
|
-
|
57
|
-
<div class="col-sm-3 nutupane-info">
|
58
|
-
<span translate>Showing {{ table.rows.length }} of {{ table.resource.subtotal }} ({{ table.resource.total }} Total)</span>
|
59
|
-
</div>
|
60
|
-
|
61
|
-
<div class="fr">
|
62
|
-
<div class="nutupane-info fl" ng-if="table.rowSelect">
|
63
|
-
<span translate>{{ table.numSelected }} Selected</span>
|
64
|
-
</div>
|
65
|
-
|
66
|
-
<div class="fl">
|
67
|
-
<div data-block="actions"></div>
|
68
|
-
</div>
|
69
|
-
</div>
|
70
|
-
</div>
|
71
|
-
|
72
|
-
<div class="row nutupane" bst-table="table" nutupane-table ng-class="{'table-reduced': $root.$state.current.collapsed}">
|
73
|
-
<div class="loading-mask" ng-show="table.refreshing" ng-class="{ 'loading-mask-collapsed': $root.$state.current.collapsed }">
|
74
|
-
<i class="fa fa-spinner fa-spin"></i>
|
75
|
-
<span ng-hide="$root.$state.current.collapsed">{{ "Loading..." | translate }}</span>
|
76
|
-
</div>
|
77
|
-
|
78
|
-
<p bst-alert="info" ng-show="table.rows.length === 0 && !table.working && !table.searchTerm && !table.searchCompleted">
|
79
|
-
<span data-block="no-rows-message"></span>
|
80
|
-
</p>
|
81
|
-
<p bst-alert="info" ng-show="table.rows.length === 0 && !table.working && (table.searchTerm || table.searchCompleted)">
|
82
|
-
<span data-block="no-search-results-message"></span>
|
83
|
-
</p>
|
84
|
-
|
85
|
-
<div ng-show="table.rows.length > 0" bst-container-scroll data="table.rows">
|
86
|
-
<div infinite-scroll="table.nextPage()" infinite-scroll-container="'.container-scroll-wrapper'" infinite-scroll-listen-for-event="nutupane:loaded"
|
87
|
-
ui-view="table"></div>
|
88
|
-
</div>
|
89
|
-
</div>
|
90
|
-
|
91
|
-
<span class="action-panel" ui-view="action-panel"></span>
|
92
|
-
|
93
|
-
</section>
|
@@ -1,63 +0,0 @@
|
|
1
|
-
describe('Directive: bstContainerScroll', function() {
|
2
|
-
var scope,
|
3
|
-
compile,
|
4
|
-
windowElement,
|
5
|
-
tableElement;
|
6
|
-
|
7
|
-
beforeEach(module('Bastion.components'));
|
8
|
-
|
9
|
-
beforeEach(inject(function(_$compile_, _$rootScope_, $window) {
|
10
|
-
compile = _$compile_;
|
11
|
-
scope = _$rootScope_;
|
12
|
-
windowElement = angular.element($window)
|
13
|
-
}));
|
14
|
-
|
15
|
-
beforeEach(function() {
|
16
|
-
tableElement = angular.element(
|
17
|
-
'<div bst-container-scroll>' +
|
18
|
-
'<table>' +
|
19
|
-
'<thead>' +
|
20
|
-
'<tr><th>Column 1</th></tr>' +
|
21
|
-
'</thead>' +
|
22
|
-
'<tbody>' +
|
23
|
-
'<tr>' +
|
24
|
-
'<td>Row 1</td>' +
|
25
|
-
'</tr>' +
|
26
|
-
'</tbody>' +
|
27
|
-
'</table>' +
|
28
|
-
'</div>');
|
29
|
-
|
30
|
-
compile(tableElement)(scope);
|
31
|
-
scope.$digest();
|
32
|
-
});
|
33
|
-
|
34
|
-
it("should adjust the table height on window resize", function() {
|
35
|
-
windowElement.height('100px');
|
36
|
-
windowElement.trigger('resize');
|
37
|
-
|
38
|
-
expect(tableElement.height()).toEqual(windowElement.height() - tableElement.offset().top);
|
39
|
-
});
|
40
|
-
|
41
|
-
it("should ensure that the element is at least 200px", function () {
|
42
|
-
windowElement.height('200px');
|
43
|
-
tableElement.css('padding-bottom', '200px');
|
44
|
-
|
45
|
-
compile(tableElement)(scope);
|
46
|
-
scope.$digest();
|
47
|
-
|
48
|
-
windowElement.trigger('resize');
|
49
|
-
expect(tableElement.height()).toEqual(300);
|
50
|
-
});
|
51
|
-
|
52
|
-
it("should add the nutupane details padding if it exists", function () {
|
53
|
-
tableElement.css('padding-bottom', '10px');
|
54
|
-
|
55
|
-
compile(tableElement)(scope);
|
56
|
-
scope.$digest();
|
57
|
-
|
58
|
-
windowElement.height('100px');
|
59
|
-
windowElement.trigger('resize');
|
60
|
-
|
61
|
-
expect(tableElement.height()).toEqual(windowElement.height() - (tableElement.offset().top + 10));
|
62
|
-
});
|
63
|
-
});
|
@@ -1,55 +0,0 @@
|
|
1
|
-
describe('Directive: nutupaneTable', function() {
|
2
|
-
var scope,
|
3
|
-
compile,
|
4
|
-
tableElement;
|
5
|
-
|
6
|
-
beforeEach(module('Bastion.components'));
|
7
|
-
|
8
|
-
beforeEach(inject(function(_$compile_, _$rootScope_) {
|
9
|
-
compile = _$compile_;
|
10
|
-
scope = _$rootScope_;
|
11
|
-
}));
|
12
|
-
|
13
|
-
beforeEach(function() {
|
14
|
-
tableElement = angular.element(
|
15
|
-
'<div nutupane-table>' +
|
16
|
-
'<table>' +
|
17
|
-
'<thead>' +
|
18
|
-
'<tr><th>Column 1</th></tr>' +
|
19
|
-
'</thead>' +
|
20
|
-
'<tbody>' +
|
21
|
-
'<tr>' +
|
22
|
-
'<td>Row 1</td>' +
|
23
|
-
'</tr>' +
|
24
|
-
'</tbody>' +
|
25
|
-
'</table>' +
|
26
|
-
'</div>');
|
27
|
-
|
28
|
-
compile(tableElement)(scope);
|
29
|
-
scope.$digest();
|
30
|
-
scope.$broadcast("$stateChangeSuccess", {}, {}, {}, {});
|
31
|
-
});
|
32
|
-
|
33
|
-
it("should create a new table element with just the thead", function() {
|
34
|
-
var theads = tableElement.find('thead'),
|
35
|
-
tbodys = tableElement.find('tbody');
|
36
|
-
|
37
|
-
expect(theads.length).toEqual(2);
|
38
|
-
expect(tbodys.length).toEqual(1);
|
39
|
-
});
|
40
|
-
|
41
|
-
it("should hide the original table's thead", function() {
|
42
|
-
var originalTableHead = angular.element(tableElement.find('thead')[1]);
|
43
|
-
|
44
|
-
expect(originalTableHead.css('display')).toBe('none');
|
45
|
-
});
|
46
|
-
|
47
|
-
it("should remove the duplicate row select from the cloned table if present", function() {
|
48
|
-
var rowSelectTable = tableElement.clone();
|
49
|
-
rowSelectTable.find('thead').prepend("<tr><th class='row-select'></th></tr>");
|
50
|
-
compile(rowSelectTable)(scope);
|
51
|
-
scope.$digest();
|
52
|
-
scope.$broadcast("$stateChangeSuccess", {}, {}, {}, {});
|
53
|
-
expect(rowSelectTable.find('.row-select').length).toBe(1);
|
54
|
-
});
|
55
|
-
});
|
@@ -1,186 +0,0 @@
|
|
1
|
-
/* ng-infinite-scroll - v1.2.0 - 2015-02-14 */
|
2
|
-
var mod;
|
3
|
-
|
4
|
-
mod = angular.module('infinite-scroll', []);
|
5
|
-
|
6
|
-
mod.value('THROTTLE_MILLISECONDS', null);
|
7
|
-
|
8
|
-
mod.directive('infiniteScroll', [
|
9
|
-
'$rootScope', '$window', '$interval', 'THROTTLE_MILLISECONDS', function($rootScope, $window, $interval, THROTTLE_MILLISECONDS) {
|
10
|
-
return {
|
11
|
-
scope: {
|
12
|
-
infiniteScroll: '&',
|
13
|
-
infiniteScrollContainer: '=',
|
14
|
-
infiniteScrollDistance: '=',
|
15
|
-
infiniteScrollDisabled: '=',
|
16
|
-
infiniteScrollUseDocumentBottom: '=',
|
17
|
-
infiniteScrollListenForEvent: '@'
|
18
|
-
},
|
19
|
-
link: function(scope, elem, attrs) {
|
20
|
-
var changeContainer, checkWhenEnabled, container, handleInfiniteScrollContainer, handleInfiniteScrollDisabled, handleInfiniteScrollDistance, handleInfiniteScrollUseDocumentBottom, handler, height, immediateCheck, offsetTop, pageYOffset, scrollDistance, scrollEnabled, throttle, unregisterEventListener, useDocumentBottom, windowElement;
|
21
|
-
windowElement = angular.element($window);
|
22
|
-
scrollDistance = null;
|
23
|
-
scrollEnabled = null;
|
24
|
-
checkWhenEnabled = null;
|
25
|
-
container = null;
|
26
|
-
immediateCheck = true;
|
27
|
-
useDocumentBottom = false;
|
28
|
-
unregisterEventListener = null;
|
29
|
-
height = function(elem) {
|
30
|
-
elem = elem[0] || elem;
|
31
|
-
if (isNaN(elem.offsetHeight)) {
|
32
|
-
return elem.document.documentElement.clientHeight;
|
33
|
-
} else {
|
34
|
-
return elem.offsetHeight;
|
35
|
-
}
|
36
|
-
};
|
37
|
-
offsetTop = function(elem) {
|
38
|
-
if (!elem[0].getBoundingClientRect || elem.css('none')) {
|
39
|
-
return;
|
40
|
-
}
|
41
|
-
return elem[0].getBoundingClientRect().top + pageYOffset(elem);
|
42
|
-
};
|
43
|
-
pageYOffset = function(elem) {
|
44
|
-
elem = elem[0] || elem;
|
45
|
-
if (isNaN(window.pageYOffset)) {
|
46
|
-
return elem.document.documentElement.scrollTop;
|
47
|
-
} else {
|
48
|
-
return elem.ownerDocument.defaultView.pageYOffset;
|
49
|
-
}
|
50
|
-
};
|
51
|
-
handler = function() {
|
52
|
-
var containerBottom, containerTopOffset, elementBottom, remaining, shouldScroll;
|
53
|
-
if (container === windowElement) {
|
54
|
-
containerBottom = height(container) + pageYOffset(container[0].document.documentElement);
|
55
|
-
elementBottom = offsetTop(elem) + height(elem);
|
56
|
-
} else {
|
57
|
-
containerBottom = height(container);
|
58
|
-
containerTopOffset = 0;
|
59
|
-
if (offsetTop(container) !== void 0) {
|
60
|
-
containerTopOffset = offsetTop(container);
|
61
|
-
}
|
62
|
-
elementBottom = offsetTop(elem) - containerTopOffset + height(elem);
|
63
|
-
}
|
64
|
-
if (useDocumentBottom) {
|
65
|
-
elementBottom = height((elem[0].ownerDocument || elem[0].document).documentElement);
|
66
|
-
}
|
67
|
-
remaining = elementBottom - containerBottom;
|
68
|
-
shouldScroll = remaining <= height(container) * scrollDistance + 1;
|
69
|
-
if (shouldScroll) {
|
70
|
-
checkWhenEnabled = true;
|
71
|
-
if (scrollEnabled) {
|
72
|
-
if (scope.$$phase || $rootScope.$$phase) {
|
73
|
-
return scope.infiniteScroll();
|
74
|
-
} else {
|
75
|
-
return scope.$apply(scope.infiniteScroll);
|
76
|
-
}
|
77
|
-
}
|
78
|
-
} else {
|
79
|
-
return checkWhenEnabled = false;
|
80
|
-
}
|
81
|
-
};
|
82
|
-
throttle = function(func, wait) {
|
83
|
-
var later, previous, timeout;
|
84
|
-
timeout = null;
|
85
|
-
previous = 0;
|
86
|
-
later = function() {
|
87
|
-
var context;
|
88
|
-
previous = new Date().getTime();
|
89
|
-
$interval.cancel(timeout);
|
90
|
-
timeout = null;
|
91
|
-
func.call();
|
92
|
-
return context = null;
|
93
|
-
};
|
94
|
-
return function() {
|
95
|
-
var now, remaining;
|
96
|
-
now = new Date().getTime();
|
97
|
-
remaining = wait - (now - previous);
|
98
|
-
if (remaining <= 0) {
|
99
|
-
clearTimeout(timeout);
|
100
|
-
$interval.cancel(timeout);
|
101
|
-
timeout = null;
|
102
|
-
previous = now;
|
103
|
-
return func.call();
|
104
|
-
} else {
|
105
|
-
if (!timeout) {
|
106
|
-
return timeout = $interval(later, remaining, 1);
|
107
|
-
}
|
108
|
-
}
|
109
|
-
};
|
110
|
-
};
|
111
|
-
if (THROTTLE_MILLISECONDS != null) {
|
112
|
-
handler = throttle(handler, THROTTLE_MILLISECONDS);
|
113
|
-
}
|
114
|
-
scope.$on('$destroy', function() {
|
115
|
-
container.unbind('scroll', handler);
|
116
|
-
if (unregisterEventListener != null) {
|
117
|
-
unregisterEventListener();
|
118
|
-
return unregisterEventListener = null;
|
119
|
-
}
|
120
|
-
});
|
121
|
-
handleInfiniteScrollDistance = function(v) {
|
122
|
-
return scrollDistance = parseFloat(v) || 0;
|
123
|
-
};
|
124
|
-
scope.$watch('infiniteScrollDistance', handleInfiniteScrollDistance);
|
125
|
-
handleInfiniteScrollDistance(scope.infiniteScrollDistance);
|
126
|
-
handleInfiniteScrollDisabled = function(v) {
|
127
|
-
scrollEnabled = !v;
|
128
|
-
if (scrollEnabled && checkWhenEnabled) {
|
129
|
-
checkWhenEnabled = false;
|
130
|
-
return handler();
|
131
|
-
}
|
132
|
-
};
|
133
|
-
scope.$watch('infiniteScrollDisabled', handleInfiniteScrollDisabled);
|
134
|
-
handleInfiniteScrollDisabled(scope.infiniteScrollDisabled);
|
135
|
-
handleInfiniteScrollUseDocumentBottom = function(v) {
|
136
|
-
return useDocumentBottom = v;
|
137
|
-
};
|
138
|
-
scope.$watch('infiniteScrollUseDocumentBottom', handleInfiniteScrollUseDocumentBottom);
|
139
|
-
handleInfiniteScrollUseDocumentBottom(scope.infiniteScrollUseDocumentBottom);
|
140
|
-
changeContainer = function(newContainer) {
|
141
|
-
if (container != null) {
|
142
|
-
container.unbind('scroll', handler);
|
143
|
-
}
|
144
|
-
container = newContainer;
|
145
|
-
if (newContainer != null) {
|
146
|
-
return container.bind('scroll', handler);
|
147
|
-
}
|
148
|
-
};
|
149
|
-
changeContainer(windowElement);
|
150
|
-
if (scope.infiniteScrollListenForEvent) {
|
151
|
-
unregisterEventListener = $rootScope.$on(scope.infiniteScrollListenForEvent, handler);
|
152
|
-
}
|
153
|
-
handleInfiniteScrollContainer = function(newContainer) {
|
154
|
-
if ((newContainer == null) || newContainer.length === 0) {
|
155
|
-
return;
|
156
|
-
}
|
157
|
-
if (newContainer instanceof HTMLElement) {
|
158
|
-
newContainer = angular.element(newContainer);
|
159
|
-
} else if (typeof newContainer.append === 'function') {
|
160
|
-
newContainer = angular.element(newContainer[newContainer.length - 1]);
|
161
|
-
} else if (typeof newContainer === 'string') {
|
162
|
-
newContainer = angular.element(document.querySelector(newContainer));
|
163
|
-
}
|
164
|
-
if (newContainer != null) {
|
165
|
-
return changeContainer(newContainer);
|
166
|
-
} else {
|
167
|
-
throw new Exception("invalid infinite-scroll-container attribute.");
|
168
|
-
}
|
169
|
-
};
|
170
|
-
scope.$watch('infiniteScrollContainer', handleInfiniteScrollContainer);
|
171
|
-
handleInfiniteScrollContainer(scope.infiniteScrollContainer || []);
|
172
|
-
if (attrs.infiniteScrollParent != null) {
|
173
|
-
changeContainer(angular.element(elem.parent()));
|
174
|
-
}
|
175
|
-
if (attrs.infiniteScrollImmediateCheck != null) {
|
176
|
-
immediateCheck = scope.$eval(attrs.infiniteScrollImmediateCheck);
|
177
|
-
}
|
178
|
-
return $interval((function() {
|
179
|
-
if (immediateCheck) {
|
180
|
-
return handler();
|
181
|
-
}
|
182
|
-
}), 0, 1);
|
183
|
-
}
|
184
|
-
};
|
185
|
-
}
|
186
|
-
]);
|