');
152 | $parent.append($element);
153 |
154 | var childInstanceId = "childInstance";
155 | var childInstance = blockUI.instances.get(childInstanceId);
156 | $attrs.blockUi = childInstanceId;
157 |
158 | // act
159 |
160 | preLinkFn($scope, $element, $attrs);
161 |
162 | // assert
163 |
164 | expect(childInstance._parent).toBe(parentInstance);
165 |
166 | });
167 |
168 | }); // parent block-ui service
169 |
170 | describe('service reference count', function() {
171 |
172 | var instanceName = 'myInstance';
173 | var instance;
174 |
175 | beforeEach(function() {
176 | instance = blockUI.instances.get(instanceName);
177 | });
178 |
179 | afterEach(function() {
180 | blockUI.instances._destroy(instance);
181 | });
182 |
183 | it('should increase the reference count of the service', function() {
184 |
185 | expect(instance._refs).toBe(0);
186 |
187 | var $element = $('
');
188 | $attrs.blockUi = instanceName;
189 |
190 | preLinkFn($scope, $element, $attrs);
191 |
192 | expect(instance._refs).toBe(1);
193 |
194 | });
195 |
196 | it('should release the instance when the scope is destroyed', function() {
197 |
198 | var $element = $('
');
199 | $attrs.blockUi = instanceName;
200 |
201 | preLinkFn($scope, $element, $attrs);
202 |
203 | spyOn(instance, 'release').andCallThrough();
204 | spyOn(blockUI.instances, '_destroy');
205 |
206 | $scope.$destroy();
207 |
208 | expect(instance.release).toHaveBeenCalled();
209 | expect(blockUI.instances._destroy).toHaveBeenCalledWith(instance);
210 |
211 | });
212 |
213 |
214 | }); // service reference count
215 |
216 | describe('pattern', function() {
217 |
218 | it('should create regexp instance', function() {
219 |
220 | var $element = $('
');
221 | var pattern = '^\/api\/quote($|\/).*';
222 |
223 | $attrs.blockUi = 'myInstance';
224 | $attrs.blockUiPattern = '/' + pattern + '/';
225 |
226 | preLinkFn($scope, $element, $attrs);
227 |
228 | var instance = blockUI.instances.myInstance;
229 |
230 | expect(instance.pattern()).toBeDefined();
231 | expect(instance.pattern().source).toBe(pattern);
232 |
233 | });
234 |
235 | }); // pattern
236 |
237 |
238 | describe('block-ui-message-class', function() {
239 |
240 | it('should expose the block-ui-message-class attribute value on the scope', function() {
241 |
242 | var $element = $('
');
243 | $attrs.blockUiMessageClass = 'my-class';
244 |
245 | preLinkFn($scope, $element, $attrs);
246 | $scope.$digest();
247 |
248 | expect($scope.$_blockUiMessageClass).toBe($attrs.blockUiMessageClass);
249 |
250 | });
251 |
252 | it('should observe the block-ui-message-class attribute value', function() {
253 |
254 | var $element = $('
');
255 |
256 | preLinkFn($scope, $element, $attrs);
257 | $scope.$digest();
258 |
259 | $attrs.blockUiMessageClass = 'my-class';
260 | $scope.$digest();
261 |
262 | expect($scope.$_blockUiMessageClass).toBe($attrs.blockUiMessageClass);
263 |
264 | });
265 |
266 | });
267 |
268 | describe('block ui state', function() {
269 |
270 | it('should expose the state on the scope', function() {
271 |
272 | var $element = $('
');
273 | var instance = blockUI.instances.get('my-instance');
274 | var state = instance.state();
275 |
276 | $attrs.blockUi = 'my-instance';
277 |
278 | preLinkFn($scope, $element, $attrs);
279 |
280 | expect($scope.$_blockUiState).toBe(state);
281 |
282 | });
283 |
284 | it('should set aria-busy to true when block is visible', function() {
285 |
286 | var blockInstance = blockUI.instances.get('myInstance');
287 | var $element = $('
');
288 | $attrs.blockUi = 'myInstance';
289 |
290 | preLinkFn($scope, $element, $attrs);
291 |
292 | blockInstance.start();
293 | $timeout.flush(); // skip the delay of the block
294 | $scope.$digest();
295 |
296 | expect($element.attr('aria-busy')).toBe('true');
297 |
298 | blockInstance.stop();
299 | $scope.$digest();
300 |
301 | expect($element.attr('aria-busy')).toBe('false');
302 | });
303 |
304 | it('should set block-ui-visible class when block is visible', function() {
305 |
306 | var blockInstance = blockUI.instances.get('myInstance');
307 | var $element = $('
');
308 | $attrs.blockUi = 'myInstance';
309 |
310 | preLinkFn($scope, $element, $attrs);
311 |
312 | blockInstance.start();
313 | $timeout.flush(); // skip the delay of the block
314 | $scope.$digest();
315 |
316 | expect($element.hasClass('block-ui-visible')).toBe(true);
317 |
318 | blockInstance.stop();
319 | $scope.$digest();
320 |
321 | expect($element.hasClass('block-ui-visible')).toBe(false);
322 |
323 | });
324 |
325 | it('should set block-ui-active class when blocking', function() {
326 |
327 | var blockInstance = blockUI.instances.get('myInstance');
328 | var $element = $('
');
329 | $attrs.blockUi = 'myInstance';
330 |
331 | preLinkFn($scope, $element, $attrs);
332 |
333 | blockInstance.start();
334 | $scope.$digest();
335 |
336 | expect($element.hasClass('block-ui-active')).toBe(true);
337 |
338 | blockInstance.stop();
339 | $scope.$digest();
340 |
341 | expect($element.hasClass('block-ui-active')).toBe(false);
342 |
343 | });
344 | });
345 |
346 | }); // pre-link
347 |
348 | // describe('post-link', function() {
349 | //
350 | // describe('block-ui-message-class', function() {
351 | //
352 | // it('should add css classes to the .block-ui-message element', function() {
353 | //
354 | // // Arrange
355 | //
356 | // //
359 | //
360 | // var messageClass = 'my-message-class';
361 | // var $blockUi = $('
');
362 | // var $message = $('
');
363 | //
364 | // $blockUi.append($message);
365 | //
366 | // $attrs.blockUiMessageClass = messageClass;
367 | //
368 | // // Act
369 | //
370 | // postLinkFn($scope, $blockUi, $attrs);
371 | // $scope.$digest();
372 | //
373 | // // Assert
374 | //
375 | // expect($message.hasClass(messageClass)).toBe(true);
376 | //
377 | // });
378 | //
379 | // it('should add css classes to the correct .block-ui-message element', function() {
380 | //
381 | // // Arrange
382 | //
383 | // //
386 | //
387 | // var messageClass = 'my-message-class';
388 | // var $blockUi = $('
');
389 | // var $message = $('
');
390 | //
391 | // $blockUi.append($message);
392 | //
393 | // $attrs.blockUiMessageClass = messageClass;
394 | //
395 | // // Act
396 | //
397 | // postLinkFn($scope, $blockUi, $attrs);
398 | // $scope.$digest();
399 | //
400 | // // Assert
401 | //
402 | // expect($message.hasClass(messageClass)).toBe(true);
403 | //
404 | // });
405 | // });
406 | //
407 | //
408 | // });
409 | });
--------------------------------------------------------------------------------
/src/angular-block-ui/config.js:
--------------------------------------------------------------------------------
1 | blkUI.constant('blockUIConfig', {
2 | templateUrl: 'angular-block-ui/angular-block-ui.ng.html',
3 | delay: 250,
4 | message: "Loading ...",
5 | autoBlock: true,
6 | resetOnException: true,
7 | requestFilter: angular.noop,
8 | autoInjectBodyBlock: true,
9 | cssClass: 'block-ui block-ui-anim-fade',
10 | blockBrowserNavigation: false
11 | });
12 |
13 |
--------------------------------------------------------------------------------
/src/angular-block-ui/config.test.js:
--------------------------------------------------------------------------------
1 | describe('angular-block-ui config', function () {
2 |
3 | var $templateCache = null;
4 |
5 | function initConfig(configCallbackFn) {
6 |
7 | var fakeModule = angular.module('i.am.so.fake', []);
8 |
9 | if(configCallbackFn) {
10 | fakeModule.config(['blockUIConfig', configCallbackFn]);
11 | }
12 |
13 | module('blockUI', 'i.am.so.fake');
14 |
15 | var config = null;
16 |
17 | inject(function(_blockUIConfig_, _$templateCache_) {
18 | config = _blockUIConfig_;
19 | $templateCache = _$templateCache_;
20 | });
21 |
22 | return config;
23 | }
24 |
25 | describe('custom template', function () {
26 |
27 | it('should override the default template', function () {
28 |
29 | // Arrange
30 |
31 | var template = '
Magic!
';
32 |
33 | var config = initConfig(function(cfg) {
34 | cfg.template = template;
35 | });
36 |
37 | // Act
38 |
39 | inject(function(_blockUIConfig_) {
40 | config = _blockUIConfig_;
41 | });
42 |
43 | // Assert
44 |
45 | expect(config.templateUrl).toBe('$$block-ui-template$$');
46 | expect($templateCache.get(config.templateUrl)).toBe(template);
47 | });
48 |
49 | });
50 |
51 | describe('cssClass', function() {
52 |
53 | it('should contain block-ui class by default', function () {
54 |
55 | // Arrange
56 |
57 |
58 | // Act
59 |
60 | var config = initConfig();
61 |
62 | // Assert
63 |
64 | expect(config.cssClass).toBeDefined();
65 | expect(config.cssClass.indexOf('block-ui')).not.toBe(-1);
66 |
67 | });
68 |
69 | it('should add single class by string', function () {
70 |
71 | // Arrange
72 |
73 | // Act
74 |
75 | var config = initConfig(function(configProvider) {
76 |
77 | configProvider.cssClass += ' my-css-class';
78 |
79 | });
80 |
81 | expect(config.cssClass.indexOf('block-ui')).not.toBe(-1);
82 | expect(config.cssClass.indexOf('my-css-class')).not.toBe(-1);
83 | });
84 |
85 | });
86 | });
87 |
--------------------------------------------------------------------------------
/src/angular-block-ui/exception-handler.test.js:
--------------------------------------------------------------------------------
1 | describe('angular-block-ui', function () {
2 |
3 | describe('exception handler', function () {
4 |
5 | var $exceptionHandler, blockUI, config, configSrc;
6 |
7 | beforeEach(function () {
8 |
9 | module('blockUI');
10 |
11 | inject(function (_$exceptionHandler_, _blockUI_, _blockUIConfig_) {
12 | $exceptionHandler = _$exceptionHandler_;
13 | blockUI = _blockUI_;
14 | config = _blockUIConfig_;
15 | });
16 |
17 | configSrc = angular.copy(config);
18 |
19 | });
20 |
21 | afterEach(function() {
22 | config = angular.copy(configSrc, config);
23 | });
24 |
25 | it('should reset the main block on exception', function () {
26 |
27 | blockUI.start(); // set blockcount to 1
28 |
29 | try {
30 | $exceptionHandler(Error('Oops'), 'Your fault');
31 | }
32 | catch (e) {
33 | }
34 |
35 | expect(blockUI.state().blockCount).toBe(0);
36 |
37 | });
38 |
39 | it('should not reset the main block on exception if specified in the config', function () {
40 |
41 | config.resetOnException = false;
42 | blockUI.start(); // set blockcount to 1
43 |
44 | try {
45 | $exceptionHandler(Error('Oops'), 'Your fault');
46 | }
47 | catch (e) {
48 | }
49 |
50 | expect(blockUI.state().blockCount).toBe(1);
51 |
52 | });
53 |
54 | it('should reset the all blocks on exception', function () {
55 |
56 | var myInstance1 = blockUI.instances.get('myInstance1');
57 | var myInstance2 = blockUI.instances.get('myInstance2');
58 |
59 | blockUI.start(); // set blockcount to 1
60 | myInstance1.start(); // set blockcount to 1
61 | myInstance2.start(); // set blockcount to 1
62 |
63 | try {
64 | $exceptionHandler(Error('Oops'), 'Your fault');
65 | }
66 | catch (e) {
67 | }
68 |
69 | expect(blockUI.state().blockCount).toBe(0);
70 | expect(myInstance1.state().blockCount).toBe(0);
71 | expect(myInstance2.state().blockCount).toBe(0);
72 |
73 | });
74 | }); // exception handler
75 | }); // angular-block-ui
--------------------------------------------------------------------------------
/src/angular-block-ui/interceptor.js:
--------------------------------------------------------------------------------
1 | blkUI.factory('blockUIHttpInterceptor', function($q, $injector, blockUIConfig, $templateCache) {
2 |
3 | var blockUI;
4 |
5 | function injectBlockUI() {
6 | blockUI = blockUI || $injector.get('blockUI');
7 | }
8 |
9 | function stopBlockUI(config) {
10 | if (blockUIConfig.autoBlock && (config && !config.$_noBlock && config.$_blocks)) {
11 | injectBlockUI();
12 | config.$_blocks.stop();
13 | }
14 | }
15 |
16 | function error(rejection) {
17 |
18 | try {
19 | stopBlockUI(rejection.config);
20 | } catch(ex) {
21 | console.log('httpRequestError', ex);
22 | }
23 |
24 | return $q.reject(rejection);
25 | }
26 |
27 | return {
28 | request: function(config) {
29 |
30 | // Only block when autoBlock is enabled ...
31 | // ... and the request doesn't match a cached template.
32 |
33 | if (blockUIConfig.autoBlock &&
34 | !(config.method == 'GET' && $templateCache.get(config.url))) {
35 |
36 | // Don't block excluded requests
37 |
38 | var result = blockUIConfig.requestFilter(config);
39 |
40 | if (result === false) {
41 | // Tag the config so we don't unblock this request
42 | config.$_noBlock = true;
43 | } else {
44 |
45 | injectBlockUI();
46 |
47 | config.$_blocks = blockUI.instances.locate(config);
48 | config.$_blocks.start(result);
49 | }
50 | }
51 |
52 | return config;
53 | },
54 |
55 | requestError: error,
56 |
57 | response: function(response) {
58 |
59 | // If the connection to the website goes down the response interceptor gets and error with "cannot read property config of null".
60 | // https://github.com/McNull/angular-block-ui/issues/53
61 |
62 | if(response) {
63 | stopBlockUI(response.config);
64 | }
65 |
66 | return response;
67 | },
68 |
69 | responseError: error
70 | };
71 |
72 | });
73 |
--------------------------------------------------------------------------------
/src/angular-block-ui/interceptor.test.js:
--------------------------------------------------------------------------------
1 | describe('block-ui-http-interceptor', function() {
2 |
3 | var blockUI, interceptor, config, configSrc, $templateCache;
4 |
5 | beforeEach(function() {
6 |
7 | module('blockUI');
8 |
9 | inject(function(_blockUI_, _blockUIHttpInterceptor_, _blockUIConfig_, _$templateCache_) {
10 | blockUI = _blockUI_;
11 | interceptor = _blockUIHttpInterceptor_;
12 | config = _blockUIConfig_;
13 | $templateCache = _$templateCache_;
14 | });
15 |
16 | configSrc = angular.copy(config);
17 |
18 | });
19 |
20 | afterEach(function() {
21 | config = angular.copy(configSrc, config);
22 | });
23 |
24 | describe('request', function() {
25 |
26 | it('should start the main block', function() {
27 |
28 | interceptor.request({ url: '/api/quote/1' });
29 |
30 | expect(blockUI.state().blockCount).toBe(1);
31 |
32 | });
33 |
34 | it('should not autoblock requests', function() {
35 |
36 | config.autoBlock = false;
37 |
38 | interceptor.request({ url: '/api/quote/1' });
39 |
40 | expect(blockUI.state().blockCount).toBe(0);
41 |
42 | });
43 |
44 | it('should not block filtered requests', function() {
45 |
46 | config.requestFilter = function(config) {
47 | return false;
48 | };
49 |
50 | interceptor.request({ url: '/api/quote/1' });
51 |
52 | expect(blockUI.state().blockCount).toBe(0);
53 |
54 | });
55 |
56 | it('should not block cached template requests', function() {
57 |
58 | var url = '/my/template.html';
59 | $templateCache.put(url, '
my template
');
60 |
61 | interceptor.request({ method: 'GET', url: url });
62 |
63 | expect(blockUI.state().blockCount).toBe(0);
64 | });
65 |
66 | it('should set the message returned by the requestFilter', function() {
67 |
68 | var message = "Saving ...";
69 |
70 | config.requestFilter = function(config) {
71 | return message;
72 | };
73 |
74 | interceptor.request({ url: '/api/quote/1' });
75 |
76 | expect(blockUI.state().message).toBe(message);
77 |
78 | });
79 |
80 | it('should block instances that match the pattern', function() {
81 |
82 | var myInstance1 = blockUI.instances.get('myInstance1');
83 | var myInstance2 = blockUI.instances.get('myInstance2');
84 |
85 | myInstance1.pattern(/^\/api\/quote\/\d+$/);
86 | myInstance2.pattern(/^\/api\/quote/);
87 |
88 | interceptor.request({ url: '/api/quote/1' });
89 |
90 | expect(blockUI.state().blockCount).toBe(0);
91 | expect(myInstance1.state().blockCount).toBe(1);
92 | expect(myInstance2.state().blockCount).toBe(1);
93 | });
94 |
95 | it('should not block instances that do not match the pattern', function() {
96 |
97 | var myInstance1 = blockUI.instances.get('myInstance1');
98 | var myInstance2 = blockUI.instances.get('myInstance2');
99 |
100 | myInstance1.pattern(/^\/api\/quote\/\d+$/);
101 | myInstance2.pattern(/^\/api\/quote/);
102 |
103 | interceptor.request({ url: '/api/user/1' });
104 |
105 | expect(blockUI.state().blockCount).toBe(1);
106 | expect(myInstance1.state().blockCount).toBe(0);
107 | expect(myInstance2.state().blockCount).toBe(0);
108 | });
109 |
110 | });
111 |
112 | describe('error', function() {
113 |
114 | it('should stop all the blocks when an error has occured', function() {
115 |
116 | // https://github.com/McNull/angular-block-ui/pull/9/files
117 |
118 | // Setup to block instances
119 |
120 | var myInstance1 = blockUI.instances.get('myInstance1');
121 | var myInstance2 = blockUI.instances.get('myInstance2');
122 |
123 | myInstance1.pattern(/^\/api\/quote\/\d+$/);
124 | myInstance2.pattern(/^\/api\/quote/);
125 |
126 | // Create a fake HttpRequest config that contains the
127 | // block instances.
128 |
129 | var config = {
130 | $_blocks: blockUI.instances.locate({ url: '/api/quote/1' })
131 | };
132 |
133 | // Increment the block count
134 |
135 | config.$_blocks.start();
136 |
137 | // Just to make sure
138 |
139 | expect(myInstance1.state().blockCount).toBe(1);
140 | expect(myInstance2.state().blockCount).toBe(1);
141 |
142 | // Act
143 |
144 | interceptor.requestError({ config: config });
145 |
146 | // Assert
147 |
148 | expect(myInstance1.state().blockCount).toBe(0);
149 | expect(myInstance2.state().blockCount).toBe(0);
150 |
151 | });
152 |
153 | });
154 |
155 | describe('response', function() {
156 |
157 | it('should stop the main block', function() {
158 |
159 | var blocks = blockUI.instances.locate({ url: '/api/quote/123' });
160 |
161 | blockUI.start(); // set blockcount to 1
162 |
163 | interceptor.response({ config: { $_blocks: blocks }});
164 |
165 | expect(blockUI.state().blockCount).toBe(0);
166 |
167 | });
168 |
169 | it('should not stop the main block when autoBlock is false', function() {
170 |
171 | var blocks = blockUI.instances.locate({ url: '/api/quote/123' });
172 |
173 | config.autoBlock = false;
174 |
175 | blockUI.start(); // set blockcount to 1
176 |
177 | interceptor.response({ config: { $_blocks: blocks }});
178 |
179 | expect(blockUI.state().blockCount).toBe(1);
180 |
181 | });
182 |
183 | it('should not stop blocks that are filtered', function() {
184 |
185 | var blocks = blockUI.instances.locate({ url: '/api/quote/123' });
186 |
187 | blockUI.start(); // set blockcount to 1
188 |
189 | interceptor.response({ config: { $_noBlock: true, $_blocks: blocks }});
190 |
191 | expect(blockUI.state().blockCount).toBe(1);
192 |
193 | });
194 |
195 | it('should stop $_blocks that matched the pattern', function() {
196 |
197 | var myInstance1 = blockUI.instances.get('myInstance1');
198 | var myInstance2 = blockUI.instances.get('myInstance2');
199 |
200 | myInstance1.pattern(/^\/api\/quote\/\d+$/);
201 | myInstance2.pattern(/^\/api\/quote/);
202 |
203 | blockUI.start(); // set blockcount to 1
204 | myInstance1.start(); // set blockcount to 1
205 | myInstance2.start(); // set blockcount to 1
206 |
207 | var blocks = blockUI.instances.locate({ url: '/api/quote/123' });
208 |
209 | interceptor.response({ config: { $_blocks: blocks }});
210 |
211 | expect(blockUI.state().blockCount).toBe(1);
212 | expect(myInstance1.state().blockCount).toBe(0);
213 | expect(myInstance2.state().blockCount).toBe(0);
214 |
215 | });
216 | });
217 | });
--------------------------------------------------------------------------------
/src/angular-block-ui/service.js:
--------------------------------------------------------------------------------
1 | blkUI.factory('blockUI', function(blockUIConfig, $timeout, blockUIUtils, $document) {
2 |
3 | var $body = $document.find('body');
4 |
5 | // These properties are not allowed to be specified in the start method.
6 | var reservedStateProperties = ['id', 'blockCount', 'blocking'];
7 |
8 | function BlockUI(id) {
9 |
10 | var self = this;
11 |
12 | var state = {
13 | id: id,
14 | blockCount: 0,
15 | message: blockUIConfig.message,
16 | blocking: false
17 | }, startPromise, doneCallbacks = [];
18 |
19 | this._id = id;
20 |
21 | this._refs = 0;
22 |
23 | this.start = function(messageOrOptions) {
24 |
25 | messageOrOptions = messageOrOptions || {};
26 |
27 | if(angular.isString(messageOrOptions)) {
28 | messageOrOptions = {
29 | message: messageOrOptions
30 | };
31 | } else {
32 | angular.forEach(reservedStateProperties, function(x) {
33 | if(messageOrOptions[x]) {
34 | throw new Error('The property ' + x + ' is reserved for the block state.');
35 | }
36 | });
37 | }
38 |
39 | angular.extend(state, messageOrOptions);
40 |
41 | if(state.blockCount > 0) {
42 | state.message = messageOrOptions.message || state.message || blockUIConfig.message;
43 | } else {
44 | state.message = messageOrOptions.message || blockUIConfig.message;
45 | }
46 |
47 | // if(state.blockCount > 0) {
48 | // messageOrOptions = messageOrOptions || state.message || blockUIConfig.message;
49 | // } else {
50 | // messageOrOptions = messageOrOptions || blockUIConfig.message;
51 | // }
52 |
53 | // state.message = messageOrOptions;
54 |
55 | state.blockCount++;
56 |
57 | // Check if the focused element is part of the block scope
58 |
59 | var $ae = angular.element($document[0].activeElement);
60 |
61 | if($ae.length && blockUIUtils.isElementInBlockScope($ae, self)) {
62 |
63 | // Let the active element lose focus and store a reference
64 | // to restore focus when we're done (reset)
65 |
66 | self._restoreFocus = $ae[0];
67 |
68 | // https://github.com/McNull/angular-block-ui/issues/13
69 | // http://stackoverflow.com/questions/22698058/apply-already-in-progress-error-when-using-typeahead-plugin-found-to-be-relate
70 | // Queue the blur after any ng-blur expression.
71 |
72 | $timeout(function() {
73 | // Ensure we still need to blur
74 | // Don't restore if active element is body, since this causes IE to switch windows (see http://tjvantoll.com/2013/08/30/bugs-with-document-activeelement-in-internet-explorer/)
75 | if (self._restoreFocus && self._restoreFocus !== $body[0]) {
76 | self._restoreFocus.blur();
77 | }
78 | });
79 | }
80 |
81 | if (!startPromise && blockUIConfig.delay !== 0) {
82 | startPromise = $timeout(block, blockUIConfig.delay);
83 | } else if (blockUIConfig.delay === 0) {
84 | block();
85 | }
86 |
87 | function block () {
88 | startPromise = null;
89 | state.blocking = true;
90 | }
91 | };
92 |
93 | this._cancelStartTimeout = function() {
94 | if (startPromise) {
95 | $timeout.cancel(startPromise);
96 | startPromise = null;
97 | }
98 | };
99 |
100 | this.stop = function() {
101 | state.blockCount = Math.max(0, --state.blockCount);
102 |
103 | if (state.blockCount === 0) {
104 | self.reset(true);
105 | }
106 | };
107 |
108 | this.isBlocking = function () {
109 | return state.blocking;
110 | };
111 |
112 | this.message = function(value) {
113 | state.message = value;
114 | };
115 |
116 | this.pattern = function(regexp) {
117 | if (regexp !== undefined) {
118 | self._pattern = regexp;
119 | }
120 |
121 | return self._pattern;
122 | };
123 |
124 | this.reset = function(executeCallbacks) {
125 |
126 | self._cancelStartTimeout();
127 | state.blockCount = 0;
128 | state.blocking = false;
129 |
130 | // Restore the focus to the element that was active
131 | // before the block start, but not if the user has
132 | // focused something else while the block was active.
133 |
134 | if(self._restoreFocus &&
135 | (!$document[0].activeElement || $document[0].activeElement === $body[0])) {
136 |
137 | //IE8 will throw if element for setting focus is invisible
138 | try {
139 | self._restoreFocus.focus();
140 | } catch(e1) {
141 | (function () {
142 | var elementToFocus = self._restoreFocus;
143 | $timeout(function() {
144 | if(elementToFocus) {
145 | try {
146 | elementToFocus.focus();
147 | } catch(e2) { }
148 | }
149 | },100);
150 | })();
151 | }
152 |
153 | self._restoreFocus = null;
154 | }
155 |
156 | try {
157 | if (executeCallbacks) {
158 | angular.forEach(doneCallbacks, function(cb) {
159 | cb();
160 | });
161 | }
162 | } finally {
163 | doneCallbacks.length = 0;
164 | }
165 | };
166 |
167 | this.done = function(fn) {
168 | doneCallbacks.push(fn);
169 | };
170 |
171 | this.state = function() {
172 | return state;
173 | };
174 |
175 | this.addRef = function() {
176 | self._refs += 1;
177 | };
178 |
179 | this.release = function() {
180 | if(--self._refs <= 0) {
181 | mainBlock.instances._destroy(self);
182 | }
183 | };
184 | }
185 |
186 | var instances = [];
187 |
188 | instances.get = function(id) {
189 |
190 | if(!isNaN(id)) {
191 | throw new Error('BlockUI id cannot be a number');
192 | }
193 |
194 | var instance = instances[id];
195 |
196 | if(!instance) {
197 | // TODO: ensure no array instance trashing [xxx] -- current workaround: '_' + $scope.$id
198 | instance = instances[id] = new BlockUI(id);
199 | instances.push(instance);
200 | }
201 |
202 | return instance;
203 | };
204 |
205 | instances._destroy = function(idOrInstance) {
206 | if (angular.isString(idOrInstance)) {
207 | idOrInstance = instances[idOrInstance];
208 | }
209 |
210 | if (idOrInstance) {
211 | idOrInstance.reset();
212 |
213 | var i = blockUIUtils.indexOf(instances, idOrInstance);
214 | instances.splice(i, 1);
215 |
216 | delete instances[idOrInstance.state().id];
217 | }
218 | };
219 |
220 | instances.locate = function(request) {
221 |
222 | var result = [];
223 |
224 | // Add function wrappers that will be executed on every item
225 | // in the array.
226 |
227 | blockUIUtils.forEachFnHook(result, 'start');
228 | blockUIUtils.forEachFnHook(result, 'stop');
229 |
230 | var i = instances.length;
231 |
232 | while(i--) {
233 | var instance = instances[i];
234 | var pattern = instance._pattern;
235 |
236 | if(pattern && pattern.test(request.url)) {
237 | result.push(instance);
238 | }
239 | }
240 |
241 | if(result.length === 0) {
242 | result.push(mainBlock);
243 | }
244 |
245 | return result;
246 | };
247 |
248 | // Propagate the reset to all instances
249 |
250 | blockUIUtils.forEachFnHook(instances, 'reset');
251 |
252 | var mainBlock = instances.get('main');
253 |
254 | mainBlock.addRef();
255 | mainBlock.instances = instances;
256 |
257 | return mainBlock;
258 | });
259 |
--------------------------------------------------------------------------------
/src/angular-block-ui/utils.js:
--------------------------------------------------------------------------------
1 |
2 | blkUI.factory('blockUIUtils', function() {
3 |
4 | var $ = angular.element;
5 |
6 | var utils = {
7 | buildRegExp: function(pattern) {
8 | var match = pattern.match(/^\/(.*)\/([gim]*)$/), regExp;
9 |
10 | if(match) {
11 | regExp = new RegExp(match[1], match[2]);
12 | } else {
13 | throw Error('Incorrect regular expression format: ' + pattern);
14 | }
15 |
16 | return regExp;
17 | },
18 | forEachFn: function(arr, fnName, args) {
19 | var i = arr.length;
20 | while(i--) {
21 | var t = arr[i];
22 | t[fnName].apply(t, args);
23 | }
24 | },
25 | forEachFnHook: function(arr, fnName) {
26 | arr[fnName] = function() {
27 | utils.forEachFn(this, fnName, arguments);
28 | }
29 | },
30 | isElementInBlockScope: function($element, blockScope) {
31 | var c = $element.inheritedData('block-ui');
32 |
33 | while(c) {
34 | if(c === blockScope) {
35 | return true;
36 | }
37 |
38 | c = c._parent;
39 | }
40 |
41 | return false;
42 | },
43 | findElement: function ($element, predicateFn, traverse) {
44 | var ret = null;
45 |
46 | if (predicateFn($element)) {
47 | ret = $element;
48 | } else {
49 |
50 | var $elements;
51 |
52 | if (traverse) {
53 | $elements = $element.parent();
54 | } else {
55 | $elements = $element.children();
56 | }
57 |
58 | var i = $elements.length;
59 | while (!ret && i--) {
60 | ret = utils.findElement($($elements[i]), predicateFn, traverse);
61 | }
62 | }
63 |
64 | return ret;
65 | },
66 | indexOf: function(arr, obj, start) {
67 | // if(Array.prototype.indexOf) {
68 | // return arr.indexOf(obj, start);
69 | // }
70 |
71 | for (var i = (start || 0), j = arr.length; i < j; i++) {
72 | if (arr[i] === obj) {
73 | return i;
74 | }
75 | }
76 |
77 | return -1;
78 | }
79 | };
80 |
81 | return utils;
82 |
83 | });
--------------------------------------------------------------------------------
/src/angular-block-ui/utils.test.js:
--------------------------------------------------------------------------------
1 | describe('block-ui-utils', function() {
2 |
3 | var utils, $ = angular.element;
4 |
5 | beforeEach(function() {
6 | module('blockUI');
7 |
8 | inject(function(blockUIUtils) {
9 | utils = blockUIUtils;
10 | });
11 | });
12 |
13 | describe('buildRegExp', function() {
14 | it('should create a RegExp object', function() {
15 | var result = utils.buildRegExp('/\d+/');
16 |
17 | expect(result).toBeDefined();
18 | expect(result.constructor.name).toBe('RegExp');
19 | });
20 |
21 | it('should parse expression', function() {
22 | var expression = '\d\d\d';
23 | var result = utils.buildRegExp('/' + expression + '/');
24 |
25 | expect(result.source).toBe(expression);
26 | });
27 |
28 | it('should parse global flag', function() {
29 |
30 | var result = utils.buildRegExp('/123/g');
31 |
32 | expect(result.global).toBe(true);
33 | expect(result.ignoreCase).toBe(false);
34 | expect(result.multiline).toBe(false);
35 | });
36 |
37 | it('should parse ignoreCase flag', function() {
38 |
39 | var result = utils.buildRegExp('/123/i');
40 |
41 | expect(result.global).toBe(false);
42 | expect(result.ignoreCase).toBe(true);
43 | expect(result.multiline).toBe(false);
44 | });
45 |
46 | it('should parse multiline flag', function() {
47 |
48 | var result = utils.buildRegExp('/123/m');
49 |
50 | expect(result.global).toBe(false);
51 | expect(result.ignoreCase).toBe(false);
52 | expect(result.multiline).toBe(true);
53 | });
54 | }); // buildRegExp
55 |
56 | describe('forEachFn', function() {
57 |
58 | it('should execute function on each element', function() {
59 |
60 | function Item() {
61 | this.fn = function() {
62 | this.executed = true;
63 | }
64 | }
65 |
66 | var arr = [ new Item(), new Item(), new Item() ];
67 |
68 | utils.forEachFn(arr, 'fn');
69 |
70 | expect(arr[0].executed).toBe(true);
71 | expect(arr[1].executed).toBe(true);
72 | expect(arr[2].executed).toBe(true);
73 | });
74 |
75 | it('should pass arguments to each function call', function() {
76 |
77 | function Item() {
78 | this.fn = function(v1, v2, v3) {
79 | this.v1 = v1;
80 | this.v2 = v2;
81 | this.v3 = v3;
82 | }
83 | }
84 |
85 | var arr = [ new Item() ];
86 | var args = [ 1, 2, 3 ];
87 | utils.forEachFn(arr, 'fn', args);
88 |
89 | expect(arr[0].v1).toBe(1);
90 | expect(arr[0].v2).toBe(2);
91 | expect(arr[0].v3).toBe(3);
92 |
93 | });
94 |
95 | it('should be able to be hook function', function() {
96 |
97 | function Item() {
98 | this.fn = function(v1, v2, v3) {
99 | this.v1 = v1;
100 | this.v2 = v2;
101 | this.v3 = v3;
102 | }
103 | }
104 |
105 | var arr = [ new Item() ];
106 |
107 | utils.forEachFnHook(arr, 'fn');
108 |
109 | arr.fn(1,2,3);
110 |
111 | expect(arr[0].v1).toBe(1);
112 | expect(arr[0].v2).toBe(2);
113 | expect(arr[0].v3).toBe(3);
114 |
115 | });
116 |
117 | }); // forEachFn
118 |
119 | describe('findElement', function() {
120 |
121 | it('should return the current element', function() {
122 |
123 | function myPredicate($e) {
124 | return $e.hasClass('my-class');
125 | }
126 |
127 | var $element = $('
');
128 |
129 | var result = utils.findElement($element, myPredicate);
130 |
131 | expect(result).toBe($element);
132 |
133 | });
134 |
135 | it('should return the child element', function() {
136 |
137 | function myPredicate($e) {
138 | return $e.hasClass('my-class');
139 | }
140 |
141 | var $element = $('
');
142 | var expected = $element.children()[0];
143 |
144 | var result = utils.findElement($element, myPredicate);
145 |
146 | expect(result[0]).toBe(expected);
147 |
148 | });
149 |
150 | it('should return the parent element', function() {
151 |
152 | function myPredicate($e) {
153 | return $e.hasClass('my-class');
154 | }
155 |
156 | var expected = $('
');
157 | var $element = $(expected.children()[0]);
158 |
159 | var result = utils.findElement($element, myPredicate, true);
160 |
161 | expect(result[0]).toBe(expected[0]);
162 |
163 | });
164 |
165 | });
166 |
167 | });
--------------------------------------------------------------------------------
/src/angular-delay/angular-delay.js:
--------------------------------------------------------------------------------
1 | angular.module('delay', []);
2 |
3 | angular.module('delay').constant('delayConfig', {
4 | enabled: true, // Enable or disable the delay
5 | timeout: {
6 | min: 200, // Minimum delay
7 | max: 1500 // Maximum delay
8 | },
9 | excludes: [] // Array of RegExp of urls to exclude
10 | });
11 |
12 | angular.module('delay').factory('delayHttpInterceptor', function($q, $templateCache, $timeout, delayConfig) {
13 |
14 | function includeRequest(config) {
15 | if (delayConfig.enabled && $templateCache.get(config.url) === undefined) {
16 |
17 | var patterns = delayConfig.excludes;
18 | var i = patterns.length;
19 |
20 | while (i--) {
21 | if (patterns[i].test(config.url)) {
22 | return false;
23 | }
24 | }
25 |
26 | return true;
27 | }
28 | }
29 |
30 | var t1 = delayConfig.timeout.min;
31 | var t2 = delayConfig.timeout.max - t1;
32 |
33 | return {
34 | request: function(config) {
35 |
36 | // Don't delay cached requests
37 |
38 | if (!includeRequest(config)) {
39 | return config;
40 | }
41 |
42 | var d = $q.defer();
43 |
44 | var delay = Math.floor(Math.random() * t2) + t1;
45 |
46 | $timeout(function() {
47 | d.resolve(config);
48 | }, delay);
49 |
50 | return d.promise;
51 | }
52 | };
53 | });
54 |
55 | angular.module('delay').config(function($httpProvider) {
56 | $httpProvider.interceptors.push('delayHttpInterceptor');
57 | });
58 |
--------------------------------------------------------------------------------
/src/angular-showdown/angular-showdown.js:
--------------------------------------------------------------------------------
1 | angular.module('showdown', []);
2 |
3 | angular.module('showdown').directive('showdown', function(showdown, showdownConfig) {
4 |
5 | return {
6 | restrict: 'EA',
7 | link: function($scope, $element, $attrs) {
8 |
9 | var options = angular.copy(showdownConfig);
10 |
11 | options.outline = $attrs.showdownSrc ? $attrs.showdownSrc == 'true' : options.outline;
12 | options.src = $attrs.showdownSrc;
13 |
14 | $scope.$watch($attrs.showdownModel, function(value) {
15 | options.markdown = value;
16 | showdown.updateElement($element, options);
17 | });
18 | }
19 | };
20 | });
21 |
22 | angular.module('showdown').provider('showdownConfig', function() {
23 | var config = {
24 | extensions: [],
25 | css: {
26 | loading: 'showdown-loading',
27 | error: 'showdown-error'
28 | },
29 | outline: true
30 | };
31 | this.$get = function() {
32 | return config;
33 | };
34 | });
35 |
36 | angular.module('showdown').factory('showdown', function($http) {
37 |
38 | var _converter;
39 |
40 | function getConverter(options) {
41 |
42 | // options: { extensions: ['twitter', mine] }
43 | // TODO: Locate (and create) converter based on extensions
44 |
45 | _converter = _converter || new Showdown.converter(options);
46 |
47 | return _converter;
48 | }
49 |
50 | function makeHtml(options) {
51 |
52 | var converter = getConverter(options);
53 |
54 | return converter.makeHtml(options.markdown || options.defaultMarkdown);
55 | }
56 |
57 | function outline(text) {
58 | if (text) {
59 |
60 | // trim leading empty lines
61 |
62 | text = text.replace(/^\s*\n/, '');
63 |
64 | // grab the first ident on the first line
65 |
66 | var m = text.match(/^[ \t]+/);
67 | if (m && m.length) {
68 |
69 | // build a pattern to strip out the located ident from all lines
70 |
71 | var p = '^[ \t]{' + m[0].length + '}';
72 | var r = new RegExp(p, 'gm');
73 | text = text.replace(r, '');
74 | }
75 | }
76 |
77 | return text;
78 | }
79 |
80 | function updateElement($element, options) {
81 |
82 | if (options.defaultMarkdown === undefined) {
83 |
84 | var t = $element.text();
85 |
86 | if (options.outline) {
87 | t = outline(t);
88 | }
89 |
90 | options.defaultMarkdown = t;
91 | }
92 |
93 | if (options.src) {
94 |
95 | $element.addClass(options.css.loading);
96 | $element.removeClass(options.css.error);
97 | options.markdown = '';
98 |
99 | $http.get(options.src).then(function(response) {
100 | options.markdown = response.data;
101 | $element.removeClass(options.css.error);
102 | })['catch'](function() {
103 | $element.addClass(options.css.error);
104 | })['finally'](function() {
105 | $element.removeClass(options.css.loading);
106 | options.src = undefined;
107 | updateElement($element, options);
108 | });
109 | } else {
110 | var html = makeHtml(options);
111 | $element.html(html);
112 | }
113 |
114 | }
115 |
116 | return {
117 | makeHtml: makeHtml,
118 | updateElement: updateElement,
119 | outline: outline
120 | };
121 | });
122 |
--------------------------------------------------------------------------------
/src/app/app.css:
--------------------------------------------------------------------------------
1 |
2 | /* Large desktop */
3 | @media (min-width: 1200px) { }
4 |
5 | /* Portrait tablet to landscape and desktop */
6 | @media (min-width: 768px) and (max-width: 979px) { }
7 |
8 | /* Landscape phone to portrait tablet */
9 | @media (max-width: 767px) { }
10 |
11 | /* Landscape phones and down */
12 | @media (max-width: 480px) { }
13 |
14 | .text-select-disable, .btn {
15 | -webkit-touch-callout: none;
16 | -webkit-user-select: none;
17 | -khtml-user-select: none;
18 | -moz-user-select: none;
19 | -ms-user-select: none;
20 | user-select: none;
21 | }
22 |
23 | html {
24 | overflow-y: scroll;
25 | }
26 |
27 | .spacer-sm {
28 | margin-top: 10px;
29 | }
30 |
31 | .spacer {
32 | margin-top: 20px;
33 | }
34 |
35 | .spacer-lg {
36 | margin-top: 40px;
37 | }
38 | body {
39 | padding-bottom: 80px;
40 | }
--------------------------------------------------------------------------------
/src/app/app.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp', [
2 | 'ngRoute',
3 | 'ngSanitize',
4 | // 'ngResource',
5 | 'ngAnimate',
6 | 'blockUI',
7 | 'markdown',
8 | 'responseLag',
9 | 'inform',
10 | 'inform-exception',
11 | 'inform-http-exception'
12 | ], null).value('navItems', [
13 | {
14 | text: 'Home',
15 | url: '#!/'
16 | },
17 | {
18 | text: 'Documentation',
19 | url: '#!/examples',
20 | pattern: '/examples(/.*)?'
21 | }
22 | ]).config(function ($routeProvider, examplesRoutes) {
23 |
24 | $routeProvider.when('/', {
25 | templateUrl: 'app/main/home.ng.html'
26 | });
27 |
28 | angular.forEach(examplesRoutes, function (value, key) {
29 | $routeProvider.when(key, value);
30 | });
31 |
32 | $routeProvider.otherwise({
33 | redirectTo: '/'
34 | });
35 |
36 | }).config(function (blockUIConfig, responseLagConfig, $locationProvider) {
37 |
38 | // Enable hashbangs
39 |
40 | $locationProvider.hashPrefix('!');
41 |
42 | blockUIConfig.blockBrowserNavigation = true;
43 |
44 | if(window.location.search.indexOf('delay=false')!=-1 ||
45 | window.location.search.indexOf('_escaped_fragment_')!=-1 ||
46 | window.navigator.userAgent.indexOf('Prerender')!=-1) {
47 |
48 | responseLagConfig.enabled = false;
49 | blockUIConfig.autoBlock = false;
50 | blockUIConfig.autoInjectBodyBlock = false;
51 | } else {
52 | responseLagConfig.excludes.push(/.*\.md/i);
53 | responseLagConfig.enabled = true;
54 | responseLagConfig.timeout.min = 750;
55 | responseLagConfig.timeout.max = 1500;
56 |
57 | // // Change the displayed message based on the http verbs being used.
58 | // blockUIConfig.requestFilter = function(config) {
59 | //
60 | // var message;
61 | //
62 | // switch(config.method) {
63 | //
64 | // case 'GET':
65 | // message = 'Getting ...';
66 | // break;
67 | //
68 | // case 'POST':
69 | // message = 'Posting ...';
70 | // break;
71 | //
72 | // case 'DELETE':
73 | // message = 'Deleting ...';
74 | // break;
75 | //
76 | // case 'PUT':
77 | // message = 'Putting ...';
78 | // break;
79 | // }
80 | //
81 | // return message;
82 | //
83 | // };
84 | }
85 |
86 | // blockUIConfig.template = '
{{ state | json }}
';
87 |
88 | // blockUIConfig.delay = 200;
89 |
90 | }).controller('MainController', function($scope, blockUI) {
91 | // blockUI.start();
92 | });
93 |
--------------------------------------------------------------------------------
/src/app/common/directives.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').directive('confirm', ['$window', function($window) {
2 | return {
3 | restrict: 'A',
4 | priority: 100,
5 | link: function(scope, element, attr) {
6 | element.bind('click', function(e) {
7 | var msg = attr.confirm;
8 |
9 | if(!$window.confirm(msg)) {
10 | e.stopImmediatePropagation();
11 | e.preventDefault();
12 | }
13 | });
14 | }
15 | };
16 | }]);
17 |
--------------------------------------------------------------------------------
/src/app/examples/element-blocking.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | It's also possible to block individual elements by using the block-ui directive.
5 | Blocking individual elements can be done manually or automatically by informing the module which request correlates with a certain element.
6 | If no match can be found for a certain request, the main block will be initiated.
7 |
8 |
9 |
Automatic Element Blocking
10 |
11 | To make automatic blocking work the block-ui directive needs a regular expression pattern provided by the block-ui-pattern attribute.
12 |
13 |
14 |
15 |
19 |
22 |
23 |
Html
24 |
<!--
25 | Mark this region as blockable for any request that
26 | matches the provided pattern: app/examples/data-array.json
27 | -->
28 | <div block-ui block-ui-pattern="/^app\/examples\/data-array\.json$/">
29 | <div my-demo-table limit="5"></div>
30 | </div>
31 |
32 |
33 |
Manual Element Blocking
34 |
35 | Just like the main blockUI instance, blocking individual elements can also be done manually.
36 | By providing the block-ui an name the associated blockUI instance can be requested in our controller or service.
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
45 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
46 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
47 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
48 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
49 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
50 |
51 |
52 |
Toggle Block
53 |
54 |
55 |
Html
56 |
<div block-ui="myBlock">
57 | <p>Lorem ipsum dolor sit amet ... </p>
58 | </div>
59 | <button ng-click="toggleBlock()">Toggle Block</button>
60 |
61 |
JavaScript
62 |
// Get a reference to the blockUI instance
63 | var myBlock = blockUI.instances.get('myBlock');
64 |
65 | $scope.toggleBlock = function() {
66 | if(myBlock.state().blocking) {
67 | myBlock.stop();
68 | } else {
69 | myBlock.start();
70 | }
71 | };
72 |
73 |
74 |
Shared blockUI instances
75 |
76 | Multiple elements can be associated with the same blockUI instance or with the same request pattern.
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
Sharing blockUI instance
85 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
86 |
87 |
88 |
89 |
90 |
91 |
92 |
Sharing blockUI instance
93 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
94 |
95 |
96 |
97 |
98 |
99 |
100 |
Sharing blockUI instance
101 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
102 |
103 |
104 |
105 |
106 |
107 |
108 | Toggle Block
109 |
110 |
111 |
--------------------------------------------------------------------------------
/src/app/examples/element-blocking.js:
--------------------------------------------------------------------------------
1 |
2 | angular.module('myApp').controller('ElementBlockingController', function($scope, blockUI) {
3 |
4 | $scope.toggleBlock = function(name) {
5 |
6 | // Get a reference to the blockUI instance
7 |
8 | var myBlock = blockUI.instances.get(name);
9 |
10 | if(myBlock.state().blocking) {
11 | myBlock.stop();
12 | } else {
13 | myBlock.start();
14 | }
15 | };
16 |
17 | });
18 |
19 |
--------------------------------------------------------------------------------
/src/app/examples/examples.css:
--------------------------------------------------------------------------------
1 | /*@media (min-width: 768px) {
2 | .example {
3 | margin-left: 0;
4 | margin-right: 0;
5 | background-color: #fff;
6 | border-width: 1px;
7 | border-color: #ddd;
8 | border-radius: 4px 4px 0 0;
9 | box-shadow: none;
10 | }
11 | }
12 | .example {
13 | position: relative;
14 | padding: 45px 15px 15px;
15 | margin: 0 -15px 15px;
16 | background-color: #fafafa;
17 | box-shadow: inset 0 3px 6px rgba(0, 0, 0, .05);
18 | border-color: #e5e5e5 #eee #eee;
19 | border-style: solid;
20 | border-width: 1px 0;
21 | }*/
22 |
23 | .example {
24 | position: relative;
25 | padding: 45px 15px 15px;
26 | background-color: #fff;
27 | border-color: #ddd;
28 | border-style: solid;
29 | border-width: 1px;
30 | }
31 |
32 | .example:after {
33 | content:"Example";
34 | position: absolute;
35 | top: 15px;
36 | left: 15px;
37 | font-size: 12px;
38 | font-weight: 700;
39 | color: #bbb;
40 | text-transform: uppercase;
41 | letter-spacing: 1px;
42 | }
43 |
44 | .form-block .block-ui-message-container {
45 | top: 30%;
46 | }
47 |
48 | .example-container {
49 | min-height: 300px;
50 | overflow: hidden;
51 | }
52 |
53 | /*.example-container.block-ui-active {*/
54 | /*background-color: yellow;*/
55 | /*}*/
56 |
57 | /*.example-container.block-ui-visible {*/
58 | /*background-color: green;*/
59 | /*}*/
60 |
61 | /*.login-form-block .block-ui-overlay.block-ui-visible {
62 | background-color: yellow;
63 | }*/
64 |
65 |
--------------------------------------------------------------------------------
/src/app/examples/examples.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').constant('examplesRoutes', {
2 | '/examples': {
3 | redirectTo: '/examples/documentation'
4 | },
5 | '/examples/:example': {
6 | templateUrl: 'app/examples/examples.ng.html',
7 | controller: 'ExamplesController'
8 | }
9 | });
10 |
11 | angular.module('myApp').controller('ExamplesController', function($scope, $routeParams) {
12 |
13 | function urlToName(str) {
14 | str = str.charAt(0).toUpperCase() + str.slice(1);
15 | return str.replace(/\W+(.)/g, function(i, c) {
16 | return ' ' + c.toUpperCase();
17 | });
18 | }
19 |
20 | function nameToUrl(str) {
21 | str = str.toLowerCase();
22 | return str.replace(/\s+/g, '-');
23 | }
24 |
25 | function indexOfExample(name, examples) {
26 |
27 | var i = examples.length;
28 | while (i--) {
29 | if (examples[i].name === name) {
30 | return i;
31 | }
32 | }
33 | return -1;
34 | }
35 |
36 | $scope.examples = [{
37 | name: 'Documentation',
38 | tmpl: 'app/examples/readme.html'
39 | }, {
40 | name: 'Manual Blocking Examples',
41 | tmpl: 'app/examples/manual-blocking.html'
42 | }, {
43 | name: 'Element Blocking Examples',
44 | tmpl: 'app/examples/element-blocking.html'
45 | }, {
46 | name: 'Focus Management',
47 | tmpl: 'app/examples/focus-input.html'
48 | }];
49 |
50 | $scope.examples.active = indexOfExample(urlToName($routeParams.example), $scope.examples);
51 | $scope.examples.getUrl = function(example) {
52 | return '#!/examples/' + nameToUrl(example.name);
53 | };
54 |
55 | });
56 |
--------------------------------------------------------------------------------
/src/app/examples/examples.ng.html:
--------------------------------------------------------------------------------
1 |
2 |
Angular BlockUI Documentation & Examples
3 |
4 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/app/examples/focus-input.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | To prevent forms from re-submitting data, focused elements will be blured
5 | whenever a containing block is active.
6 | Unless the focus has been changed by the user while the (non-global) block was active, the focus is restored
7 | whenever the block has finished.
8 |
9 |
10 |
11 |
Restoring focus to any input element other than the submit button is not possible in any version of Internet
12 | Explorer . All other major browsers should be able to restore the focus to any previous element.
13 |
14 |
15 | The example below contains two forms both with their own blocking scope. Blocking is activated whenever the form is
16 | submitted by pressing enter in one of the inputs or by clicking on the submit button.
17 |
18 |
19 |
20 |
21 |
22 |
38 |
39 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/app/examples/focus-input.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').controller('FocusInputExampleController', function($scope, blockUI, $timeout) {
2 |
3 | var loginFormBlock = blockUI.instances.get('loginFormBlock');
4 |
5 | $scope.login = function() {
6 | loginFormBlock.start('Validating account ...');
7 |
8 | $timeout(function() {
9 | loginFormBlock.stop();
10 | }, 2000);
11 | };
12 |
13 | var searchFormBlock = blockUI.instances.get('searchFormBlock');
14 |
15 | $scope.search = function() {
16 | searchFormBlock.start('Searching ...');
17 |
18 | $timeout(function() {
19 | searchFormBlock.stop();
20 | }, 2000);
21 | };
22 |
23 | $scope.globalBlock = function() {
24 |
25 | blockUI.start('Blocking whole page ...');
26 |
27 | $timeout(function() {
28 | blockUI.stop();
29 | }, 2000);
30 |
31 | };
32 | });
--------------------------------------------------------------------------------
/src/app/examples/manual-blocking.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | The module blocks the user interface automatically on each http request done by Angular, but you can also perform the blocking manually. Below are some examples on how to do this.
5 |
6 |
7 |
Start and stop block
8 |
9 | Start the block manually and stop it after 2 seconds.
10 |
11 |
12 | Demo
13 |
14 |
blockUI.start();
15 |
16 | $timeout(function() {
17 | blockUI.stop();
18 | }, 2000);
19 |
20 |
Block with custom message
21 |
22 | Start the block and display a custom message.
23 |
24 |
25 |
Note: the default message can be specified in the configuration.
26 |
27 |
28 | Demo
29 |
30 |
blockUI.start("My custom message");
31 |
32 | $timeout(function() {
33 | blockUI.stop();
34 | }, 2000);
35 |
36 |
Update messages
37 |
38 | Start the block and modify the displayed message.
39 |
40 |
41 | Demo
42 |
43 |
blockUI.start();
44 |
45 | $timeout(function() {
46 | blockUI.message('Still loading ...');
47 | }, 1000);
48 |
49 | $timeout(function() {
50 | blockUI.message('Almost there ...');
51 | }, 2000);
52 |
53 | $timeout(function() {
54 | blockUI.message('Cleaning up ...');
55 | }, 3000);
56 |
57 | $timeout(function() {
58 | blockUI.stop();
59 | }, 4000);
60 |
61 |
Reset on exception
62 |
63 | Example that hides the block whenever an uncaught exception has occured.
64 |
65 |
66 | Demo
67 |
68 |
blockUI.start();
69 |
70 | $timeout(function() {
71 | throw new Error('Oh dear!');
72 | blockUI.stop(); // Stop will never be called
73 | }, 1000);
74 |
75 |
Block on HTTP requests
76 |
77 | Example that blocks whenever a http request is fired.
78 |
79 |
80 | Note: The block isn't shown if the server response time is less than the delay set in the configuration.
81 |
82 |
83 | Demo
84 |
85 |
$http.get('index.html').then(function(data) {
86 | inform.add('Data received from server');
87 | });
88 |
89 |
Callback queue
90 |
91 | Execute callback when the block ui has been finished.
92 |
93 |
94 | Demo
95 |
96 |
blockUI.start();
97 |
98 | blockUI.done(function() {
99 | $window.alert('BlockUI has finished.');
100 | });
101 |
102 | $timeout(function() {
103 | blockUI.stop();
104 | }, 1000);
105 |
106 |
--------------------------------------------------------------------------------
/src/app/examples/manual-blocking.js:
--------------------------------------------------------------------------------
1 |
2 | angular.module('myApp').controller('ManualBlockingController', function($scope, blockUI, $timeout, $http, $window, inform) {
3 |
4 | $scope.startBlock = function() {
5 | blockUI.start();
6 |
7 | $timeout(function() {
8 | blockUI.stop();
9 | }, 2000);
10 | };
11 |
12 | $scope.startBlockWithMessage = function() {
13 | blockUI.start("My custom message");
14 |
15 | $timeout(function() {
16 | blockUI.stop();
17 | }, 2000);
18 | };
19 |
20 | $scope.startBlockUpdateMessage = function() {
21 | blockUI.start();
22 |
23 | $timeout(function() {
24 | blockUI.message('Still loading ...');
25 | }, 1000);
26 |
27 | $timeout(function() {
28 | blockUI.message('Almost there ...');
29 | }, 2000);
30 |
31 | $timeout(function() {
32 | blockUI.message('Cleaning up ...');
33 | }, 3000);
34 |
35 | $timeout(function() {
36 | blockUI.stop();
37 | }, 4000);
38 | };
39 |
40 | $scope.resetOnError = function() {
41 | blockUI.start();
42 |
43 | $timeout(function() {
44 | throw new Error('Oh dear!');
45 | blockUI.stop(); // Stop will never be called
46 | }, 1000);
47 |
48 | };
49 |
50 | $scope.withHttpRequest = function() {
51 |
52 | $http.get('index.html').then(function(data) {
53 | inform.add('Data received from server', { type: 'success' });
54 | });
55 | };
56 |
57 | $scope.executeWhenDone = function() {
58 |
59 | blockUI.start();
60 |
61 | blockUI.done(function() {
62 | inform.add('BlockUI has finished.');
63 | });
64 |
65 | $timeout(function() {
66 | blockUI.stop();
67 | }, 1000);
68 | };
69 | });
--------------------------------------------------------------------------------
/src/app/examples/my-demo-table.css:
--------------------------------------------------------------------------------
1 | .my-demo-table th {
2 | width: 25%;
3 | }
4 |
5 | .my-demo-table table, .my-demo-table .pagination {
6 | margin-bottom: 0;
7 | }
--------------------------------------------------------------------------------
/src/app/examples/my-demo-table.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').directive('myDemoTable', function(myFakeDataResource) {
2 | return {
3 | templateUrl: 'app/examples/my-demo-table.ng.html',
4 | link: function($scope, $element, $attrs) {
5 |
6 | $scope.table = {
7 | items: [],
8 | offset: 0,
9 | limit: 10,
10 | previous: function() {
11 | $scope.table.offset = Math.max(0, $scope.table.offset - 10);
12 | },
13 | next: function() {
14 | $scope.table.offset = Math.min(40, $scope.table.offset + 10);
15 | },
16 | emptyRows: function() {
17 | return new Array($scope.table.limit - $scope.table.items.length);
18 | }
19 | };
20 |
21 | $scope.$watch($attrs.limit, function(v) {
22 | $scope.table.limit = v === undefined ? $scope.table.limit : v;
23 | });
24 |
25 | $scope.$watchCollection('[ table.offset, table.limit ]', function(value) {
26 | myFakeDataResource.query({ limit: $scope.table.limit, offset: $scope.table.offset }).$promise.then(function(data) {
27 | $scope.table.items = data;
28 | });
29 | });
30 | }
31 | };
32 | });
33 |
34 | angular.module('myApp').factory('myFakeDataResource', function($http, $q) {
35 |
36 | return {
37 | query: function(params) {
38 |
39 | var d = $q.defer();
40 |
41 | var ret = [];
42 |
43 | ret.$resolved = false;
44 | ret.$promise = d.promise;
45 | $http.get('app/examples/data-array.json').then(function(response) {
46 |
47 | ret.length = 0;
48 |
49 | if(params.offset + params.limit >= response.data.length) {
50 | params.offset = 0;
51 | }
52 |
53 | response.data = response.data.splice(params.offset, params.limit);
54 | Array.prototype.push.apply(ret, response.data);
55 |
56 | d.resolve(ret);
57 | });
58 |
59 | return ret;
60 | }
61 | };
62 |
63 | });
--------------------------------------------------------------------------------
/src/app/examples/my-demo-table.ng.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Name
5 | Lastname
6 | Email
7 | Country
8 |
9 |
10 | {{ item.first_name }}
11 | {{ item.last_name }}
12 | {{ item.email }}
13 | {{ item.country }}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
29 |
30 |
--------------------------------------------------------------------------------
/src/app/examples/readme.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/src/app/main/home.ng.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Angular BlockUI
4 |
5 |
6 | A simple AngularJS module that allows you to block user interaction on AJAX requests.
7 |
8 |
9 |
10 | Documentation »
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/app/navbar/navbar-controller.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').controller('NavbarController', function ($scope, $location, navItems) {
2 |
3 | var self = this;
4 |
5 | this.setActiveNavItem = function(url) {
6 |
7 | for(var i = 0; i < navItems.length; i++) {
8 |
9 | var navItem = navItems[i];
10 | var regexp = navItem.$_regexp;
11 |
12 | if(!regexp) {
13 | var pattern = navItem.pattern;
14 |
15 | if (!pattern) {
16 | pattern = navItem.url || '/';
17 | pattern = pattern.replace(/^#!/, '')
18 | }
19 |
20 | regexp = new RegExp('^' + pattern + '$', 'i');
21 | navItem.$_regexp = regexp;
22 | }
23 |
24 | navItem.isActive = regexp.test(url);
25 | }
26 | };
27 |
28 | $scope.navItems = navItems;
29 |
30 | $scope.$watch(function () {
31 | return $location.path();
32 | }, function(newValue) { self.setActiveNavItem(newValue) });
33 |
34 | $scope.navItems.isCollapsed = true;
35 |
36 | $scope.toggleCollapse = function() {
37 | $scope.navItems.isCollapsed = !$scope.navItems.isCollapsed;
38 | };
39 |
40 | $scope.collapseNavItems = function() {
41 | $scope.navItems.isCollapsed = true;
42 | };
43 |
44 | });
45 |
--------------------------------------------------------------------------------
/src/app/navbar/navbar-controller.test.js:
--------------------------------------------------------------------------------
1 | describe('NavbarController', function() {
2 |
3 | var $injector, $controller, $rootScope, $location;
4 |
5 | beforeEach(module('myApp'));
6 |
7 | beforeEach(inject(function(_$controller_, _$rootScope_, _$location_) {
8 | $controller = _$controller_;
9 | $rootScope = _$rootScope_;
10 | $location = _$location_;
11 | }));
12 |
13 | it('should be able to construct controller', function() {
14 |
15 | // Arrange
16 |
17 | var $scope = $rootScope.$new();
18 |
19 | // Act
20 |
21 | var controller = $controller('NavbarController', { $scope: $scope });
22 |
23 | // Assert
24 |
25 | expect(controller).toBeDefined();
26 |
27 | });
28 |
29 | it('should call setActiveNavItem on construction', function() {
30 |
31 | // Arrange
32 |
33 | var $scope = $rootScope.$new();
34 |
35 | var ctrl = $controller('NavbarController', { $scope: $scope });
36 | spyOn(ctrl, 'setActiveNavItem');
37 |
38 | // Act
39 |
40 | $scope.$apply();
41 |
42 | // Assert
43 |
44 | expect(ctrl.setActiveNavItem).toHaveBeenCalled();
45 | });
46 |
47 | it('should call setActiveNavItem on location changes', function() {
48 |
49 | // Arrange
50 |
51 | var url = '/einsweidriedus';
52 | var $scope = $rootScope.$new();
53 |
54 | var ctrl = $controller('NavbarController', { $scope: $scope, $location: $location });
55 |
56 | // Act
57 |
58 | $scope.$apply(); // flush the construction watch call
59 |
60 | spyOn(ctrl, 'setActiveNavItem');
61 |
62 | $location.path(url);
63 | $scope.$apply();
64 |
65 | // Assert
66 |
67 | expect(ctrl.setActiveNavItem).toHaveBeenCalledWith(url);
68 | });
69 |
70 | it('should set active item on exact url match', function() {
71 |
72 | // Arrange
73 |
74 | var url = '/einsweidriedus';
75 |
76 | var navItems = [
77 | { text: 'DoeMijDieMa', url: url },
78 | { text: 'DezeNiet', url: '/noMatch' }
79 | ];
80 |
81 | var ctrl = $controller('NavbarController', { $scope: $rootScope.$new(), navItems: navItems });
82 |
83 | // Act
84 |
85 | ctrl.setActiveNavItem(url);
86 |
87 | // Assert
88 |
89 | expect(navItems[0].isActive).toBe(true);
90 | expect(navItems[1].isActive).toBeFalsy();
91 |
92 | });
93 |
94 | it('should not set active item on partial url match', function() {
95 |
96 | // Arrange
97 |
98 | var url = '/einsweidriedus/ennogwat';
99 |
100 | var navItems = [
101 | { text: 'DoeMijDieMa', url: '/einsweidriedus' },
102 | { text: 'DezeNiet', url: '/noMatch' }
103 | ];
104 |
105 | var ctrl = $controller('NavbarController', { $scope: $rootScope.$new(), navItems: navItems });
106 |
107 | // Act
108 |
109 | ctrl.setActiveNavItem(url);
110 |
111 | // Assert
112 |
113 | expect(navItems[0].isActive).toBeFalsy();
114 | expect(navItems[1].isActive).toBeFalsy();
115 |
116 | });
117 |
118 | it('should use pattern to match active item', function() {
119 |
120 | // Arrange
121 |
122 | var url = '/einsweidriedus/ennogwat?dus=123';
123 |
124 | var navItems = [
125 | { text: 'DoeMijDieMa', url: '/einsweidriedus', pattern: "/einsweidriedus(/.*)?" },
126 | { text: 'DezeNiet', url: '/noMatch' }
127 | ];
128 |
129 | var ctrl = $controller('NavbarController', { $scope: $rootScope.$new(), navItems: navItems });
130 |
131 | // Act
132 |
133 | ctrl.setActiveNavItem(url);
134 |
135 | // Assert
136 |
137 | expect(navItems[0].isActive).toBeTruthy();
138 | expect(navItems[1].isActive).toBeFalsy();
139 |
140 | });
141 | });
142 |
--------------------------------------------------------------------------------
/src/app/navbar/navbar-directive.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').directive('navbar', function ($location) {
2 |
3 | var routePatternAttribute = 'data-route-pattern';
4 |
5 | return {
6 | restrict: 'A',
7 | templateUrl: 'app/navbar/navbar.ng.html',
8 | controller: 'NavbarController',
9 | replace: true
10 | };
11 | });
12 |
--------------------------------------------------------------------------------
/src/app/navbar/navbar.css:
--------------------------------------------------------------------------------
1 | /* Landscape phone to portrait tablet */
2 | @media (max-width: 767px) {
3 |
4 | .navbar-collapse.collapsed {
5 | display: none;
6 | }
7 | }
8 |
9 | .navbar-collapse {
10 | overflow-y: hidden;
11 | }
--------------------------------------------------------------------------------
/src/app/navbar/navbar.ng.html:
--------------------------------------------------------------------------------
1 |
21 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
<%- pkg.name %>
11 |
12 |
13 |
14 |
15 |
16 | <% _.forEach(css, function(include) { %>
17 |
18 | <%
19 | }); %>
20 |
21 |
26 |
27 |
28 |
29 |
30 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | <% _.forEach(js, function(include) { %>
50 |
51 | <%
52 | }); %>
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/src/sandbox/animations/animations.css:
--------------------------------------------------------------------------------
1 |
2 |
3 | /*.my-block-area {*/
4 | /*position: relative;*/
5 | /*}*/
6 |
7 | /*.my-block-container {*/
8 | /*position: absolute;*/
9 | /*z-index: 10000;*/
10 | /*top: 0; right: 0; bottom: 0; left: 0;*/
11 | /*height: 0;*/
12 | /*overflow: hidden;*/
13 | /*opacity: 0;*/
14 | /*filter: alpha(opacity=00);*/
15 | /*cursor: wait;*/
16 | /*}*/
17 |
18 | /*.my-block-container.my-block-active {*/
19 | /*height: 100%;*/
20 | /*}*/
21 |
22 | /*.my-block-container.my-block-visible {*/
23 | /*opacity: 1;*/
24 | /*filter: alpha(opacity=100);*/
25 | /*}*/
26 |
27 | /*.my-block-overlay {*/
28 | /*width: 100%;*/
29 | /*height: 100%;*/
30 | /*opacity: 0.5;*/
31 | /*filter: alpha(opacity=50);*/
32 | /*background-color: white;*/
33 | /*}*/
34 |
35 | /*.my-block-message-container {*/
36 | /*position: absolute;*/
37 | /*top: 35%;*/
38 | /*left: 0;*/
39 | /*right: 0;*/
40 | /*height: 0;*/
41 | /*text-align: center;*/
42 | /*z-index: 10001;*/
43 | /*}*/
44 |
45 | /*.my-block-message {*/
46 | /*display: inline-block;*/
47 | /*text-align: left;*/
48 | /*background-color: #333;*/
49 | /*color: #f5f5f5;*/
50 | /*padding: 20px;*/
51 | /*border-radius: 4px;*/
52 | /*font-size: 20px;*/
53 | /*font-weight: bold;*/
54 | /*filter: alpha(opacity=100);*/
55 | /*}*/
56 |
57 | /*.my-fade-in-out > .my-block-container {*/
58 | /*transition: height 0s ease 200ms, opacity 200ms ease;*/
59 | /*}*/
60 |
61 | /*.my-fade-in-out > .my-block-container.my-block-visible {*/
62 | /*this resets the initial delay of the height */
63 | /*and sizes the block to full height at once at the start of the block. */
64 | /*transition-delay: 0s;*/
65 | /*}*/
66 |
67 | /*.block-ui-fade-in .block-ui-container.block-ui-visible {*/
68 | /*opacity: 1.0;*/
69 | /*}*/
70 |
71 | /*.block-ui-fade-in-out .block-ui-container {*/
72 | /*transition: opacity 200ms;*/
73 | /*opacity: 0.0;*/
74 | /*}*/
75 |
76 | /*.block-ui-fade-in-out .block-ui-container.block-ui-visible {*/
77 | /*opacity: 1.0;*/
78 | /*}*/
79 |
80 | /*.block-ui-fade-in-out .block-ui-overlay {*/
81 | /*transition: height 1200ms;*/
82 | /*}*/
--------------------------------------------------------------------------------
/src/sandbox/animations/animations.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{ animateCss.selected.name }}
6 |
7 |
8 |
9 |
11 |
--------------------------------------------------------------------------------
/src/sandbox/animations/animations.js:
--------------------------------------------------------------------------------
1 | angular.module('myApp').controller('AnimationController', function($scope, $timeout, blockUI) {
2 |
3 | // $scope.toggleMyBlock = function() {
4 | // $scope.state = $scope.state || {};
5 | //
6 | // if($scope.state.myBlockActive) {
7 | //
8 | //// if($scope.state.promise) {
9 | //// $timeout.cancel($scope.state.promise);
10 | //// delete $scope.state.promise;
11 | //// }
12 | //
13 | // if($scope.state.myBlockVisible) {
14 | // $scope.state.myBlockActive = false;
15 | // $scope.state.myBlockVisible = false;
16 | // } else {
17 | // $scope.state.myBlockVisible = true;
18 | // }
19 | //
20 | //
21 | // } else {
22 | // $scope.state.myBlockActive = true;
23 | //
24 | //// $scope.state.promise = $timeout(function() {
25 | //// $scope.state.myBlockVisible = true;
26 | //// delete $scope.state.promise;
27 | //// }, 200);
28 | // }
29 | // };
30 |
31 | // $scope.startBlock = function(id, timeout) {
32 | //
33 | // var blockInstance = blockUI.instances.get(id);
34 | //
35 | // blockInstance.start();
36 | //
37 | // if(timeout >= 0) {
38 | // $timeout(function() {
39 | // blockInstance.stop();
40 | // }, timeout);
41 | // }
42 | // };
43 | //
44 | // $scope.stopBlock = function(id) {
45 | // var blockInstance = blockUI.instances.get(id);
46 | // blockInstance.stop();
47 | // };
48 | //
49 | // $scope.toggleBlock = function(id) {
50 | // var blockInstance = blockUI.instances.get(id);
51 | //
52 | // if(blockInstance.state().blocking) {
53 | // blockInstance.stop();
54 | // } else {
55 | // blockInstance.start();
56 | // }
57 | // };
58 |
59 | var animateConfig = {
60 |
61 | "attention_seekers": {
62 | "bounce": true,
63 | "flash": true,
64 | "pulse": true,
65 | "rubberBand": true,
66 | "shake": true,
67 | "swing": true,
68 | "tada": true,
69 | "wobble": true
70 | },
71 |
72 | "bouncing_entrances": {
73 | "bounceIn": true,
74 | "bounceInDown": true,
75 | "bounceInLeft": true,
76 | "bounceInRight": true,
77 | "bounceInUp": true
78 | },
79 |
80 | "bouncing_exits": {
81 | "bounceOut": true,
82 | "bounceOutDown": true,
83 | "bounceOutLeft": true,
84 | "bounceOutRight": true,
85 | "bounceOutUp": true
86 | },
87 |
88 | "fading_entrances": {
89 | "fadeIn": true,
90 | "fadeInDown": true,
91 | "fadeInDownBig": true,
92 | "fadeInLeft": true,
93 | "fadeInLeftBig": true,
94 | "fadeInRight": true,
95 | "fadeInRightBig": true,
96 | "fadeInUp": true,
97 | "fadeInUpBig": true
98 | },
99 |
100 | "fading_exits": {
101 | "fadeOut": true,
102 | "fadeOutDown": true,
103 | "fadeOutDownBig": true,
104 | "fadeOutLeft": true,
105 | "fadeOutLeftBig": true,
106 | "fadeOutRight": true,
107 | "fadeOutRightBig": true,
108 | "fadeOutUp": true,
109 | "fadeOutUpBig": true
110 | },
111 |
112 | "flippers": {
113 | "flip": true,
114 | "flipInX": true,
115 | "flipInY": true,
116 | "flipOutX": true,
117 | "flipOutY": true
118 | },
119 |
120 | "lightspeed": {
121 | "lightspeedIn": true,
122 | "lightspeedOut": true
123 | },
124 |
125 | "rotating_entrances": {
126 | "rotateIn": true,
127 | "rotateInDownLeft": true,
128 | "rotateInDownRight": true,
129 | "rotateInUpLeft": true,
130 | "rotateInUpRight": true
131 | },
132 |
133 | "rotating_exits": {
134 | "rotateOut": true,
135 | "rotateOutDownLeft": true,
136 | "rotateOutDownRight": true,
137 | "rotateOutUpLeft": true,
138 | "rotateOutUpRight": true
139 | },
140 |
141 | "specials": {
142 | "hinge": true,
143 | "rollIn": true,
144 | "rollOut": true
145 | },
146 |
147 | "zooming_entrances": {
148 | "zoomIn": true,
149 | "zoomInDown": true,
150 | "zoomInLeft": true,
151 | "zoomInRight": true,
152 | "zoomInUp": true
153 | },
154 |
155 | "zooming_exits": {
156 | "zoomOut": true,
157 | "zoomOutDown": true,
158 | "zoomOutLeft": true,
159 | "zoomOutRight": true,
160 | "zoomOutUp": true
161 | }
162 |
163 | };
164 |
165 | (function() {
166 |
167 | var options = [];
168 |
169 | angular.forEach(animateConfig, function(group, groupName) {
170 | angular.forEach(group, function(b, animName) {
171 | options.push({
172 | name: animName, group: groupName
173 | });
174 | });
175 | });
176 |
177 |
178 | $scope.animateCss = {
179 | options: options,
180 | selected: options[0]
181 | };
182 |
183 | })();
184 |
185 | $scope.$watch('animateCss.recompile', function(value) {
186 |
187 | if(!value) {
188 | $scope.animateCss.recompile = true;
189 | }
190 | });
191 |
192 | var blockInstance = blockUI.instances.get('animateCssTest');
193 | blockInstance.addRef();
194 | blockInstance.start();
195 |
196 | });
--------------------------------------------------------------------------------
/src/sandbox/animations/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/sandbox/animations/script.js:
--------------------------------------------------------------------------------
1 | var myApp = angular.module('myApp', ['blockUI']);
2 |
3 |
--------------------------------------------------------------------------------
/src/sandbox/autoblocking/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
I am the main block instance
35 |
36 |
37 |
38 | By default the block-ui module marks the body element as the main block instance.
39 | But in some cases this behaviour is not desired. When for instance the body element is not accessible or your ng-app directive is
40 | a child element of the body element.
41 |
42 |
It is however quite simple to relocate the main block-ui instance by simply marking a different element as the main instance.
43 |
44 |
<!-- Mark the desired containing element as the main block instance -->
45 | <div block-ui="main" class="block-ui-main">
46 | <p>Lorem ipsum ... </p>
47 | </div>
48 |
49 |
angular.module('myApp').config(function(blockUIConfig) {
50 | // Tell blockUI not to mark the body element as the main block scope.
51 | blockUIConfig.autoInjectBodyBlock = false;
52 | });
53 |
54 |
55 | Start demo block
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/sandbox/autoblocking/script.js:
--------------------------------------------------------------------------------
1 |
2 | var myApp = angular.module('myApp', ['blockUI']);
3 |
4 | myApp.config(function(blockUIConfig) {
5 | // Tell blockUI not to mark the body element as the main block scope.
6 | blockUIConfig.autoInjectBodyBlock = false;
7 | });
8 |
9 | myApp.controller('MyController', function($scope, blockUI, $timeout) {
10 |
11 | $scope.startBlock = function() {
12 |
13 | blockUI.start();
14 |
15 | $timeout(function() {
16 | blockUI.stop();
17 | }, 2000);
18 | };
19 |
20 | });
--------------------------------------------------------------------------------
/src/sandbox/autoblocking/style.css:
--------------------------------------------------------------------------------
1 | /* Styles go here */
--------------------------------------------------------------------------------
/src/sandbox/destroy-bug/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/McNull/angular-block-ui/0d01eee67a6f8b0fd6beeaf16f950d1870842702/src/sandbox/destroy-bug/README.md
--------------------------------------------------------------------------------
/src/sandbox/destroy-bug/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
42 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | Id
52 | Name
53 | Lastname
54 | Email
55 |
56 |
57 |
58 |
59 | {{ person.id }}
60 | {{ person.firstName }}
61 | {{ person.lastName }}
62 | {{ person.email }}
63 |
64 | Click
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/src/sandbox/destroy-bug/my-pager.html:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/src/sandbox/destroy-bug/script.js:
--------------------------------------------------------------------------------
1 | // Code goes here
2 |
3 | var app = angular.module('myApp', ['inform', 'inform-exception', 'blockUI', 'responseLag']);
4 |
5 | app.config(function(blockUIConfig) {
6 |
7 | // For this demo we'll disable the "fullscreen" body block
8 | blockUIConfig.autoInjectBodyBlock = false;
9 |
10 | });
11 |
12 | // Our people controller for the main view. It monitors the pager.index
13 | // property and reflects the data by querying the myPeopleResource.
14 |
15 | app.controller('PeopleCtrl', function($scope, blockUI, myPeopleResource, inform, $timeout) {
16 |
17 | $scope.grid = {
18 | pager: {
19 | index: 0,
20 | size: 20
21 | },
22 | items: []
23 | };
24 |
25 | $scope.$watch('grid.pager.index', function(value) {
26 |
27 | if(value !== undefined) {
28 | myPeopleResource.query({
29 | limit: $scope.grid.pager.size,
30 | skip: $scope.grid.pager.size * value
31 | }).then(function(result) {
32 | $scope.grid.items = result.items;
33 | $scope.grid.pager.count = Math.ceil(result.totalItems / $scope.grid.pager.size);
34 | });
35 | }
36 |
37 | });
38 |
39 | $scope.click = function(person) {
40 | var personBlock = blockUI.instances.get('person-block-' + person.id);
41 |
42 | personBlock.start();
43 |
44 | $timeout(function() {
45 | // personBlock.stop();
46 | }, 1000);
47 | };
48 | });
49 |
50 | // A fake resource object that returns our fake data.
51 | // Every http request will be captured by the block-ui that is associated
52 | // with the request url -- in this case 'people-data.json'.
53 |
54 | app.factory('myPeopleResource', function($q, $http) {
55 |
56 | return {
57 | query: function(args) {
58 |
59 | args = args || {};
60 | args.limit = args.limit || 20;
61 | args.skip = args.skip || 0;
62 |
63 | var defer = $q.defer();
64 |
65 | $http.get('people-data.json')
66 | .success(function(items) {
67 |
68 | var result = {
69 | totalItems: items.length,
70 | items: items.slice(args.skip, args.skip + args.limit)
71 | };
72 |
73 | defer.resolve(result);
74 | });
75 |
76 | return defer.promise;
77 |
78 | }
79 | };
80 |
81 | });
82 |
83 | // The pager shown above the grid.
84 |
85 | app.directive('myPager', function() {
86 |
87 | return {
88 | templateUrl: 'my-pager.html',
89 | scope: {
90 | pageIndex: '=',
91 | pageCount: '='
92 | },
93 | link: function($scope) {
94 |
95 | $scope.index = function(value) {
96 | if (value !== undefined) {
97 | $scope.pageIndex = value;
98 | }
99 |
100 | return $scope.pageIndex;
101 | };
102 |
103 | $scope.move = function(value) {
104 | $scope.pageIndex += value;
105 | $scope.pageIndex = Math.max($scope.pageIndex, 0);
106 | $scope.pageIndex = Math.min($scope.pageIndex, $scope.pageCount - 1);
107 | };
108 |
109 | $scope.getIndex = function(value) {
110 | $scope.index = value;
111 | };
112 |
113 | $scope.$watch('pageCount', function(value) {
114 | $scope.pages = [];
115 |
116 | if (value >= 1) {
117 | while (value--) {
118 | $scope.pages.unshift(value);
119 | }
120 | }
121 | });
122 |
123 | }
124 | };
125 |
126 | });
127 |
--------------------------------------------------------------------------------
/src/sandbox/destroy-bug/style.css:
--------------------------------------------------------------------------------
1 | /* Styles go here */
2 |
3 | .my-pager {
4 | max-width: 250px;
5 | }
6 |
7 | .people-list {
8 | overflow-y: scroll;
9 | height: 300px;
10 | }
11 |
12 | .container-border {
13 | border: solid 1px #ddd;
14 | height: 400px;
15 |
16 | }
--------------------------------------------------------------------------------
/src/sandbox/history-block/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Browser navigation block
17 |
18 |
19 |
20 |
21 |
Description
22 |
23 | Whenever an async request has been made in a single page app to the backend server, you'll probably want to wait untill it has completed.
24 | The registered callbacks will execute even if the user has navigated away from the originating view/controller. The angular-block-ui
25 | module can disable navigation until al the requests have been completed and still allows you to change the url whenever this is done via the
26 | $location service.
27 |
28 |
Demostration
29 |
30 | The current active element in the pagination below is determined by the index search argument passed in the url.
31 | When this page is loaded the controller will add some history urls to the browser. Navigating back and forward should highlite the current index
32 | in the pagination.
33 |
34 |
35 | The button "Start Block" will start a user interface block and does not allow the user to navigate back and forward until
36 | the block has been lifted.
37 |
38 |
The button "Start Block and Change Location" also starts a user interface block, but changes with a certain interval the url search parameters.
39 |
40 |
41 |
46 |
47 |
48 | Start Block
49 | Start Block and Change Location
50 |
51 |
52 |
53 |
54 |
Enable browser navigation block
55 |
Navigation blocking can be enabled by setting the blockBrowserNavigation property of the blockUIConfig to true .
56 |
angular.module('myApp').config(function(blockUIConfig) {
57 | blockUIConfig.blockBrowserNavigation = true;
58 | });
59 |
60 |
61 |
62 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/sandbox/history-block/script.js:
--------------------------------------------------------------------------------
1 | var app = angular.module('myApp', ['blockUI']);
2 |
3 | app.config(function(blockUIConfig) {
4 |
5 | // Enable navigation block
6 |
7 | blockUIConfig.blockBrowserNavigation = true;
8 |
9 | });
10 |
11 | app.controller('MainCtrl', function ($scope, blockUIConfig, blockUI, $timeout, $location) {
12 |
13 | $scope.blockUIConfig = blockUIConfig;
14 | $scope.indexItems = [];
15 |
16 | // Create some url history entries in the browser
17 |
18 | var indexCount = 10;
19 |
20 | for (var i = 0; i < indexCount; i++) {
21 | $scope.indexItems.push(i);
22 | (function (i) {
23 | $timeout(function () {
24 | $location.search({
25 | index: i
26 | });
27 | }, indexCount - i);
28 | })(i);
29 | }
30 |
31 | $scope.$watch(function() {
32 | return $location.search().index;
33 | }, function(value) {
34 | $scope.index = value || 0;
35 | });
36 |
37 | $scope.startBlock = function (changeLocation) {
38 |
39 | var duration = 5000,
40 | step = 100;
41 |
42 | function message(t) {
43 | return "Blocking (" + t + " ms)";
44 | }
45 |
46 | function tick(t) {
47 | if (t > 0) {
48 | if(changeLocation) {
49 | var index = Math.floor(Math.random() * $scope.indexItems.length);
50 | $location.search({ index: index })
51 | }
52 |
53 | blockUI.message(message(t));
54 | $timeout(function () {
55 | tick(t - step);
56 | }, step);
57 | } else {
58 | blockUI.stop();
59 | }
60 | }
61 |
62 | blockUI.start();
63 | tick(duration);
64 | };
65 | });
--------------------------------------------------------------------------------
/src/sandbox/history-block/style.css:
--------------------------------------------------------------------------------
1 | html {
2 | position: relative;
3 | min-height: 100%;
4 | }
5 |
6 | body {
7 | margin-bottom: 60px;
8 | }
9 |
10 | .footer {
11 | position: absolute;
12 | bottom: 0px;
13 | width: 100%;
14 | height: 60px;
15 | background-color: #F5F5F5;
16 | }
--------------------------------------------------------------------------------
/src/sandbox/manual-main/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
I am the main block instance
35 |
36 |
37 |
38 | By default the block-ui module marks the body element as the main block instance.
39 | But in some cases this behaviour is not desired. When for instance the body element is not accessible or your ng-app directive is
40 | a child element of the body element.
41 |
42 |
It is however quite simple to relocate the main block-ui instance by simply marking a different element as the main instance.
43 |
44 |
<!-- Mark the desired containing element as the main block instance -->
45 | <div block-ui="main" class="block-ui-main">
46 | <p>Lorem ipsum ... </p>
47 | </div>
48 |
49 |
angular.module('myApp').config(function(blockUIConfig) {
50 | // Tell blockUI not to mark the body element as the main block scope.
51 | blockUIConfig.autoInjectBodyBlock = false;
52 | });
53 |
54 |
55 | Start demo block
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/src/sandbox/manual-main/script.js:
--------------------------------------------------------------------------------
1 |
2 | var myApp = angular.module('myApp', ['blockUI']);
3 |
4 | myApp.config(function(blockUIConfig) {
5 | // Tell blockUI not to mark the body element as the main block scope.
6 | blockUIConfig.autoInjectBodyBlock = false;
7 | });
8 |
9 | myApp.controller('MyController', function($scope, blockUI, $timeout) {
10 |
11 | $scope.startBlock = function() {
12 |
13 | blockUI.start();
14 |
15 | $timeout(function() {
16 | blockUI.stop();
17 | }, 2000);
18 | };
19 |
20 | });
--------------------------------------------------------------------------------
/src/sandbox/manual-main/style.css:
--------------------------------------------------------------------------------
1 | /* Styles go here */
--------------------------------------------------------------------------------
/src/sandbox/preventroute-bug/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
48 |
49 |
54 |
55 | View the tutorial on Scotch.io
56 |
57 | View a tutorial on Animating Your Angular Single Page App
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/src/sandbox/preventroute-bug/pages/about.html:
--------------------------------------------------------------------------------
1 |
2 |
About Page
3 |
4 |
{{ message }}
5 |
--------------------------------------------------------------------------------
/src/sandbox/preventroute-bug/pages/contact.html:
--------------------------------------------------------------------------------
1 |
2 |
Contact Page
3 |
4 |
{{ message }}
5 |
--------------------------------------------------------------------------------
/src/sandbox/preventroute-bug/pages/home.html:
--------------------------------------------------------------------------------
1 |
2 |
Home Page
3 |
4 |
{{ message }}
5 |
--------------------------------------------------------------------------------
/src/sandbox/preventroute-bug/script.js:
--------------------------------------------------------------------------------
1 | // create the module and name it scotchApp
2 | var scotchApp = angular.module('scotchApp', ['ngRoute', 'blockUI']);
3 |
4 |
5 | //function decorateLocation($delegate) {
6 | // window.ll = $delegate;
7 | //
8 | // var overrides = [
9 | // 'url', 'path', 'search', 'hash', 'state'
10 | // ];
11 | //
12 | // function hook(f) {
13 | // var s = $delegate[f];
14 | // $delegate[f] = function() {
15 | // console.log(f);
16 | // return s.apply($delegate, arguments);
17 | // };
18 | // }
19 | //
20 | // angular.forEach(overrides, hook);
21 | //
22 | // return $delegate;
23 | //}
24 | //
25 | //scotchApp.config(function ($provide) {
26 | // $provide.decorator('$location', decorateLocation);
27 | //});
28 |
29 |
30 | scotchApp.config(function (blockUIConfig) {
31 | // blockUIConfig.preventRouting = false;
32 | });
33 |
34 | // configure our routes
35 | scotchApp.config(function ($routeProvider) {
36 | $routeProvider
37 | // route for the home page
38 | .when('/', {
39 | templateUrl: 'pages/home.html',
40 | controller: 'mainController',
41 | reloadOnSearch: false
42 | })
43 |
44 | // route for the about page
45 | .when('/about', {
46 | templateUrl: 'pages/about.html',
47 | controller: 'aboutController'
48 | })
49 |
50 | // route for the contact page
51 | .when('/contact', {
52 | templateUrl: 'pages/contact.html',
53 | controller: 'contactController'
54 | })
55 |
56 | .otherwise({
57 | redirectTo: '/'
58 | });
59 | });
60 |
61 | // create the controller and inject Angular's $scope
62 | scotchApp.controller('mainController', function ($scope, $timeout, $location, blockUI) {
63 | // create a message to display in our view
64 | $scope.message = 'Everyone come and see how good I look!';
65 |
66 | blockUI.start();
67 |
68 | function tick(t) {
69 | $location.search({
70 | t: t
71 | }).hash('gedoe' + t);
72 | $timeout(function () {
73 | tick(t + 1);
74 | }, 500);
75 | }
76 |
77 | $timeout(function() {
78 | tick(0);
79 | });
80 |
81 |
82 | // blockUI.start();
83 |
84 | // $timeout(function () {
85 | // $location.path('/about');
86 | //
87 | //// blockUI.stop();
88 | // });
89 |
90 | });
91 |
92 | scotchApp.controller('aboutController', function ($scope, $timeout, $location) {
93 | $scope.message = 'Look! I am an about page.';
94 |
95 | // $timeout(function () {
96 | // $location.path('/');
97 | //
98 | //// blockUI.stop();
99 | // }, 1000);
100 |
101 | });
102 |
103 | scotchApp.controller('contactController', function ($scope) {
104 | $scope.message = 'Contact us! JK. This is just a demo.';
105 | });
--------------------------------------------------------------------------------
/src/sandbox/simple/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Block
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/sandbox/simple/script.js:
--------------------------------------------------------------------------------
1 | angular.module('app', ['blockUI'])
2 | .config(function(blockUIConfig) {
3 | // Disable injecting the main block on the body
4 | blockUIConfig.autoInjectBodyBlock = false;
5 | })
6 | .controller('thing', function ($scope, blockUI) {
7 | $scope.show = function () {
8 | blockUI.start();
9 | };
10 | });
--------------------------------------------------------------------------------