1/*! 2 angular-block-ui v0.2.0 3 (c) 2015 (null) McNull https://github.com/McNull/angular-block-ui 4 License: MIT 5*/ 6(function(angular) { 7 8var blkUI = angular.module('blockUI', []); 9 10blkUI.config(["$provide", "$httpProvider", function ($provide, $httpProvider) { 11 12 $provide.decorator('$exceptionHandler', ['$delegate', '$injector', 13 function ($delegate, $injector) { 14 var blockUI, blockUIConfig; 15 16 return function (exception, cause) { 17 18 blockUIConfig = blockUIConfig || $injector.get('blockUIConfig'); 19 20 if (blockUIConfig.resetOnException) { 21 try { 22 blockUI = blockUI || $injector.get('blockUI'); 23 blockUI.instances.reset(); 24 } catch (ex) { 25 console.log('$exceptionHandler', exception); 26 } 27 } 28 29 $delegate(exception, cause); 30 }; 31 } 32 ]); 33 34 $httpProvider.interceptors.push('blockUIHttpInterceptor'); 35}]); 36 37blkUI.run(["$document", "blockUIConfig", "$templateCache", function ($document, blockUIConfig, $templateCache) { 38 if (blockUIConfig.autoInjectBodyBlock) { 39 $document.find('body').attr('block-ui', 'main'); 40 } 41 42 if (blockUIConfig.template) { 43 44 // Swap the builtin template with the custom template. 45 // Create a magic cache key and place the template in the cache. 46 47 blockUIConfig.templateUrl = '$$block-ui-template$$'; 48 $templateCache.put(blockUIConfig.templateUrl, blockUIConfig.template); 49 } 50}]); 51 52function moduleLoaded(name) { 53 try { 54 angular.module(name); 55 } catch(ex) { 56 return false; 57 } 58 return true; 59} 60blkUI.config(["$provide", function ($provide) { 61 $provide.decorator('$location', decorateLocation); 62}]); 63 64var decorateLocation = [ 65 '$delegate', 'blockUI', 'blockUIConfig', 66 function ($delegate, blockUI, blockUIConfig) { 67 68 if (blockUIConfig.blockBrowserNavigation) { 69 70 blockUI.$_blockLocationChange = true; 71 72 var overrides = ['url', 'path', 'search', 'hash', 'state']; 73 74 function hook(f) { 75 var s = $delegate[f]; 76 $delegate[f] = function () { 77 78 // console.log(f, Date.now(), arguments); 79 80 var result = s.apply($delegate, arguments); 81 82 // The call was a setter if the $location service is returned. 83 84 if (result === $delegate) { 85 86 // Mark the mainblock ui to allow the location change. 87 88 blockUI.$_blockLocationChange = false; 89 } 90 91 return result; 92 }; 93 } 94 95 angular.forEach(overrides, hook); 96 97 } 98 99 return $delegate; 100}]; 101 102// Called from block-ui-directive for the 'main' instance. 103 104function blockNavigation($scope, mainBlockUI, blockUIConfig) { 105 106 if (blockUIConfig.blockBrowserNavigation) { 107 108 function registerLocationChange() { 109 110 $scope.$on('$locationChangeStart', function (event) { 111 112 // console.log('$locationChangeStart', mainBlockUI.$_blockLocationChange + ' ' + mainBlockUI.state().blockCount); 113 114 if (mainBlockUI.$_blockLocationChange && mainBlockUI.state().blockCount > 0) { 115 event.preventDefault(); 116 } 117 }); 118 119 $scope.$on('$locationChangeSuccess', function () { 120 mainBlockUI.$_blockLocationChange = blockUIConfig.blockBrowserNavigation; 121 122 // console.log('$locationChangeSuccess', mainBlockUI.$_blockLocationChange + ' ' + mainBlockUI.state().blockCount); 123 }); 124 } 125 126 if (moduleLoaded('ngRoute')) { 127 128 // After the initial content has been loaded we'll spy on any location 129 // changes and discard them when needed. 130 131 var fn = $scope.$on('$viewContentLoaded', function () { 132 133 // Unhook the view loaded and hook a function that will prevent 134 // location changes while the block is active. 135 136 fn(); 137 registerLocationChange(); 138 139 }); 140 141 } else { 142 registerLocationChange(); 143 } 144 145 } 146} 147blkUI.directive('blockUiContainer', ["blockUIConfig", "blockUiContainerLinkFn", function (blockUIConfig, blockUiContainerLinkFn) { 148 return { 149 scope: true, 150 restrict: 'A', 151 templateUrl: blockUIConfig.templateUrl, 152 compile: function($element) { 153 return blockUiContainerLinkFn; 154 } 155 }; 156}]).factory('blockUiContainerLinkFn', ["blockUI", "blockUIUtils", function (blockUI, blockUIUtils) { 157 158 return function ($scope, $element, $attrs) { 159 160 var srvInstance = $element.inheritedData('block-ui'); 161 162 if (!srvInstance) { 163 throw new Error('No parent block-ui service instance located.'); 164 } 165 166 // Expose the state on the scope 167 168 $scope.state = srvInstance.state(); 169 170// $scope.$watch('state.blocking', function(value) { 171// $element.toggleClass('block-ui-visible', !!value); 172// });
173// 174// $scope.$watch('state.blockCount > 0', function(value) { 175// $element.toggleClass('block-ui-active', !!value); 176// }); 177 }; 178}]); 179blkUI.directive('blockUi', ["blockUiCompileFn", function (blockUiCompileFn) { 180 181 return { 182 scope: true, 183 restrict: 'A', 184 compile: blockUiCompileFn 185 }; 186 187}]).factory('blockUiCompileFn', ["blockUiPreLinkFn", function (blockUiPreLinkFn) { 188 189 return function ($element, $attrs) { 190 191 // Class should be added here to prevent an animation delay error. 192 193 $element.append('<div block-ui-container class="block-ui-container"></div>'); 194 195 return { 196 pre: blockUiPreLinkFn 197 }; 198 199 }; 200 201}]).factory('blockUiPreLinkFn', ["blockUI", "blockUIUtils", "blockUIConfig", function (blockUI, blockUIUtils, blockUIConfig) { 202 203 return function ($scope, $element, $attrs) { 204 205 // If the element does not have the class "block-ui" set, we set the 206 // default css classes from the config. 207 208 if (!$element.hasClass('block-ui')) { 209 $element.addClass(blockUIConfig.cssClass); 210 } 211 212 // Expose the blockUiMessageClass attribute value on the scope 213 214 $attrs.$observe('blockUiMessageClass', function (value) { 215 $scope.$_blockUiMessageClass = value; 216 }); 217 218 // Create the blockUI instance 219 // Prefix underscore to prevent integers: 220 // https://github.com/McNull/angular-block-ui/pull/8 221 222 var instanceId = $attrs.blockUi || '_' + $scope.$id; 223 var srvInstance = blockUI.instances.get(instanceId); 224 225 // If this is the main (topmost) block element we'll also need to block any 226 // location changes while the block is active. 227 228 if (instanceId === 'main') { 229 blockNavigation($scope, srvInstance, blockUIConfig); 230 } else { 231 // Locate the parent blockUI instance 232 var parentInstance = $element.inheritedData('block-ui'); 233 234 if (parentInstance) { 235 // TODO: assert if parent is already set to something else 236 srvInstance._parent = parentInstance; 237 } 238 } 239 240 // Ensure the instance is released when the scope is destroyed 241 242 $scope.$on('$destroy', function () { 243 srvInstance.release(); 244 }); 245 246 // Increase the reference count 247 248 srvInstance.addRef(); 249 250 // Expose the state on the scope 251 252 $scope.$_blockUiState = srvInstance.state(); 253 254 $scope.$watch('$_blockUiState.blocking', function (value) { 255 // Set the aria-busy attribute if needed 256 $element.attr('aria-busy', !!value); 257 $element.toggleClass('block-ui-visible', !!value); 258 }); 259 260 $scope.$watch('$_blockUiState.blockCount > 0', function (value) { 261 $element.toggleClass('block-ui-active', !!value); 262 }); 263 264 // If a pattern is provided assign it to the state 265 266 var pattern = $attrs.blockUiPattern; 267 268 if (pattern) { 269 var regExp = blockUIUtils.buildRegExp(pattern); 270 srvInstance.pattern(regExp); 271 } 272 273 // Store a reference to the service instance on the element 274 275 $element.data('block-ui', srvInstance); 276 277 }; 278 279}]); 280//.factory('blockUiPostLinkFn', function(blockUIUtils) { 281// 282// return function($scope, $element, $attrs) { 283// 284// var $message; 285// 286// $attrs.$observe('blockUiMessageClass', function(value) { 287// 288// $message = $message || blockUIUtils.findElement($element, function($e) { 289// return $e.hasClass('block-ui-message'); 290// }); 291// 292// $message.addClass(value); 293// 294// }); 295// }; 296// 297//}); 298blkUI.constant('blockUIConfig', { 299 templateUrl: 'angular-block-ui/angular-block-ui.ng.html', 300 delay: 250, 301 message: "Loading ...", 302 autoBlock: true, 303 resetOnException: true, 304 requestFilter: angular.noop, 305 autoInjectBodyBlock: true, 306 cssClass: 'block-ui block-ui-anim-fade', 307 blockBrowserNavigation: false 308}); 309 310 311blkUI.factory('blockUIHttpInterceptor', ["$q", "$injector", "blockUIConfig", "$templateCache", function($q, $injector, blockUIConfig, $templateCache) { 312 313 var blockUI; 314 315 function injectBlockUI() { 316 blockUI = blockUI || $injector.get('blockUI'); 317 } 318 319 function stopBlockUI(config) { 320 if (blockUIConfig.autoBlock && (config && !config.$_noBlock && config.$_blocks)) { 321 injectBlockUI(); 322 config.$_blocks.stop(); 323 } 324 } 325 326 function error(rejection) { 327 328 try { 329 stopBlockUI(rejection.config); 330 } catch(ex) { 331 console.log('httpRequestError', ex); 332 } 333 334 return $q.reject(rejection); 335 } 336 337 return { 338 request: function(config) { 339 340 // Only block when autoBlock is enabled ... 341 // ... and the request doesn't match a cached template. 342 343 if (blockUIConfig.autoBlock && 344 !(config.method == 'GET' && $templateCache.get(config.url))) { 345 346 // Don't block excluded requests 347 348 var result = blockUIConfig.requestFilter(config); 349 350 if (result === false) { 351 // Tag the config so we don't unblock this request 352 config.$_noBlock = true; 353 } else { 354 355 injectBlockUI(); 356 357 config.$_blocks = blockUI.instances.locate(config); 358 config.$_blocks.start(result); 359 } 360 } 361 362 return config; 363 }, 364 365 requestError: error, 366 367 response: function(response) { 368 369 // If the connection to the website goes down the response interceptor gets and error with "cannot read property config of null". 370 // https://github.com/McNull/angular-block-ui/issues/53 371 372 if(response) { 373 stopBlockUI(response.config); 374 } 375 376 return response; 377 }, 378 379 responseError: error 380 }; 381 382}]); 383 384blkUI.factory('blockUI', ["blockUIConfig", "$timeout", "blockUIUtils", "$document", function(blockUIConfig, $timeout, blockUIUtils, $document) { 385 386 var $body = $document.find('body'); 387 388 function BlockUI(id) { 389 390 var self = this; 391 392 var state = { 393 id: id, 394 blockCount: 0, 395 message: blockUIConfig.message, 396 blocking: false 397 }, startPromise, doneCallbacks = []; 398 399 this._id = id; 400 401 this._refs = 0; 402 403 this.start = function(message) { 404 405 if(state.blockCount > 0) { 406 message = message || state.message || blockUIConfig.message; 407 } else { 408 message = message || blockUIConfig.message; 409 } 410 411 state.message = message; 412 413 state.blockCount++; 414 415 // Check if the focused element is part of the block scope 416 417 var $ae = angular.element($document[0].activeElement); 418 419 if($ae.length && blockUIUtils.isElementInBlockScope($ae, self)) { 420 421 // Let the active element lose focus and store a reference 422 // to restore focus when we're done (reset) 423 424 self._restoreFocus = $ae[0]; 425 426 // https://github.com/McNull/angular-block-ui/issues/13
427 // http://stackoverflow.com/questions/22698058/apply-already-in-progress-error-when-using-typeahead-plugin-found-to-be-relate 428 // Queue the blur after any ng-blur expression. 429 430 $timeout(function() { 431 // Ensure we still need to blur 432 if(self._restoreFocus) { 433 self._restoreFocus.blur(); 434 } 435 }); 436 } 437 438 if (!startPromise) { 439 startPromise = $timeout(function() { 440 startPromise = null; 441 state.blocking = true; 442 }, blockUIConfig.delay); 443 } 444 }; 445 446 this._cancelStartTimeout = function() { 447 if (startPromise) { 448 $timeout.cancel(startPromise); 449 startPromise = null; 450 } 451 }; 452 453 this.stop = function() { 454 state.blockCount = Math.max(0, --state.blockCount); 455 456 if (state.blockCount === 0) { 457 self.reset(true); 458 } 459 }; 460 461 this.message = function(value) { 462 state.message = value; 463 }; 464 465 this.pattern = function(regexp) { 466 if (regexp !== undefined) { 467 self._pattern = regexp; 468 } 469 470 return self._pattern; 471 }; 472 473 this.reset = function(executeCallbacks) { 474 475 self._cancelStartTimeout(); 476 state.blockCount = 0; 477 state.blocking = false; 478 479 // Restore the focus to the element that was active 480 // before the block start, but not if the user has 481 // focused something else while the block was active. 482 483 if(self._restoreFocus && 484 (!$document[0].activeElement || $document[0].activeElement === $body[0])) { 485 self._restoreFocus.focus(); 486 self._restoreFocus = null; 487 } 488 489 try { 490 if (executeCallbacks) { 491 angular.forEach(doneCallbacks, function(cb) { 492 cb(); 493 }); 494 } 495 } finally { 496 doneCallbacks.length = 0; 497 } 498 }; 499 500 this.done = function(fn) { 501 doneCallbacks.push(fn); 502 }; 503 504 this.state = function() { 505 return state; 506 }; 507 508 this.addRef = function() { 509 self._refs += 1; 510 }; 511 512 this.release = function() { 513 if(--self._refs <= 0) { 514 mainBlock.instances._destroy(self); 515 } 516 }; 517 } 518 519 var instances = []; 520 521 instances.get = function(id) { 522 523 if(!isNaN(id)) { 524 throw new Error('BlockUI id cannot be a number'); 525 } 526 527 var instance = instances[id]; 528 529 if(!instance) { 530 // TODO: ensure no array instance trashing [xxx] -- current workaround: '_' + $scope.$id 531 instance = instances[id] = new BlockUI(id); 532 instances.push(instance); 533 } 534 535 return instance; 536 }; 537 538 instances._destroy = function(idOrInstance) { 539 if (angular.isString(idOrInstance)) { 540 idOrInstance = instances[idOrInstance]; 541 } 542 543 if (idOrInstance) { 544 idOrInstance.reset(); 545 546 var i = blockUIUtils.indexOf(instances, idOrInstance); 547 instances.splice(i, 1); 548 549 delete instances[idOrInstance.state().id]; 550 } 551 }; 552 553 instances.locate = function(request) { 554 555 var result = []; 556 557 // Add function wrappers that will be executed on every item 558 // in the array. 559 560 blockUIUtils.forEachFnHook(result, 'start'); 561 blockUIUtils.forEachFnHook(result, 'stop'); 562 563 var i = instances.length; 564 565 while(i--) { 566 var instance = instances[i]; 567 var pattern = instance._pattern; 568 569 if(pattern && pattern.test(request.url)) { 570 result.push(instance); 571 } 572 } 573 574 if(result.length === 0) { 575 result.push(mainBlock); 576 } 577 578 return result; 579 }; 580 581 // Propagate the reset to all instances 582 583 blockUIUtils.forEachFnHook(instances, 'reset'); 584 585 var mainBlock = instances.get('main'); 586 587 mainBlock.addRef(); 588 mainBlock.instances = instances; 589 590 return mainBlock; 591}]); 592 593 594blkUI.factory('blockUIUtils', function() { 595 596 var $ = angular.element; 597 598 var utils = { 599 buildRegExp: function(pattern) { 600 var match = pattern.match(/^\/(.*)\/([gim]*)$/), regExp; 601 602 if(match) { 603 regExp = new RegExp(match[1], match[2]); 604 } else { 605 throw Error('Incorrect regular expression format: ' + pattern); 606 } 607 608 return regExp; 609 },
610 forEachFn: function(arr, fnName, args) { 611 var i = arr.length; 612 while(i--) { 613 var t = arr[i]; 614 t[fnName].apply(t, args); 615 } 616 }, 617 forEachFnHook: function(arr, fnName) { 618 arr[fnName] = function() { 619 utils.forEachFn(this, fnName, arguments); 620 } 621 }, 622 isElementInBlockScope: function($element, blockScope) { 623 var c = $element.inheritedData('block-ui'); 624 625 while(c) { 626 if(c === blockScope) { 627 return true; 628 } 629 630 c = c._parent; 631 } 632 633 return false; 634 }, 635 findElement: function ($element, predicateFn, traverse) { 636 var ret = null; 637 638 if (predicateFn($element)) { 639 ret = $element; 640 } else { 641 642 var $elements; 643 644 if (traverse) { 645 $elements = $element.parent(); 646 } else { 647 $elements = $element.children(); 648 } 649 650 var i = $elements.length; 651 while (!ret && i--) { 652 ret = utils.findElement($($elements[i]), predicateFn, traverse); 653 } 654 } 655 656 return ret; 657 }, 658 indexOf: function(arr, obj, start) { 659// if(Array.prototype.indexOf) { 660// return arr.indexOf(obj, start); 661// } 662 663 for (var i = (start || 0), j = arr.length; i < j; i++) { 664 if (arr[i] === obj) { 665 return i; 666 } 667 } 668 669 return -1; 670 } 671 }; 672 673 return utils; 674 675}); 676// Automatically generated. 677// This file is already embedded in your main javascript output, there's no need to include this file 678// manually in the index.html. This file is only here for your debugging pleasures. 679angular.module('blockUI').run(['$templateCache', function($templateCache){ 680 $templateCache.put('angular-block-ui/angular-block-ui.ng.html', '<div class=\"block-ui-overlay\"></div><div class=\"block-ui-message-container\" aria-live=\"assertive\" aria-atomic=\"true\"><div class=\"block-ui-message\" ng-class=\"$_blockUiMessageClass\">{{ state.message }}</div></div>'); 681}]); 682})(angular); 683//# sourceMappingURL=angular-block-ui.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.