1/*! 2 angular-block-ui v0.2.1 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 // These properties are not allowed to be specified in the start method. 389 var reservedStateProperties = ['id', 'blockCount', 'blocking']; 390 391 function BlockUI(id) { 392 393 var self = this; 394 395 var state = { 396 id: id, 397 blockCount: 0, 398 message: blockUIConfig.message, 399 blocking: false 400 }, startPromise, doneCallbacks = []; 401 402 this._id = id; 403 404 this._refs = 0; 405 406 this.start = function(messageOrOptions) { 407 408 messageOrOptions = messageOrOptions || {}; 409 410 if(angular.isString(messageOrOptions)) { 411 messageOrOptions = { 412 message: messageOrOptions 413 }; 414 } else { 415 angular.forEach(reservedStateProperties, function(x) { 416 if(messageOrOptions[x]) { 417 throw new Error('The property ' + x + ' is reserved for the block state.'); 418 } 419 }); 420 } 421 422 angular.extend(state, messageOrOptions); 423 424 if(state.blockCount > 0) { 425 state.message = messageOrOptions.message || state.message || blockUIConfig.message; 426 } else { 427 state.message = messageOrOptions.message || blockUIConfig.message; 428 } 429 430 // if(state.blockCount > 0) { 431 // messageOrOptions = messageOrOptions || state.message || blockUIConfig.message; 432 // } else { 433 // messageOrOptions = messageOrOptions || blockUIConfig.message; 434 // } 435 436 // state.message = messageOrOptions; 437 438 state.blockCount++; 439 440 // Check if the focused element is part of the block scope 441 442 var $ae = angular.element($document[0].activeElement); 443 444 if($ae.length && blockUIUtils.isElementInBlockScope($ae, self)) { 445 446 // Let the active element lose focus and store a reference 447 // to restore focus when we're done (reset) 448 449 self._restoreFocus = $ae[0]; 450 451 // https://github.com/McNull/angular-block-ui/issues/13
452 // http://stackoverflow.com/questions/22698058/apply-already-in-progress-error-when-using-typeahead-plugin-found-to-be-relate 453 // Queue the blur after any ng-blur expression. 454 455 $timeout(function() { 456 // Ensure we still need to blur 457 // 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/) 458 if (self._restoreFocus && self._restoreFocus !== $body[0]) { 459 self._restoreFocus.blur(); 460 } 461 }); 462 } 463 464 if (!startPromise && blockUIConfig.delay !== 0) { 465 startPromise = $timeout(block, blockUIConfig.delay); 466 } else if (blockUIConfig.delay === 0) { 467 block(); 468 } 469 470 function block () { 471 startPromise = null; 472 state.blocking = true; 473 } 474 }; 475 476 this._cancelStartTimeout = function() { 477 if (startPromise) { 478 $timeout.cancel(startPromise); 479 startPromise = null; 480 } 481 }; 482 483 this.stop = function() { 484 state.blockCount = Math.max(0, --state.blockCount); 485 486 if (state.blockCount === 0) { 487 self.reset(true); 488 } 489 }; 490 491 this.isBlocking = function () { 492 return state.blocking; 493 }; 494 495 this.message = function(value) { 496 state.message = value; 497 }; 498 499 this.pattern = function(regexp) { 500 if (regexp !== undefined) { 501 self._pattern = regexp; 502 } 503 504 return self._pattern; 505 }; 506 507 this.reset = function(executeCallbacks) { 508 509 self._cancelStartTimeout(); 510 state.blockCount = 0; 511 state.blocking = false; 512 513 // Restore the focus to the element that was active 514 // before the block start, but not if the user has 515 // focused something else while the block was active. 516 517 if(self._restoreFocus && 518 (!$document[0].activeElement || $document[0].activeElement === $body[0])) { 519 520 //IE8 will throw if element for setting focus is invisible 521 try { 522 self._restoreFocus.focus(); 523 } catch(e1) { 524 (function () { 525 var elementToFocus = self._restoreFocus; 526 $timeout(function() { 527 if(elementToFocus) { 528 try { 529 elementToFocus.focus(); 530 } catch(e2) { } 531 } 532 },100); 533 })(); 534 } 535 536 self._restoreFocus = null; 537 } 538 539 try { 540 if (executeCallbacks) { 541 angular.forEach(doneCallbacks, function(cb) { 542 cb(); 543 }); 544 } 545 } finally { 546 doneCallbacks.length = 0; 547 } 548 }; 549 550 this.done = function(fn) { 551 doneCallbacks.push(fn); 552 }; 553 554 this.state = function() { 555 return state; 556 }; 557 558 this.addRef = function() { 559 self._refs += 1; 560 }; 561 562 this.release = function() { 563 if(--self._refs <= 0) { 564 mainBlock.instances._destroy(self); 565 } 566 }; 567 } 568 569 var instances = []; 570 571 instances.get = function(id) { 572 573 if(!isNaN(id)) { 574 throw new Error('BlockUI id cannot be a number'); 575 } 576 577 var instance = instances[id]; 578 579 if(!instance) { 580 // TODO: ensure no array instance trashing [xxx] -- current workaround: '_' + $scope.$id 581 instance = instances[id] = new BlockUI(id); 582 instances.push(instance); 583 } 584 585 return instance; 586 }; 587 588 instances._destroy = function(idOrInstance) { 589 if (angular.isString(idOrInstance)) { 590 idOrInstance = instances[idOrInstance]; 591 } 592 593 if (idOrInstance) { 594 idOrInstance.reset(); 595 596 var i = blockUIUtils.indexOf(instances, idOrInstance); 597 instances.splice(i, 1); 598 599 delete instances[idOrInstance.state().id]; 600 } 601 }; 602 603 instances.locate = function(request) { 604 605 var result = []; 606 607 // Add function wrappers that will be executed on every item 608 // in the array. 609 610 blockUIUtils.forEachFnHook(result, 'start'); 611 blockUIUtils.forEachFnHook(result, 'stop'); 612 613 var i = instances.length; 614 615 while(i--) { 616 var instance = instances[i]; 617 var pattern = instance._pattern; 618 619 if(pattern && pattern.test(request.url)) { 620 result.push(instance); 621 } 622 } 623 624 if(result.length === 0) { 625 result.push(mainBlock); 626 } 627 628 return result; 629 }; 630 631 // Propagate the reset to all instances 632
633 blockUIUtils.forEachFnHook(instances, 'reset'); 634 635 var mainBlock = instances.get('main'); 636 637 mainBlock.addRef(); 638 mainBlock.instances = instances; 639 640 return mainBlock; 641}]); 642 643 644blkUI.factory('blockUIUtils', function() { 645 646 var $ = angular.element; 647 648 var utils = { 649 buildRegExp: function(pattern) { 650 var match = pattern.match(/^\/(.*)\/([gim]*)$/), regExp; 651 652 if(match) { 653 regExp = new RegExp(match[1], match[2]); 654 } else { 655 throw Error('Incorrect regular expression format: ' + pattern); 656 } 657 658 return regExp; 659 }, 660 forEachFn: function(arr, fnName, args) { 661 var i = arr.length; 662 while(i--) { 663 var t = arr[i]; 664 t[fnName].apply(t, args); 665 } 666 }, 667 forEachFnHook: function(arr, fnName) { 668 arr[fnName] = function() { 669 utils.forEachFn(this, fnName, arguments); 670 } 671 }, 672 isElementInBlockScope: function($element, blockScope) { 673 var c = $element.inheritedData('block-ui'); 674 675 while(c) { 676 if(c === blockScope) { 677 return true; 678 } 679 680 c = c._parent; 681 } 682 683 return false; 684 }, 685 findElement: function ($element, predicateFn, traverse) { 686 var ret = null; 687 688 if (predicateFn($element)) { 689 ret = $element; 690 } else { 691 692 var $elements; 693 694 if (traverse) { 695 $elements = $element.parent(); 696 } else { 697 $elements = $element.children(); 698 } 699 700 var i = $elements.length; 701 while (!ret && i--) { 702 ret = utils.findElement($($elements[i]), predicateFn, traverse); 703 } 704 } 705 706 return ret; 707 }, 708 indexOf: function(arr, obj, start) { 709// if(Array.prototype.indexOf) { 710// return arr.indexOf(obj, start); 711// } 712 713 for (var i = (start || 0), j = arr.length; i < j; i++) { 714 if (arr[i] === obj) { 715 return i; 716 } 717 } 718 719 return -1; 720 } 721 }; 722 723 return utils; 724 725}); 726// Automatically generated. 727// This file is already embedded in your main javascript output, there's no need to include this file 728// manually in the index.html. This file is only here for your debugging pleasures. 729angular.module('blockUI').run(['$templateCache', function($templateCache){ 730 $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>'); 731}]); 732})(angular); 733//# 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.