├── .gitignore ├── .idea ├── angular-block-ui.iml ├── encodings.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── jsLibraryMappings.xml ├── libraries │ ├── angular_block_ui_node_modules.xml │ └── angular_project_template_node_modules.xml ├── misc.xml ├── modules.xml ├── runConfigurations │ ├── gulpfile_js.xml │ ├── gulpfile_js_app.xml │ ├── gulpfile_js_app_copy_readme.xml │ ├── gulpfile_js_build.xml │ ├── gulpfile_js_dist.xml │ ├── gulpfile_js_sandbox.xml │ ├── gulpfile_js_test_run.xml │ ├── gulpfile_js_test_watch.xml │ ├── http___localhost_8080_.xml │ ├── http___localhost_8080_sandbox_.xml │ └── watch_sh.xml ├── scopes │ └── scope_settings.xml ├── vcs.xml └── webResources.xml ├── LICENSE ├── README.md ├── bower.json ├── build-config.js ├── dist ├── LICENSE ├── README.md ├── angular-block-ui.css ├── angular-block-ui.css.map ├── angular-block-ui.js ├── angular-block-ui.js.map ├── angular-block-ui.min.css ├── angular-block-ui.min.js └── angular-block-ui.min.js.map ├── gulp-tasks ├── bower-task.js ├── index-task.js ├── lib │ ├── gulp-autoprefixer-map.js │ ├── gulp-bower-power.js │ ├── gulp-csswring.js │ ├── gulp-mini-filter.js │ ├── gulp-modify-content.js │ ├── gulp-rename-filename.js │ ├── gulp-sort.js │ ├── gulp-wrap-src.js │ └── ng-xml.js ├── module-tasks │ ├── clean-task.js │ ├── copy-task.js │ ├── scripts-task.js │ ├── styles-task.js │ ├── svg-task.js │ └── templates-task.js ├── modules-task.js ├── run.png ├── visual-studio.targets ├── watch.png └── watch.sh ├── gulpfile.js ├── karma.conf.js ├── package.json └── src ├── angular-block-ui ├── angular-block-ui.css ├── angular-block-ui.js ├── angular-block-ui.ng.html ├── block-navigation.js ├── block-ui-animations.css ├── block-ui-container-directive.js ├── block-ui-container-directive.test.js ├── block-ui-directive.js ├── block-ui-directive.test.js ├── config.js ├── config.test.js ├── exception-handler.test.js ├── interceptor.js ├── interceptor.test.js ├── service.js ├── service.test.js ├── utils.js └── utils.test.js ├── angular-delay └── angular-delay.js ├── angular-showdown └── angular-showdown.js ├── app ├── app.css ├── app.js ├── common │ └── directives.js ├── examples │ ├── data-array.json │ ├── element-blocking.html │ ├── element-blocking.js │ ├── examples.css │ ├── examples.js │ ├── examples.ng.html │ ├── focus-input.html │ ├── focus-input.js │ ├── manual-blocking.html │ ├── manual-blocking.js │ ├── my-demo-table.css │ ├── my-demo-table.js │ ├── my-demo-table.ng.html │ └── readme.html ├── main │ └── home.ng.html └── navbar │ ├── navbar-controller.js │ ├── navbar-controller.test.js │ ├── navbar-directive.js │ ├── navbar.css │ └── navbar.ng.html ├── index.html └── sandbox ├── animations ├── animations.css ├── animations.html ├── animations.js ├── index.html └── script.js ├── autoblocking ├── index.html ├── script.js └── style.css ├── destroy-bug ├── README.md ├── index.html ├── my-pager.html ├── people-data.json ├── script.js └── style.css ├── history-block ├── index.html ├── script.js └── style.css ├── manual-main ├── index.html ├── script.js └── style.css ├── preventroute-bug ├── index.html ├── pages │ ├── about.html │ ├── contact.html │ └── home.html └── script.js └── simple ├── index.html └── script.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/workspace.xml 2 | .idea/tasks.xml 3 | .DS_Store 4 | node_modules/* 5 | bower_components/* 6 | dest/* 7 | projectFilesBackup/ 8 | -------------------------------------------------------------------------------- /.idea/angular-block-ui.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 37 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/jsLibraryMappings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/libraries/angular_block_ui_node_modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/libraries/angular_project_template_node_modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_app_copy_readme.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_dist.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_sandbox.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_test_run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations/gulpfile_js_test_watch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/runConfigurations/http___localhost_8080_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations/http___localhost_8080_sandbox_.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/runConfigurations/watch_sh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/webResources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 McNull 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-block-ui", 3 | "description": "An AngularJS module that allows you to block user interaction on AJAX requests.", 4 | "version": "0.2.2", 5 | "keywords": [ 6 | "angular", 7 | "angularjs", 8 | "block", 9 | "block-ui", 10 | "blockui", 11 | "loading" 12 | ], 13 | "authors": [ 14 | "Null McNull " 15 | ], 16 | "license": "MIT", 17 | "ignore": [ 18 | "**/.*", 19 | "node_modules", 20 | "bower_components", 21 | "gulp-tasks", 22 | "src", 23 | "dest", 24 | "/build-config.js", 25 | "/gulpfile.js", 26 | "/package.json", 27 | "/README.md", 28 | "/karma.conf.js" 29 | ], 30 | "main": [ 31 | "dist/angular-block-ui.js", 32 | "dist/angular-block-ui.css" 33 | ], 34 | "dependencies": { 35 | "angular": "~1" 36 | }, 37 | "devDependencies": { 38 | "angular-route": "~1", 39 | "angular-resource": "~1", 40 | "angular-mocks": "~1", 41 | "angular-animate": "~1", 42 | "angular-inform": "~0.0.8", 43 | "angular-response-lag": "~0.0.1", 44 | "bootstrap": "~3.2.0", 45 | "jquery": "1.*", 46 | "respond": "~1.4.2", 47 | "html5shiv": "~3.7.2", 48 | "showdown": "~0.3.1", 49 | "animate.css": "~3.2.0", 50 | "angular-markdown-text": "~0.0.2", 51 | "angular-sanitize": "~1" 52 | }, 53 | "overrides": { 54 | "respond": { 55 | "main": "dest/respond.min.js" 56 | }, 57 | "showdown": { 58 | "main": "compressed/showdown.js" 59 | }, 60 | "angular-mocks": { 61 | "ignore": true 62 | } 63 | }, 64 | "resolutions": { 65 | "angular": "~1" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /build-config.js: -------------------------------------------------------------------------------- 1 | // - - - - - 8-< - - - - - - - - - - - - - - 2 | 3 | var _ = require('lodash'); 4 | 5 | // - - - - - 8-< - - - - - - - - - - - - - - 6 | 7 | var pkg = require('./package.json'); 8 | pkg.year = pkg.year || new Date().getFullYear(); 9 | 10 | // - - - - - 8-< - - - - - - - - - - - - - - 11 | 12 | var config = { 13 | 14 | /* 'production' || 'development' */ 15 | env: process.env.NODE_ENV, 16 | 17 | folders: { 18 | dest: 'dest/', 19 | src: 'src/' 20 | }, 21 | 22 | modules: [ 23 | { 24 | name: 'angular-block-ui', 25 | alias: 'blockUI' 26 | }, 27 | // { 28 | // name: 'angular-delay', 29 | // alias: 'delay' 30 | // }, 31 | // { 32 | // name: 'angular-showdown', 33 | // alias: 'showdown' 34 | // }, 35 | { 36 | name: 'app', 37 | alias: 'myApp' 38 | } 39 | ], 40 | 41 | bower: { 42 | includeDev: true 43 | }, 44 | 45 | header: _.template([ 46 | '/*!', 47 | ' <%= pkg.name %> v<%= pkg.version %>', 48 | ' (c) <%= pkg.year %> <%= pkg.author %> <%= pkg.homepage %>', 49 | ' License: <%= pkg.license %>', 50 | '*/\n' 51 | ].join('\n'), { pkg: pkg }) 52 | 53 | }; 54 | 55 | // - - - - - 8-< - - - - - - - - - - - - - - 56 | 57 | module.exports = config; -------------------------------------------------------------------------------- /dist/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 McNull 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dist/angular-block-ui.css: -------------------------------------------------------------------------------- 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 | 7 | .block-ui { 8 | position: relative; 9 | } 10 | 11 | body.block-ui { 12 | /* IE8 doesn't support .block-ui:not(body) */ 13 | 14 | position: static; 15 | } 16 | 17 | body.block-ui > .block-ui-container, 18 | .block-ui-main > .block-ui-container { 19 | position: fixed; 20 | } 21 | 22 | .block-ui-container { 23 | position: absolute; 24 | z-index: 10000; 25 | top: 0; 26 | right: 0; 27 | bottom: 0; 28 | left: 0; 29 | height: 0; 30 | overflow: hidden; 31 | opacity: 0; 32 | filter: alpha(opacity=00); 33 | } 34 | 35 | .block-ui-active > .block-ui-container { 36 | height: 100%; 37 | cursor: wait; 38 | } 39 | 40 | .block-ui-active .block-ui-active > .block-ui-container { 41 | height: 0; 42 | } 43 | 44 | .block-ui-visible > .block-ui-container { 45 | opacity: 1; 46 | filter: alpha(opacity=100); 47 | } 48 | 49 | .block-ui-overlay { 50 | width: 100%; 51 | height: 100%; 52 | opacity: 0.5; 53 | filter: alpha(opacity=50); 54 | background-color: white; 55 | } 56 | 57 | .block-ui-message-container { 58 | position: absolute; 59 | top: 35%; 60 | left: 0; 61 | right: 0; 62 | height: 0; 63 | text-align: center; 64 | z-index: 10001; 65 | } 66 | 67 | .block-ui-message { 68 | display: inline-block; 69 | text-align: left; 70 | background-color: #333; 71 | color: #f5f5f5; 72 | padding: 20px; 73 | border-radius: 4px; 74 | font-size: 20px; 75 | font-weight: bold; 76 | /* needed for IE */ 77 | 78 | filter: alpha(opacity=100); 79 | } 80 | 81 | /* - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 82 | 83 | .block-ui-anim-fade > .block-ui-container { 84 | transition: height 0s linear 200ms, opacity 200ms ease 0s; 85 | } 86 | 87 | .block-ui-anim-fade.block-ui-active > .block-ui-container { 88 | /*this resets the initial delay of the height */ 89 | /*and sizes the block to full height at once at the start of the block. */ 90 | transition-delay: 0s; 91 | } 92 | 93 | /* - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 94 | /*# sourceMappingURL=angular-block-ui.css.map */ -------------------------------------------------------------------------------- /dist/angular-block-ui.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["angular-block-ui-header.css","angular-block-ui.css","block-ui-animations.css"],"names":[],"mappings":"AAAA;;;;GAIA;;ACJA;EACA,oBAAA;EACA;;AAEA;EACA,8CAAA;;EAEA,kBAAA;EACA;;AAEA;;EAEA,iBAAA;EACA;;AAEA;EACA,oBAAA;EACA,gBAAA;EACA,QAAA;EACA,UAAA;EACA,WAAA;EACA,SAAA;EACA,WAAA;EACA,kBAAA;EACA,YAAA;EACA,2BAAA;EACA;;AAEA;EACA,cAAA;EACA,cAAA;EACA;;AAEA;EACA,WAAA;EACA;;AAEA;EACA,YAAA;EACA,4BAAA;EACA;;AAEA;EACA,aAAA;EACA,cAAA;EACA,cAAA;EACA,2BAAA;EACA,yBAAA;EACA;;AAEA;EACA,oBAAA;EACA,UAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,oBAAA;EACA,gBAAA;EACA;;AAEA;EACA,uBAAA;EACA,kBAAA;EACA,wBAAA;EACA,gBAAA;EACA,eAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,oBAAA;;EAEA,4BAAA;EACA;;ACvEA,kFAAA;;AAEA;EACA,2DAAA;EACA;;AAEA;EACA,iDAAA;EACA,2EAAA;EACA,sBAAA;EACA;;AAEA,kFAAA","file":"angular-block-ui.css","sourcesContent":["/*!\n angular-block-ui v0.2.1\n (c) 2015 (null) McNull https://github.com/McNull/angular-block-ui\n License: MIT\n*/\n",".block-ui {\n position: relative;\n}\n\nbody.block-ui {\n /* IE8 doesn't support .block-ui:not(body) */\n \n position: static;\n}\n\nbody.block-ui > .block-ui-container,\n.block-ui-main > .block-ui-container {\n position: fixed;\n}\n\n.block-ui-container {\n position: absolute;\n z-index: 10000;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n height: 0;\n overflow: hidden;\n opacity: 0;\n filter: alpha(opacity=00);\n}\n\n.block-ui-active > .block-ui-container {\n height: 100%;\n cursor: wait;\n}\n\n.block-ui-active .block-ui-active > .block-ui-container {\n height: 0;\n}\n\n.block-ui-visible > .block-ui-container {\n opacity: 1;\n filter: alpha(opacity=100);\n}\n\n.block-ui-overlay {\n width: 100%;\n height: 100%;\n opacity: 0.5;\n filter: alpha(opacity=50);\n background-color: white;\n}\n\n.block-ui-message-container {\n position: absolute;\n top: 35%;\n left: 0;\n right: 0;\n height: 0;\n text-align: center;\n z-index: 10001;\n}\n\n.block-ui-message {\n display: inline-block;\n text-align: left;\n background-color: #333;\n color: #f5f5f5;\n padding: 20px;\n border-radius: 4px;\n font-size: 20px;\n font-weight: bold;\n /* needed for IE */\n \n filter: alpha(opacity=100);\n}","\n/* - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */\n\n.block-ui-anim-fade > .block-ui-container {\n transition: height 0s linear 200ms, opacity 200ms ease 0s;\n}\n\n.block-ui-anim-fade.block-ui-active > .block-ui-container {\n /*this resets the initial delay of the height */\n /*and sizes the block to full height at once at the start of the block. */\n transition-delay: 0s;\n}\n\n/* - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */"],"sourceRoot":"../src/angular-block-ui"} -------------------------------------------------------------------------------- /dist/angular-block-ui.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | angular-block-ui v0.2.1 3 | (c) 2015 (null) McNull https://github.com/McNull/angular-block-ui 4 | License: MIT 5 | */.block-ui{position:relative}body.block-ui{position:static}.block-ui-main>.block-ui-container,body.block-ui>.block-ui-container{position:fixed}.block-ui-container{position:absolute;z-index:10000;top:0;right:0;bottom:0;left:0;height:0;overflow:hidden;opacity:0;filter:alpha(opacity=00)}.block-ui-active>.block-ui-container{height:100%;cursor:wait}.block-ui-active .block-ui-active>.block-ui-container{height:0}.block-ui-visible>.block-ui-container{opacity:1;filter:alpha(opacity=100)}.block-ui-overlay{width:100%;height:100%;opacity:.5;filter:alpha(opacity=50);background-color:#fff}.block-ui-message-container{position:absolute;top:35%;left:0;right:0;height:0;text-align:center;z-index:10001}.block-ui-message{display:inline-block;text-align:left;background-color:#333;color:#f5f5f5;padding:20px;border-radius:4px;font-size:20px;font-weight:700;filter:alpha(opacity=100)}.block-ui-anim-fade>.block-ui-container{transition:height 0s linear 200ms,opacity 200ms ease 0s}.block-ui-anim-fade.block-ui-active>.block-ui-container{transition-delay:0s} -------------------------------------------------------------------------------- /dist/angular-block-ui.min.js: -------------------------------------------------------------------------------- 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(t){function e(e){try{t.module(e)}catch(n){return!1}return!0}function n(t,n,o){function r(){t.$on("$locationChangeStart",function(t){n.$_blockLocationChange&&n.state().blockCount>0&&t.preventDefault()}),t.$on("$locationChangeSuccess",function(){n.$_blockLocationChange=o.blockBrowserNavigation})}if(o.blockBrowserNavigation)if(e("ngRoute"))var c=t.$on("$viewContentLoaded",function(){c(),r()});else r()}var o=t.module("blockUI",[]);o.config(["$provide","$httpProvider",function(t,e){t.decorator("$exceptionHandler",["$delegate","$injector",function(t,e){var n,o;return function(r,c){if(o=o||e.get("blockUIConfig"),o.resetOnException)try{n=n||e.get("blockUI"),n.instances.reset()}catch(i){console.log("$exceptionHandler",r)}t(r,c)}}]),e.interceptors.push("blockUIHttpInterceptor")}]),o.run(["$document","blockUIConfig","$templateCache",function(t,e,n){e.autoInjectBodyBlock&&t.find("body").attr("block-ui","main"),e.template&&(e.templateUrl="$$block-ui-template$$",n.put(e.templateUrl,e.template))}]),o.config(["$provide",function(t){t.decorator("$location",r)}]);var r=["$delegate","blockUI","blockUIConfig",function(e,n,o){function r(t){var o=e[t];e[t]=function(){var t=o.apply(e,arguments);return t===e&&(n.$_blockLocationChange=!1),t}}if(o.blockBrowserNavigation){n.$_blockLocationChange=!0;var c=["url","path","search","hash","state"];t.forEach(c,r)}return e}];o.directive("blockUiContainer",["blockUIConfig","blockUiContainerLinkFn",function(t,e){return{scope:!0,restrict:"A",templateUrl:t.templateUrl,compile:function(){return e}}}]).factory("blockUiContainerLinkFn",["blockUI","blockUIUtils",function(){return function(t,e){var n=e.inheritedData("block-ui");if(!n)throw new Error("No parent block-ui service instance located.");t.state=n.state()}}]),o.directive("blockUi",["blockUiCompileFn",function(t){return{scope:!0,restrict:"A",compile:t}}]).factory("blockUiCompileFn",["blockUiPreLinkFn",function(t){return function(e){return e.append('
'),{pre:t}}}]).factory("blockUiPreLinkFn",["blockUI","blockUIUtils","blockUIConfig",function(t,e,o){return function(r,c,i){c.hasClass("block-ui")||c.addClass(o.cssClass),i.$observe("blockUiMessageClass",function(t){r.$_blockUiMessageClass=t});var a=i.blockUi||"_"+r.$id,l=t.instances.get(a);if("main"===a)n(r,l,o);else{var s=c.inheritedData("block-ui");s&&(l._parent=s)}r.$on("$destroy",function(){l.release()}),l.addRef(),r.$_blockUiState=l.state(),r.$watch("$_blockUiState.blocking",function(t){c.attr("aria-busy",!!t),c.toggleClass("block-ui-visible",!!t)}),r.$watch("$_blockUiState.blockCount > 0",function(t){c.toggleClass("block-ui-active",!!t)});var u=i.blockUiPattern;if(u){var f=e.buildRegExp(u);l.pattern(f)}c.data("block-ui",l)}}]),o.constant("blockUIConfig",{templateUrl:"angular-block-ui/angular-block-ui.ng.html",delay:250,message:"Loading ...",autoBlock:!0,resetOnException:!0,requestFilter:t.noop,autoInjectBodyBlock:!0,cssClass:"block-ui block-ui-anim-fade",blockBrowserNavigation:!1}),o.factory("blockUIHttpInterceptor",["$q","$injector","blockUIConfig","$templateCache",function(t,e,n,o){function r(){a=a||e.get("blockUI")}function c(t){n.autoBlock&&t&&!t.$_noBlock&&t.$_blocks&&(r(),t.$_blocks.stop())}function i(e){try{c(e.config)}catch(n){console.log("httpRequestError",n)}return t.reject(e)}var a;return{request:function(t){if(n.autoBlock&&("GET"!=t.method||!o.get(t.url))){var e=n.requestFilter(t);e===!1?t.$_noBlock=!0:(r(),t.$_blocks=a.instances.locate(t),t.$_blocks.start(e))}return t},requestError:i,response:function(t){return t&&c(t.config),t},responseError:i}}]),o.factory("blockUI",["blockUIConfig","$timeout","blockUIUtils","$document",function(e,n,o,r){function c(c){var l,u=this,f={id:c,blockCount:0,message:e.message,blocking:!1},k=[];this._id=c,this._refs=0,this.start=function(c){function s(){l=null,f.blocking=!0}c=c||{},t.isString(c)?c={message:c}:t.forEach(a,function(t){if(c[t])throw new Error("The property "+t+" is reserved for the block state.")}),t.extend(f,c),f.message=f.blockCount>0?c.message||f.message||e.message:c.message||e.message,f.blockCount++;var k=t.element(r[0].activeElement);k.length&&o.isElementInBlockScope(k,u)&&(u._restoreFocus=k[0],n(function(){u._restoreFocus&&u._restoreFocus!==i[0]&&u._restoreFocus.blur()})),l||0===e.delay?0===e.delay&&s():l=n(s,e.delay)},this._cancelStartTimeout=function(){l&&(n.cancel(l),l=null)},this.stop=function(){f.blockCount=Math.max(0,--f.blockCount),0===f.blockCount&&u.reset(!0)},this.isBlocking=function(){return f.blocking},this.message=function(t){f.message=t},this.pattern=function(t){return void 0!==t&&(u._pattern=t),u._pattern},this.reset=function(e){if(u._cancelStartTimeout(),f.blockCount=0,f.blocking=!1,u._restoreFocus&&(!r[0].activeElement||r[0].activeElement===i[0])){try{u._restoreFocus.focus()}catch(o){!function(){var t=u._restoreFocus;n(function(){if(t)try{t.focus()}catch(e){}},100)}()}u._restoreFocus=null}try{e&&t.forEach(k,function(t){t()})}finally{k.length=0}},this.done=function(t){k.push(t)},this.state=function(){return f},this.addRef=function(){u._refs+=1},this.release=function(){--u._refs<=0&&s.instances._destroy(u)}}var i=r.find("body"),a=["id","blockCount","blocking"],l=[];l.get=function(t){if(!isNaN(t))throw new Error("BlockUI id cannot be a number");var e=l[t];return e||(e=l[t]=new c(t),l.push(e)),e},l._destroy=function(e){if(t.isString(e)&&(e=l[e]),e){e.reset();var n=o.indexOf(l,e);l.splice(n,1),delete l[e.state().id]}},l.locate=function(t){var e=[];o.forEachFnHook(e,"start"),o.forEachFnHook(e,"stop");for(var n=l.length;n--;){var r=l[n],c=r._pattern;c&&c.test(t.url)&&e.push(r)}return 0===e.length&&e.push(s),e},o.forEachFnHook(l,"reset");var s=l.get("main");return s.addRef(),s.instances=l,s}]),o.factory("blockUIUtils",function(){var e=t.element,n={buildRegExp:function(t){var e,n=t.match(/^\/(.*)\/([gim]*)$/);if(!n)throw Error("Incorrect regular expression format: "+t);return e=new RegExp(n[1],n[2])},forEachFn:function(t,e,n){for(var o=t.length;o--;){var r=t[o];r[e].apply(r,n)}},forEachFnHook:function(t,e){t[e]=function(){n.forEachFn(this,e,arguments)}},isElementInBlockScope:function(t,e){for(var n=t.inheritedData("block-ui");n;){if(n===e)return!0;n=n._parent}return!1},findElement:function(t,o,r){var c=null;if(o(t))c=t;else{var i;i=r?t.parent():t.children();for(var a=i.length;!c&&a--;)c=n.findElement(e(i[a]),o,r)}return c},indexOf:function(t,e,n){for(var o=n||0,r=t.length;r>o;o++)if(t[o]===e)return o;return-1}};return n}),t.module("blockUI").run(["$templateCache",function(t){t.put("angular-block-ui/angular-block-ui.ng.html",'
{{ state.message }}
')}])}(angular); 7 | //# sourceMappingURL=angular-block-ui.min.js.map -------------------------------------------------------------------------------- /dist/angular-block-ui.min.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["angular-block-ui.js"],"names":["angular","moduleLoaded","name","module","ex","blockNavigation","$scope","mainBlockUI","blockUIConfig","registerLocationChange","$on","event","$_blockLocationChange","state","blockCount","preventDefault","blockBrowserNavigation","fn","blkUI","config","$provide","$httpProvider","decorator","$delegate","$injector","blockUI","exception","cause","get","resetOnException","instances","reset","console","log","interceptors","push","run","$document","$templateCache","autoInjectBodyBlock","find","attr","template","templateUrl","put","decorateLocation","hook","f","s","result","apply","arguments","overrides","forEach","directive","blockUiContainerLinkFn","scope","restrict","compile","factory","$element","srvInstance","inheritedData","Error","blockUiCompileFn","blockUiPreLinkFn","append","pre","blockUIUtils","$attrs","hasClass","addClass","cssClass","$observe","value","$_blockUiMessageClass","instanceId","blockUi","$id","parentInstance","_parent","release","addRef","$_blockUiState","$watch","toggleClass","pattern","blockUiPattern","regExp","buildRegExp","data","constant","delay","message","autoBlock","requestFilter","noop","$q","injectBlockUI","stopBlockUI","$_noBlock","$_blocks","stop","error","rejection","reject","request","method","url","locate","start","requestError","response","responseError","$timeout","BlockUI","id","startPromise","self","this","blocking","doneCallbacks","_id","_refs","messageOrOptions","block","isString","reservedStateProperties","x","extend","$ae","element","activeElement","length","isElementInBlockScope","_restoreFocus","$body","blur","_cancelStartTimeout","cancel","Math","max","isBlocking","regexp","undefined","_pattern","executeCallbacks","focus","e1","elementToFocus","e2","cb","done","mainBlock","_destroy","isNaN","instance","idOrInstance","i","indexOf","splice","forEachFnHook","test","$","utils","match","RegExp","forEachFn","arr","fnName","args","t","blockScope","c","findElement","predicateFn","traverse","ret","$elements","parent","children","obj","j"],"mappings":";;;;;CAKA,SAAUA,GA8CV,QAASC,GAAaC,GACpB,IACEF,EAAQG,OAAOD,GACf,MAAME,GACN,OAAO,EAET,OAAO,EA8CT,QAASC,GAAgBC,EAAQC,EAAaC,GAI1C,QAASC,KAEPH,EAAOI,IAAI,uBAAwB,SAAUC,GAIvCJ,EAAYK,uBAAyBL,EAAYM,QAAQC,WAAa,GACxEH,EAAMI,mBAIVT,EAAOI,IAAI,yBAA0B,WACnCH,EAAYK,sBAAwBJ,EAAcQ,yBAdxD,GAAIR,EAAcQ,uBAoBhB,GAAIf,EAAa,WAKf,GAAIgB,GAAKX,EAAOI,IAAI,qBAAsB,WAKxCO,IACAR,UAKFA,KAtIN,GAAIS,GAAQlB,EAAQG,OAAO,aAE3Be,GAAMC,QAAQ,WAAY,gBAAiB,SAAUC,EAAUC,GAE7DD,EAASE,UAAU,qBAAsB,YAAa,YACpD,SAAUC,EAAWC,GACnB,GAAIC,GAASjB,CAEb,OAAO,UAAUkB,EAAWC,GAI1B,GAFAnB,EAAgBA,GAAiBgB,EAAUI,IAAI,iBAE3CpB,EAAcqB,iBAChB,IACEJ,EAAUA,GAAWD,EAAUI,IAAI,WACnCH,EAAQK,UAAUC,QAClB,MAAO3B,GACP4B,QAAQC,IAAI,oBAAqBP,GAIrCH,EAAUG,EAAWC,OAK3BN,EAAca,aAAaC,KAAK,6BAGlCjB,EAAMkB,KAAK,YAAa,gBAAiB,iBAAkB,SAAUC,EAAW7B,EAAe8B,GACzF9B,EAAc+B,qBAChBF,EAAUG,KAAK,QAAQC,KAAK,WAAY,QAGtCjC,EAAckC,WAKhBlC,EAAcmC,YAAc,wBAC5BL,EAAeM,IAAIpC,EAAcmC,YAAanC,EAAckC,cAYhExB,EAAMC,QAAQ,WAAY,SAAUC,GAClCA,EAASE,UAAU,YAAauB,KAGlC,IAAIA,IACF,YAAa,UAAW,gBACxB,SAAUtB,EAAWE,EAASjB,GAQ1B,QAASsC,GAAKC,GACZ,GAAIC,GAAIzB,EAAUwB,EAClBxB,GAAUwB,GAAK,WAIb,GAAIE,GAASD,EAAEE,MAAM3B,EAAW4B,UAWhC,OAPIF,KAAW1B,IAIbE,EAAQb,uBAAwB,GAG3BqC,GAvBb,GAAIzC,EAAcQ,uBAAwB,CAExCS,EAAQb,uBAAwB,CAEhC,IAAIwC,IAAa,MAAO,OAAQ,SAAU,OAAQ,QAuBlDpD,GAAQqD,QAAQD,EAAWN,GAI7B,MAAOvB,IAgDXL,GAAMoC,UAAU,oBAAqB,gBAAiB,yBAA0B,SAAU9C,EAAe+C,GACvG,OACEC,OAAO,EACPC,SAAU,IACVd,YAAanC,EAAcmC,YAC3Be,QAAS,WACP,MAAOH,QAGTI,QAAQ,0BAA2B,UAAW,eAAgB,WAEhE,MAAO,UAAUrD,EAAQsD,GAEvB,GAAIC,GAAcD,EAASE,cAAc,WAEzC,KAAKD,EACH,KAAM,IAAIE,OAAM,+CAKlBzD,GAAOO,MAAQgD,EAAYhD,YAW/BK,EAAMoC,UAAU,WAAY,mBAAoB,SAAUU,GAExD,OACER,OAAO,EACPC,SAAU,IACVC,QAASM,MAGTL,QAAQ,oBAAqB,mBAAoB,SAAUM,GAE7D,MAAO,UAAUL,GAMf,MAFAA,GAASM,OAAO,8DAGdC,IAAKF,OAKPN,QAAQ,oBAAqB,UAAW,eAAgB,gBAAiB,SAAUlC,EAAS2C,EAAc5D,GAE5G,MAAO,UAAUF,EAAQsD,EAAUS,GAK5BT,EAASU,SAAS,aACrBV,EAASW,SAAS/D,EAAcgE,UAKlCH,EAAOI,SAAS,sBAAuB,SAAUC,GAC/CpE,EAAOqE,sBAAwBD,GAOjC,IAAIE,GAAaP,EAAOQ,SAAW,IAAMvE,EAAOwE,IAC5CjB,EAAcpC,EAAQK,UAAUF,IAAIgD,EAKxC,IAAmB,SAAfA,EACFvE,EAAgBC,EAAQuD,EAAarD,OAChC,CAEL,GAAIuE,GAAiBnB,EAASE,cAAc,WAExCiB,KAEFlB,EAAYmB,QAAUD,GAM1BzE,EAAOI,IAAI,WAAY,WACrBmD,EAAYoB,YAKdpB,EAAYqB,SAIZ5E,EAAO6E,eAAiBtB,EAAYhD,QAEpCP,EAAO8E,OAAO,0BAA2B,SAAUV,GAEjDd,EAASnB,KAAK,cAAeiC,GAC7Bd,EAASyB,YAAY,qBAAsBX,KAG7CpE,EAAO8E,OAAO,gCAAiC,SAAUV,GACvDd,EAASyB,YAAY,oBAAqBX,IAK5C,IAAIY,GAAUjB,EAAOkB,cAErB,IAAID,EAAS,CACX,GAAIE,GAASpB,EAAaqB,YAAYH,EACtCzB,GAAYyB,QAAQE,GAKtB5B,EAAS8B,KAAK,WAAY7B,OAuB9B3C,EAAMyE,SAAS,iBACXhD,YAAa,4CACbiD,MAAO,IACPC,QAAS,cACTC,WAAW,EACXjE,kBAAkB,EAClBkE,cAAe/F,EAAQgG,KACvBzD,qBAAqB,EACrBiC,SAAU,8BACVxD,wBAAwB,IAI5BE,EAAMyC,QAAQ,0BAA2B,KAAM,YAAa,gBAAiB,iBAAkB,SAASsC,EAAIzE,EAAWhB,EAAe8B,GAIpI,QAAS4D,KACPzE,EAAUA,GAAWD,EAAUI,IAAI,WAGrC,QAASuE,GAAYhF,GACfX,EAAcsF,WAAc3E,IAAWA,EAAOiF,WAAajF,EAAOkF,WACpEH,IACA/E,EAAOkF,SAASC,QAIpB,QAASC,GAAMC,GAEb,IACEL,EAAYK,EAAUrF,QACtB,MAAMf,GACN4B,QAAQC,IAAI,mBAAoB7B,GAGlC,MAAO6F,GAAGQ,OAAOD,GArBnB,GAAI/E,EAwBJ,QACEiF,QAAS,SAASvF,GAKhB,GAAIX,EAAcsF,YACG,OAAjB3E,EAAOwF,SAAmBrE,EAAeV,IAAIT,EAAOyF,MAAO,CAI7D,GAAI3D,GAASzC,EAAcuF,cAAc5E,EAErC8B,MAAW,EAEb9B,EAAOiF,WAAY,GAGnBF,IAEA/E,EAAOkF,SAAW5E,EAAQK,UAAU+E,OAAO1F,GAC3CA,EAAOkF,SAASS,MAAM7D,IAI1B,MAAO9B,IAGT4F,aAAcR,EAEdS,SAAU,SAASA,GASjB,MAJGA,IACDb,EAAYa,EAAS7F,QAGhB6F,GAGTC,cAAeV,MAKnBrF,EAAMyC,QAAQ,WAAY,gBAAiB,WAAY,eAAgB,YAAa,SAASnD,EAAe0G,EAAU9C,EAAc/B,GAOlI,QAAS8E,GAAQC,GAEf,GAOGC,GAPCC,EAAOC,KAEP1G,GACFuG,GAAIA,EACJtG,WAAY,EACZ+E,QAASrF,EAAcqF,QACvB2B,UAAU,GACKC,IAEjBF,MAAKG,IAAMN,EAEXG,KAAKI,MAAQ,EAEbJ,KAAKT,MAAQ,SAASc,GAgEpB,QAASC,KACPR,EAAe,KACfxG,EAAM2G,UAAW,EAhEnBI,EAAmBA,MAEhB5H,EAAQ8H,SAASF,GAClBA,GACE/B,QAAS+B,GAGX5H,EAAQqD,QAAQ0E,EAAyB,SAASC,GAChD,GAAGJ,EAAiBI,GAClB,KAAM,IAAIjE,OAAM,gBAAkBiE,EAAI,uCAK5ChI,EAAQiI,OAAOpH,EAAO+G,GAGpB/G,EAAMgF,QADLhF,EAAMC,WAAa,EACJ8G,EAAiB/B,SAAWhF,EAAMgF,SAAWrF,EAAcqF,QAE3D+B,EAAiB/B,SAAWrF,EAAcqF,QAW5DhF,EAAMC,YAIN,IAAIoH,GAAMlI,EAAQmI,QAAQ9F,EAAU,GAAG+F,cAEpCF,GAAIG,QAAUjE,EAAakE,sBAAsBJ,EAAKZ,KAKvDA,EAAKiB,cAAgBL,EAAI,GAMzBhB,EAAS,WAGHI,EAAKiB,eAAiBjB,EAAKiB,gBAAkBC,EAAM,IACrDlB,EAAKiB,cAAcE,UAKpBpB,GAAwC,IAAxB7G,EAAcoF,MAEA,IAAxBpF,EAAcoF,OACvBiC,IAFAR,EAAeH,EAASW,EAAOrH,EAAcoF,QAWjD2B,KAAKmB,oBAAsB,WACrBrB,IACFH,EAASyB,OAAOtB,GAChBA,EAAe,OAInBE,KAAKjB,KAAO,WACVzF,EAAMC,WAAa8H,KAAKC,IAAI,IAAKhI,EAAMC,YAEd,IAArBD,EAAMC,YACRwG,EAAKvF,OAAM,IAIfwF,KAAKuB,WAAa,WACd,MAAOjI,GAAM2G,UAGjBD,KAAK1B,QAAU,SAASnB,GACtB7D,EAAMgF,QAAUnB,GAGlB6C,KAAKjC,QAAU,SAASyD,GAKtB,MAJeC,UAAXD,IACFzB,EAAK2B,SAAWF,GAGXzB,EAAK2B,UAGd1B,KAAKxF,MAAQ,SAASmH,GAUpB,GARA5B,EAAKoB,sBACL7H,EAAMC,WAAa,EACnBD,EAAM2G,UAAW,EAMdF,EAAKiB,iBACHlG,EAAU,GAAG+F,eAAiB/F,EAAU,GAAG+F,gBAAkBI,EAAM,IAAK,CAG3E,IACElB,EAAKiB,cAAcY,QACnB,MAAMC,IACN,WACI,GAAIC,GAAiB/B,EAAKiB,aAC1BrB,GAAS,WACP,GAAGmC,EACD,IACEA,EAAeF,QACf,MAAMG,MAEZ,QAINhC,EAAKiB,cAAgB,KAGvB,IACMW,GACFlJ,EAAQqD,QAAQoE,EAAe,SAAS8B,GACtCA,MAGJ,QACA9B,EAAcY,OAAS,IAI3Bd,KAAKiC,KAAO,SAASvI,GACnBwG,EAActF,KAAKlB,IAGrBsG,KAAK1G,MAAQ,WACX,MAAOA,IAGT0G,KAAKrC,OAAS,WACZoC,EAAKK,OAAS,GAGhBJ,KAAKtC,QAAU,aACRqC,EAAKK,OAAS,GACjB8B,EAAU3H,UAAU4H,SAASpC,IAlLnC,GAAIkB,GAAQnG,EAAUG,KAAK,QAGvBuF,GAA2B,KAAM,aAAc,YAoL/CjG,IAEJA,GAAUF,IAAM,SAASwF,GAEvB,IAAIuC,MAAMvC,GACR,KAAM,IAAIrD,OAAM,gCAGlB,IAAI6F,GAAW9H,EAAUsF,EAQzB,OANIwC,KAEFA,EAAW9H,EAAUsF,GAAM,GAAID,GAAQC,GACvCtF,EAAUK,KAAKyH,IAGVA,GAGT9H,EAAU4H,SAAW,SAASG,GAK5B,GAJI7J,EAAQ8H,SAAS+B,KACnBA,EAAe/H,EAAU+H,IAGvBA,EAAc,CAChBA,EAAa9H,OAEb,IAAI+H,GAAI1F,EAAa2F,QAAQjI,EAAW+H,EACxC/H,GAAUkI,OAAOF,EAAG,SAEbhI,GAAU+H,EAAahJ,QAAQuG,MAI1CtF,EAAU+E,OAAS,SAASH,GAE1B,GAAIzD,KAKJmB,GAAa6F,cAAchH,EAAQ,SACnCmB,EAAa6F,cAAchH,EAAQ,OAInC,KAFA,GAAI6G,GAAIhI,EAAUuG,OAEZyB,KAAK,CACT,GAAIF,GAAW9H,EAAUgI,GACrBxE,EAAUsE,EAASX,QAEpB3D,IAAWA,EAAQ4E,KAAKxD,EAAQE,MACjC3D,EAAOd,KAAKyH,GAQhB,MAJqB,KAAlB3G,EAAOoF,QACRpF,EAAOd,KAAKsH,GAGPxG,GAKTmB,EAAa6F,cAAcnI,EAAW,QAEtC,IAAI2H,GAAY3H,EAAUF,IAAI,OAK9B,OAHA6H,GAAUvE,SACVuE,EAAU3H,UAAYA,EAEf2H,KAITvI,EAAMyC,QAAQ,eAAgB,WAE5B,GAAIwG,GAAInK,EAAQmI,QAEZiC,GACF3E,YAAa,SAASH,GACpB,GAAiDE,GAA7C6E,EAAQ/E,EAAQ+E,MAAM,qBAE1B,KAAGA,EAGD,KAAMtG,OAAM,wCAA0CuB,EAGxD,OALEE,GAAS,GAAI8E,QAAOD,EAAM,GAAIA,EAAM,KAOxCE,UAAW,SAASC,EAAKC,EAAQC,GAE/B,IADA,GAAIZ,GAAIU,EAAInC,OACNyB,KAAK,CACT,GAAIa,GAAIH,EAAIV,EACZa,GAAEF,GAAQvH,MAAMyH,EAAGD,KAGvBT,cAAe,SAASO,EAAKC,GAC3BD,EAAIC,GAAU,WACZL,EAAMG,UAAUhD,KAAMkD,EAAQtH,aAGlCmF,sBAAuB,SAAS1E,EAAUgH,GAGxC,IAFA,GAAIC,GAAIjH,EAASE,cAAc,YAEzB+G,GAAG,CACP,GAAGA,IAAMD,EACP,OAAO,CAGTC,GAAIA,EAAE7F,QAGR,OAAO,GAET8F,YAAa,SAAUlH,EAAUmH,EAAaC,GAC5C,GAAIC,GAAM,IAEV,IAAIF,EAAYnH,GACdqH,EAAMrH,MACD,CAEL,GAAIsH,EAGFA,GADEF,EACUpH,EAASuH,SAETvH,EAASwH,UAIvB,KADA,GAAItB,GAAIoB,EAAU7C,QACV4C,GAAOnB,KACbmB,EAAMb,EAAMU,YAAYX,EAAEe,EAAUpB,IAAKiB,EAAaC,GAI1D,MAAOC,IAETlB,QAAS,SAASS,EAAKa,EAAKvE,GAK1B,IAAK,GAAIgD,GAAKhD,GAAS,EAAIwE,EAAId,EAAInC,OAAYiD,EAAJxB,EAAOA,IAChD,GAAIU,EAAIV,KAAOuB,EACb,MAAOvB,EAIX,OAAO,IAIX,OAAOM,KAMTpK,EAAQG,OAAO,WAAWiC,KAAK,iBAAkB,SAASE,GACxDA,EAAeM,IAAI,4CAA6C,2NAE/D5C","file":"angular-block-ui.min.js","sourceRoot":"./"} -------------------------------------------------------------------------------- /gulp-tasks/bower-task.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 4 | 5 | var path = require('path'); 6 | var clean = require('gulp-rimraf'); 7 | 8 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 9 | 10 | var bower = require('./lib/gulp-bower-power.js'); 11 | var config = require('../build-config.js'); 12 | 13 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 14 | 15 | module.exports = function(gulp) { 16 | gulp.task('bower-clean', function () { 17 | 18 | return gulp.src(path.join(config.folders.dest, 'vendor'), { read: false }) 19 | .pipe(clean()); 20 | 21 | }); 22 | 23 | gulp.task('bower', ['bower-clean'], function () { 24 | 25 | return bower.src(gulp, { env: config.env, includeDev: config.bower && config.bower.includeDev }) 26 | .pipe(gulp.dest(path.join(config.folders.dest, 'vendor'))); 27 | 28 | }); 29 | }; 30 | 31 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 32 | -------------------------------------------------------------------------------- /gulp-tasks/index-task.js: -------------------------------------------------------------------------------- 1 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 2 | 3 | var config = require('../build-config.js'); 4 | var modify = require('./lib/gulp-modify-content.js'); 5 | var pkg = require('../package.json'); 6 | var _ = require('lodash'); 7 | var path = require('path'); 8 | var fs = require('fs'); 9 | 10 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 11 | 12 | module.exports = function (gulp) { 13 | 14 | gulp.task('index', ['modules'], function () { 15 | 16 | return gulp.src('index.html', { 17 | cwd: config.folders.src 18 | }).pipe(modify(function (content) { 19 | 20 | var css = [], js = []; 21 | 22 | var ext = config.env === 'production' ? '.min' : ''; 23 | 24 | _.forEach(config.modules, function (module) { 25 | 26 | var moduleBase = module.name + '/' + module.name + ext; 27 | var moduleCss = moduleBase + '.css'; 28 | var moduleJs = moduleBase + '.js'; 29 | 30 | if(fs.existsSync(path.join(config.folders.dest, moduleCss))) { 31 | css.push(module.name + '/' + module.name + ext + '.css'); 32 | } 33 | 34 | if(fs.existsSync(path.join(config.folders.dest, moduleJs))) { 35 | js.push(module.name + '/' + module.name + ext + '.js'); 36 | } 37 | }); 38 | 39 | return _.template(content, { 40 | pkg: pkg, css: css, js: js 41 | }); 42 | 43 | })).pipe(gulp.dest(config.folders.dest)); 44 | 45 | }); 46 | }; 47 | 48 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 49 | -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-autoprefixer-map.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /* 4 | Hack to enable source maps in with gulp-sourcemaps and autoprefixer. 5 | 6 | Created by null on 12/08/14. 7 | 8 | npm --save-dev install through2 9 | npm --save-dev install autoprefixer 10 | npm --save-dev install vinyl-sourcemaps-apply 11 | 12 | var prefixer = require('./gulp-autoprefixer-map.js'); 13 | 14 | gulp.task('css', [], function() { 15 | .pipe(sourcemaps.init()) 16 | .pipe(prefixer()) 17 | .pipe(sourcemaps.write('.')) 18 | }); 19 | 20 | */ 21 | 22 | var through = require('through2'); 23 | var prefix = require('autoprefixer'); 24 | //var applySourceMap = require('vinyl-sourcemaps-apply'); 25 | 26 | module.exports = function(browsers, options) { 27 | 28 | options = options || {}; 29 | 30 | return through.obj(function(file, enc, cb) { 31 | 32 | if(file.isStream()) { 33 | throw new Error('Streams not supported'); 34 | } 35 | 36 | if(!file.isNull()) { 37 | 38 | if(file.sourceMap) { 39 | options.map = { 40 | prev: file.sourceMap.mappings ? file.sourceMap : undefined, 41 | annotation: false, 42 | sourcesContent: true 43 | }; 44 | options.to = options.from = file.relative; 45 | } 46 | 47 | var contents = file.contents.toString(); 48 | 49 | var result = prefix.apply(this, browsers).process(contents, options); 50 | contents = result.css; 51 | 52 | file.contents = new Buffer(contents); 53 | 54 | if(file.sourceMap) { 55 | var map = JSON.parse(result.map.toString()); 56 | 57 | map.sources = file.sourceMap.sources; 58 | map.file = file.sourceMap.file; 59 | 60 | file.sourceMap = map; 61 | 62 | //applySourceMap(file, map); 63 | } 64 | } 65 | 66 | this.push(file); 67 | cb(); 68 | 69 | }); 70 | 71 | }; 72 | -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-bower-power.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require('path'); 4 | var fs = require('fs'); 5 | 6 | var mainBowerFiles = require('main-bower-files'); 7 | 8 | module.exports = { 9 | src: src 10 | }; 11 | 12 | function src(gulp, options) { 13 | 14 | options = options || {}; 15 | 16 | // Grab globs from main-bower-files module. 17 | // This sorts out the dependencies. 18 | 19 | var globs = mainBowerFiles(options); 20 | 21 | for(var i = 0; i < globs.length; i++) { 22 | 23 | var glob = globs[i]; 24 | 25 | var ext = path.extname(glob); 26 | 27 | // Check if the extension is JS or css 28 | if(ext === '.js' || ext === '.css') { 29 | 30 | if(glob.indexOf('.min') == -1) { 31 | // Add the minified version file name to the list 32 | var dirname = path.dirname(glob); 33 | var basename = path.basename(glob); 34 | 35 | var minified = basename.split('.'); 36 | minified.splice(minified.length - 1, 0, 'min'); 37 | minified = minified.join('.'); 38 | minified = path.join(dirname, minified); 39 | 40 | i += 1; 41 | globs.splice(i, 0, minified); 42 | 43 | // Add the source map file name for the minified version 44 | 45 | i += 1; 46 | globs.splice(i, 0, minified + '.map'); 47 | } 48 | 49 | // Add the source map file name for the unminified version 50 | 51 | i += 1; 52 | globs.splice(i, 0, glob + '.map'); 53 | 54 | } 55 | } 56 | 57 | return gulp.src(globs, options); 58 | } 59 | 60 | -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-csswring.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var through = require('through2'); 4 | var csswring = require('csswring'); 5 | var applySourceMap = require('vinyl-sourcemaps-apply'); 6 | 7 | module.exports = function(options) { 8 | 9 | options = options || {}; 10 | 11 | return through.obj(function(file, enc, cb) { 12 | 13 | if(file.isStream()) { 14 | throw new Error('Streams are not supported.'); 15 | } 16 | 17 | if (!file.isNull()) { 18 | 19 | if(file.sourceMap) { 20 | options.map = { 21 | prev: file.sourceMap.mappings ? file.sourceMap : undefined, 22 | annotation: false, 23 | sourcesContent: true 24 | }; 25 | options.from = 26 | options.to = file.relative; 27 | } 28 | 29 | var contents = file.contents.toString(); 30 | 31 | var result = csswring().wring(contents, options); 32 | 33 | file.contents = new Buffer(result.css); 34 | 35 | if(file.sourceMap) { 36 | var map = JSON.parse(result.map.toString()); 37 | 38 | map.sources = file.sourceMap.sources; 39 | map.file = file.sourceMap.file; 40 | 41 | // applySourceMap(file, map); 42 | file.sourceMap = map; 43 | } 44 | } 45 | 46 | this.push(file); 47 | cb(); 48 | 49 | }); 50 | }; -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-mini-filter.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var through = require('through2'); 4 | 5 | module.exports = function filter(fn) { 6 | return through.obj(function(file, enc, cb) { 7 | 8 | if(fn(file)) { 9 | this.push(file); 10 | } 11 | 12 | cb(); 13 | }); 14 | }; -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-modify-content.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var through = require('through2'); 4 | 5 | module.exports = function modify(modifiers) { 6 | 7 | return through.obj(function(file, encoding, done) { 8 | 9 | var stream = this; 10 | 11 | function applyModifiers(content) { 12 | (typeof modifiers === 'function' ? [modifiers] : modifiers).forEach(function(modifier) { 13 | content = modifier(content, file); 14 | }); 15 | return content; 16 | } 17 | 18 | function write(data) { 19 | file.contents = new Buffer(data); 20 | stream.push(file); 21 | return done(); 22 | } 23 | 24 | if (file.isBuffer()) { 25 | return write(applyModifiers(String(file.contents))); 26 | } else if (file.isStream()) { 27 | var buffer = ''; 28 | file.contents.on('data', function(chunk) { 29 | buffer += chunk; 30 | }); 31 | file.contents.on('end', function() { 32 | write(applyModifiers(String(buffer))); 33 | }); 34 | } 35 | }); 36 | }; -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-rename-filename.js: -------------------------------------------------------------------------------- 1 | 2 | var path = require('path'); 3 | var through = require('through2'); 4 | 5 | function rename(filename) { 6 | return through.obj(function(file, enc, cb) { 7 | 8 | file.path = path.join(file.base, filename); 9 | 10 | if(file.sourceMap) { 11 | file.sourceMap.file = file.relative; 12 | } 13 | 14 | this.push(file); 15 | cb(); 16 | }); 17 | } 18 | 19 | module.exports = rename; -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-sort.js: -------------------------------------------------------------------------------- 1 | 2 | var through = require('through2'); 3 | 4 | module.exports = function(sortFn) { 5 | 6 | var files = []; 7 | 8 | function onFile(file, enc, cb) { 9 | files.push(file); 10 | cb(); 11 | } 12 | 13 | function onEnd(cb) { 14 | var self = this; 15 | 16 | files.sort(sortFn); 17 | 18 | files.forEach(function(file) { 19 | self.push(file); 20 | }); 21 | 22 | cb(); 23 | } 24 | 25 | return through.obj(onFile, onEnd); 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /gulp-tasks/lib/gulp-wrap-src.js: -------------------------------------------------------------------------------- 1 | var File = require('vinyl'); 2 | var through = require('through2'); 3 | 4 | // options = { 5 | // header: { 6 | // contents: '/* my header */', 7 | // path: 'my-virtual-header.js' 8 | // } || '/* my header */, 9 | // footer: { 10 | // contents: '/* my footer */', 11 | // path: 'my-virtual-footer.js' 12 | // } || '/* my footer */ 13 | // }; 14 | 15 | module.exports = function (options) { 16 | 17 | var pushedHeader = false; 18 | 19 | function pushHeader(file, enc, cb) { 20 | 21 | if (!pushedHeader) { 22 | pushedHeader = true; 23 | 24 | if (typeof(options.header) == 'string') { 25 | options.header = { 26 | contents: options.header 27 | }; 28 | } 29 | 30 | if (options.header.contents === undefined) { 31 | throw new Error('No header content provided.'); 32 | } 33 | 34 | var headerFile = new File({ 35 | path: options.header.path || 'header', 36 | contents: new Buffer(options.header.contents) 37 | }); 38 | 39 | this.push(headerFile); 40 | } 41 | 42 | this.push(file); 43 | cb(); 44 | 45 | } 46 | 47 | function pass(file, enc, cb) { 48 | this.push(file); 49 | cb(); 50 | } 51 | 52 | function pushFooter(cb) { 53 | 54 | if (typeof(options.footer) == 'string') { 55 | options.footer = { 56 | contents: options.footer 57 | }; 58 | } 59 | 60 | if (options.header.contents === undefined) { 61 | throw new Error('No header content provided.'); 62 | } 63 | 64 | var footerFile = new File({ 65 | path: options.footer.path || 'footer', 66 | contents: new Buffer(options.footer.contents) 67 | }); 68 | 69 | this.push(footerFile); 70 | 71 | cb(); 72 | } 73 | 74 | return through.obj( 75 | options.header ? pushHeader : pass, 76 | options.footer ? pushFooter : undefined 77 | ); 78 | }; -------------------------------------------------------------------------------- /gulp-tasks/lib/ng-xml.js: -------------------------------------------------------------------------------- 1 | // Optimised version of https://github.com/fraserxu/gulp-html2js 2 | 3 | var path = require('path'); 4 | var through = require('through2'); 5 | var File = require('vinyl'); 6 | 7 | var bsRegexp = new RegExp('\\\\', 'g'); 8 | var quoteRegexp = new RegExp('\\\"', 'g'); 9 | var nlReplace = '\\n\'' + ' +\n \''; 10 | 11 | function escape(content) { 12 | return content 13 | .replace(bsRegexp, '\\\\') 14 | .replace(quoteRegexp, '\\\"') 15 | .replace(/'/g, '\\\'') 16 | .replace(/\r?\n/g, nlReplace); 17 | } 18 | 19 | function templateCache(content, key) { 20 | return '$templateCache.put(\'' + key + '\', \'' + escape(content) + '\');' 21 | } 22 | 23 | function ensureSlashPath(p) { 24 | if (path.sep !== '/') { 25 | p = p.replace(/\\/g, '/') 26 | } 27 | return p; 28 | } 29 | 30 | /* 31 | options.base: base filepath of the template. This value is used as cache key. 32 | options.moduleName: the name of the module where to inject the templates. 33 | options.filename: [optional] target filename of the result. 34 | */ 35 | 36 | module.exports = function (options) { 37 | 38 | var buffer = []; 39 | 40 | function transform(file, encoding, callback) { 41 | 42 | var key = ensureSlashPath(path.relative(options.base, file.path)); 43 | var contents = templateCache(file.contents.toString(), key); 44 | 45 | buffer.push(' ' + contents); 46 | callback(); 47 | 48 | } 49 | 50 | function flush(callback) { 51 | 52 | var contents = 'angular.module(\'' + options.moduleName + '\').run([\'$templateCache\', function($templateCache){\n' + 53 | buffer.join('\n') + '\n}]);'; 54 | 55 | 56 | var file = new File({ 57 | path: options.filename || options.moduleName + '-templates.js', 58 | contents: new Buffer(contents) 59 | }); 60 | 61 | this.push(file); 62 | 63 | return callback(); 64 | } 65 | 66 | return through.obj(transform, flush); 67 | }; 68 | 69 | -------------------------------------------------------------------------------- /gulp-tasks/module-tasks/clean-task.js: -------------------------------------------------------------------------------- 1 | 2 | // Not used anymore; each module-task has it's own associated clean task. 3 | 4 | //var clean = require('gulp-clean'); 5 | // 6 | //module.exports = function(gulp, module) { 7 | // 8 | // module.task('clean', function () { 9 | // 10 | // return gulp.src(module.folders.dest, { read: false }) 11 | // .pipe(clean({ force: true })); 12 | // 13 | // }); 14 | // 15 | // 16 | //}; -------------------------------------------------------------------------------- /gulp-tasks/module-tasks/copy-task.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var filter = require('../lib/gulp-mini-filter.js'); 3 | var sort = require('../lib/gulp-sort'); 4 | var fs = require('fs'); 5 | var clean = require('gulp-rimraf'); 6 | 7 | module.exports = function (gulp, module) { 8 | 9 | var ignoreGlob = [ 10 | '!**/*.css', 11 | '!**/*.js', 12 | '!**/*.svg', 13 | '!**/*.map', 14 | '!**/*.less', 15 | '!**/*.map', 16 | '!**/*.ng.html', 17 | '!**/*.ignore.*' 18 | ]; 19 | 20 | // var exclude = /(\.css|\.js|\.svg|\.map|\.less|\.map|\.ng\.html)$/i; 21 | 22 | // Sometimes node is unable to read the stat property (file-busy) 23 | 24 | function isFile(file) { 25 | try { 26 | return file.stat && file.stat.isFile(); 27 | } catch (e) { 28 | return false; 29 | } 30 | } 31 | 32 | module.watch('copy', function () { 33 | 34 | return { 35 | glob: [path.join(module.folders.src, '**/*')].concat(ignoreGlob) 36 | }; 37 | 38 | }); 39 | 40 | // Cleaning the copy must go in two phases. 41 | // gulp-rimraf will throw an exception if a file is already deleted by deleting the containing directory. 42 | // So we first clean the files and then any empty directory leftovers. 43 | 44 | // This task can only start AFTER the other modules tasks. The build will crash if any of the other tasks 45 | // is writing output files and it's somehow included in the gulp.src(). 46 | 47 | module.task('copy-clean', /* ['scripts', 'styles', 'svg'] , */ function () { 48 | 49 | var outputFiles = [ 50 | path.join(module.folders.dest, '**/*') 51 | ].concat(ignoreGlob); 52 | 53 | return gulp.src(outputFiles, { read: false }) 54 | .pipe(filter(function (file) { 55 | return isFile(file); 56 | })) 57 | .pipe(clean({ force: true })); 58 | 59 | }); 60 | 61 | function copyCleanDirs() { 62 | var outputFiles = [ 63 | path.join(module.folders.dest, '**/*') 64 | ].concat(ignoreGlob); 65 | 66 | return gulp.src(outputFiles, { read: false }) 67 | .pipe(filter(function (file) { 68 | // Only include directories 69 | return !isFile(file); 70 | })) 71 | .pipe(sort(function (fileA, fileB) { 72 | // Reorder directories -- deepest first 73 | 74 | var a = fileA.path.split(path.sep).length; 75 | var b = fileB.path.split(path.sep).length; 76 | 77 | return b - a; 78 | })) 79 | .pipe(filter(function (file) { 80 | // Only empty directories 81 | var files = fs.readdirSync(file.path); 82 | return !files || files.length == 0; 83 | })) 84 | .pipe(clean({ force: true })); 85 | } 86 | 87 | module.task('copy-clean-dirs', ['copy-clean'], copyCleanDirs); 88 | 89 | module.task('copy', ['copy-clean-dirs'], function () { 90 | 91 | var glob = [ 92 | path.join(module.folders.src, '/**/*') 93 | ].concat(ignoreGlob); 94 | 95 | // module.touched.forEach(function (filename) { 96 | // glob.push('!' + filename); 97 | // }); 98 | 99 | return gulp.src(glob) 100 | .pipe(filter(function (file) { 101 | // Only copy files -- don't copy empty directories 102 | return isFile(file); 103 | })) 104 | .pipe(gulp.dest(module.folders.dest)); 105 | 106 | }); 107 | 108 | }; 109 | 110 | -------------------------------------------------------------------------------- /gulp-tasks/module-tasks/scripts-task.js: -------------------------------------------------------------------------------- 1 | var sourcemaps = require('gulp-sourcemaps'); 2 | var concat = require('gulp-concat'); 3 | var ngAnnotate = require('gulp-ng-annotate'); 4 | var uglify = require('gulp-uglify'); 5 | var path = require('path'); 6 | 7 | var wrap = require('../lib/gulp-wrap-src.js'); 8 | var config = require('../../build-config.js'); 9 | var rename = require('../lib/gulp-rename-filename.js'); 10 | var filter = require('../lib/gulp-mini-filter.js'); 11 | 12 | module.exports = function (gulp, module) { 13 | 14 | module.watch('scripts', function() { 15 | 16 | // Input files differ from the actual script task: 17 | // We're not watching the templates.js output file, since this gives problems 18 | // when a manual build occurs. 19 | // The template (ng.html) watch task fires the script task. 20 | 21 | var inputFiles = [ 22 | path.join(module.folders.src, module.name + '.js'), 23 | path.join(module.folders.src, '**/*.js'), 24 | // path.join(module.folders.dest, module.name + '-templates.js'), 25 | '!**/*.test.js', 26 | '!**/*.ignore.js' 27 | ]; 28 | 29 | return { 30 | glob: inputFiles, 31 | tasks: ['scripts-no-templates-rebuild'] 32 | }; 33 | // gulp.watch(inputFiles, [ module.name + '-scripts' ]); 34 | }); 35 | 36 | module.task('scripts-clean', function() { 37 | var outputFiles = [ 38 | path.join(module.folders.dest, module.name + '.js'), 39 | path.join(module.folders.dest, module.name + '.js.map'), 40 | path.join(module.folders.dest, module.name + '.min.js'), 41 | path.join(module.folders.dest, module.name + '.min.js.map') 42 | ]; 43 | 44 | var clean = require('gulp-rimraf'); 45 | 46 | return gulp.src(outputFiles, { read: false }) 47 | .pipe(clean({ force: true })); 48 | 49 | }); 50 | 51 | function scriptsTask() { 52 | 53 | // The input files differ from the watch task: we're including the templates.js file here. 54 | 55 | var inputFiles = [ 56 | path.join(module.folders.src, module.name + '.js'), 57 | path.join(module.folders.src, '**/*.js'), 58 | path.join(module.folders.dest, module.name + '-templates.js'), 59 | '!**/*.test.js', 60 | '!**/*.ignore.js' 61 | ]; 62 | 63 | // At the moment of writing, generating and consuming source maps isn't optimal. Compile tools merge previous 64 | // maps incorrectly, browsers aren't 100% certain about breakpoint locations and are unable to unmangle 65 | // argument names. The most stable seems to be to uglify and map in two stages: 66 | 67 | // 1. concat all js in one file and persist to the filesystem 68 | // 2. uglify the previous file and point point the content of the source map to the original file. 69 | 70 | return gulp.src(inputFiles) 71 | .pipe(module.touch()) 72 | .pipe(wrap({ 73 | header: { 74 | path: module.name + '-header.js', 75 | contents: config.header + '(function(angular) {\n' 76 | }, 77 | footer: { 78 | path: module.name + '-footer.js', 79 | contents: '})(angular);' 80 | } 81 | })) 82 | .pipe(sourcemaps.init()) 83 | .pipe(concat(module.name + '.js')) 84 | .pipe(ngAnnotate()) 85 | .pipe(sourcemaps.write('.', { sourceRoot: '../src/' + module.name })) 86 | .pipe(gulp.dest(module.folders.dest)) 87 | 88 | // Create the minified version 89 | 90 | .pipe(sourcemaps.init()) 91 | .pipe(filter(function(file) { 92 | 93 | // Filter out the previous map file. 94 | return path.extname(file.path) != '.map'; 95 | 96 | })) 97 | .pipe(rename(module.name + '.min.js')) 98 | .pipe(uglify({ preserveComments: 'some' })) 99 | .pipe(sourcemaps.write('.', { includeContent: false, sourceRoot: './' })) 100 | .pipe(gulp.dest(module.folders.dest)); 101 | } 102 | 103 | module.task('scripts-no-templates-rebuild', ['scripts-clean'], scriptsTask, true); 104 | module.task('scripts', ['scripts-clean', 'templates'], scriptsTask); 105 | }; 106 | 107 | -------------------------------------------------------------------------------- /gulp-tasks/module-tasks/styles-task.js: -------------------------------------------------------------------------------- 1 | var sourcemaps = require('gulp-sourcemaps'); 2 | var concat = require('gulp-concat'); 3 | var minifyCss = require('gulp-minify-css'); 4 | var path = require('path'); 5 | var gulpIf = require('gulp-if'); 6 | var less = require('gulp-less'); 7 | 8 | var config = require('../../build-config.js'); 9 | 10 | var prefixer = require('../lib/gulp-autoprefixer-map.js'); 11 | var rename = require('../lib/gulp-rename-filename.js'); 12 | var filter = require('../lib/gulp-mini-filter.js'); 13 | var wrapper = require('../lib/gulp-wrap-src'); 14 | 15 | module.exports = function (gulp, module) { 16 | 17 | var inputFiles = [ 18 | path.join(module.folders.src, module.name + '.less'), 19 | path.join(module.folders.src, module.name + '.css'), 20 | path.join(module.folders.src, '**/*.css'), 21 | '!**/*.ignore.css' 22 | ]; 23 | 24 | module.watch('styles', function() { 25 | 26 | // Include all *.less files in the watch 27 | var files = inputFiles.concat([]); 28 | files.splice(1, 0, path.join(module.folders.src, '**/*.less')); 29 | 30 | return { 31 | glob: files, 32 | tasks: [ 'styles' ] 33 | }; 34 | 35 | }); 36 | 37 | module.task('styles-clean', function() { 38 | 39 | var outputFiles = [ 40 | path.join(module.folders.dest, module.name + '.css'), 41 | path.join(module.folders.dest, module.name + '.css.map'), 42 | path.join(module.folders.dest, module.name + '.min.css'), 43 | path.join(module.folders.dest, module.name + '.min.css.map') 44 | ]; 45 | 46 | var clean = require('gulp-rimraf'); 47 | 48 | return gulp.src(outputFiles, { read: false }) 49 | .pipe(clean({ force: true })); 50 | 51 | }); 52 | 53 | module.task('styles', 'styles-clean', function () { 54 | 55 | // Gulp plugins with support for sourcemaps with css are minimal and buggy. 56 | // I couldn't get any minifier to output a valid sourcemap in all situations. 57 | // The task here generates two stylesheets. 58 | // 59 | // 1. unminified + concat + autoprefixed + sourcemaps 60 | // 2. minified 61 | // 62 | // The minified version is based on the output generated by the 1st but does 63 | // not have a sourcemap associated with it. 64 | 65 | return gulp.src(inputFiles) 66 | .pipe(wrapper({ 67 | header: { 68 | path: module.name + '-header.css', 69 | contents: config.header 70 | } 71 | })) 72 | 73 | // Generate the unminified stylesheet 74 | 75 | .pipe(module.touch()) 76 | .pipe(sourcemaps.init()) 77 | .pipe(gulpIf(/\.less$/ , less())) 78 | .pipe(concat(module.name + '.css')) 79 | .pipe(prefixer(['last 2 versions', '> 1%', 'ie 8'])) 80 | .pipe(filter(function(file) { 81 | 82 | // For gulp-sourcemaps to work with less import statements we'll need to rebase the file 83 | 84 | file.base = path.join(file.base, module.folders.src); 85 | file.path = path.join(file.base, module.name + '.css'); 86 | 87 | return true; 88 | 89 | })) 90 | .pipe(sourcemaps.write('.', { sourceRoot: '../src/' + module.name })) 91 | .pipe(gulp.dest(module.folders.dest)) 92 | 93 | // Generate the minified stylesheet 94 | 95 | .pipe(filter(function (file) { 96 | 97 | // delete the previous generated sourcemap so we don't trigger 98 | // sourcemap merging in csswring. 99 | 100 | delete file.sourceMap; 101 | 102 | // Filter out the previous map file. 103 | 104 | return path.extname(file.path) != '.map'; 105 | 106 | })) 107 | .pipe(minifyCss({ keepSpecialComments: 1 })) 108 | .pipe(rename(module.name + '.min.css')) 109 | .pipe(gulp.dest(module.folders.dest)); 110 | 111 | }); 112 | 113 | }; 114 | -------------------------------------------------------------------------------- /gulp-tasks/module-tasks/svg-task.js: -------------------------------------------------------------------------------- 1 | 2 | var svgmin = require('gulp-svgmin'); 3 | var path = require('path'); 4 | 5 | module.exports = function(gulp, module) { 6 | 7 | module.task('svg-clean', function() { 8 | 9 | var outputFiles = [ 10 | path.join(module.folders.dest, '**/*.svg') 11 | ]; 12 | 13 | var clean = require('gulp-rimraf'); 14 | 15 | return gulp.src(outputFiles, { read: false }) 16 | .pipe(clean({ force: true })); 17 | 18 | }); 19 | 20 | module.task('svg', 'svg-clean', function () { 21 | 22 | var glob = [ 23 | path.join(module.folders.src, '/**/*.svg'), 24 | '!**/*.ng.svg', 25 | '!**/*.ignore.svg' 26 | ]; 27 | 28 | return gulp.src(glob) 29 | .pipe(module.touch()) 30 | .pipe(svgmin()) 31 | .pipe(gulp.dest(module.folders.dest)); 32 | 33 | }); 34 | 35 | }; 36 | 37 | -------------------------------------------------------------------------------- /gulp-tasks/module-tasks/templates-task.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /** 3 | * Created by null on 11/08/14. 4 | */ 5 | 6 | var minifyHtml = require('gulp-minify-html'); 7 | var svgmin = require('gulp-svgmin'); 8 | var merge = require('merge-stream'); 9 | 10 | var path = require('path'); 11 | 12 | var ngXml = require('../lib/ng-xml.js'); 13 | var modify = require('../lib/gulp-modify-content.js'); 14 | var config = require('../../build-config.js'); 15 | 16 | module.exports = function(gulp, module) { 17 | 18 | var inputFiles = [ 19 | path.join(module.folders.src, '**/*.ng.html'), 20 | path.join(module.folders.src, '**/*.ng.svg') 21 | ]; 22 | 23 | module.watch('templates', function() { 24 | return { 25 | glob: inputFiles, 26 | tasks: ['scripts'] 27 | }; 28 | }); 29 | 30 | module.task('templates-clean', function() { 31 | 32 | var outputFiles = [ 33 | path.join(module.folders.dest, module.name + '-templates.js') 34 | ]; 35 | 36 | var clean = require('gulp-rimraf'); 37 | 38 | return gulp.src(outputFiles, { read: false }) 39 | .pipe(clean({ force: true })); 40 | 41 | }); 42 | 43 | module.task('templates', 'templates-clean', function () { 44 | 45 | var ngHtmlGlob = [ 46 | path.join(module.folders.src, '**/*.ng.html'), 47 | '!**/*.ignore.ng.html' 48 | ]; 49 | 50 | var ngSvgGlob = [ 51 | path.join(module.folders.src, '/**/*.ng.svg'), 52 | '!**/*.ignore.ng.svg' 53 | ]; 54 | 55 | var ngHtmlStream = gulp.src(ngHtmlGlob) 56 | .pipe(module.touch()) 57 | .pipe(minifyHtml({ 58 | empty: true, 59 | spare: true, 60 | quotes: true 61 | })); 62 | 63 | var ngSvgStream = gulp.src(ngSvgGlob) 64 | .pipe(module.touch()) 65 | .pipe(svgmin()); 66 | 67 | return merge(ngHtmlStream, ngSvgStream) 68 | .pipe(ngXml({ 69 | moduleName: module.alias || module.name, 70 | base: config.folders.src, 71 | filename: module.name + '-templates.js' 72 | })) 73 | .pipe(modify(function(contents) { 74 | return [ 75 | '// Automatically generated.', 76 | '// This file is already embedded in your main javascript output, there\'s no need to include this file', 77 | '// manually in the index.html. This file is only here for your debugging pleasures.', 78 | '' 79 | ].join('\n') + contents; 80 | })) 81 | .pipe(gulp.dest(module.folders.dest)); 82 | 83 | }); 84 | 85 | }; 86 | 87 | -------------------------------------------------------------------------------- /gulp-tasks/modules-task.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var through = require('through2'); 3 | var config = require('../build-config.js'); 4 | 5 | module.exports = function (gulp) { 6 | 7 | var moduleTasks = []; 8 | var moduleWatchTasks = []; 9 | 10 | for (var i = 0; i < config.modules.length; i++) (function (module) { 11 | 12 | moduleTasks.push(module.name); 13 | moduleWatchTasks.push(module.name + '-watch'); 14 | 15 | module.folders = { 16 | src: path.join(config.folders.src, module.name), 17 | dest: path.join(config.folders.dest, module.name) 18 | }; 19 | 20 | // We'll track the tasks that are created for this module so that we can one gulp task that is dependent on this list. 21 | 22 | module.tasks = []; 23 | module.task = moduleTask; 24 | 25 | // We do the same for the watch tasks. 26 | 27 | module.watchTasks = []; 28 | module.watch = moduleWatchTask; 29 | 30 | // Filenames of every file we'll process in some way is kept in this array. Everything not touched is copied to the 31 | // destination directory at the end (copy-task). 32 | 33 | module.touched = []; 34 | module.touch = moduleTouchFile; 35 | 36 | // Register all tasks for the current module. 37 | 38 | // require('./module-tasks/clean-task.js')(gulp, module); 39 | require('./module-tasks/styles-task.js')(gulp, module); 40 | require('./module-tasks/templates-task.js')(gulp, module); 41 | require('./module-tasks/scripts-task.js')(gulp, module); 42 | require('./module-tasks/svg-task.js')(gulp, module); 43 | require('./module-tasks/copy-task.js')(gulp, module); 44 | 45 | // Register a task for this module that is dependent on all sub tasks ... 46 | 47 | gulp.task(module.name, module.tasks); 48 | 49 | // ... and register a watch task for this module 50 | 51 | gulp.task(module.name + '-watch', module.watchTasks); 52 | 53 | })(config.modules[i]); 54 | 55 | // Register the main task that is dependent on all module tasks 56 | 57 | gulp.task('modules', moduleTasks); 58 | 59 | // ... and register a task that is dependent on all the module watch tasks 60 | 61 | gulp.task('modules-watch', moduleWatchTasks); 62 | 63 | // - - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - 64 | 65 | function moduleTask(taskname, depsOrFn, fn, noAutoRegister) { 66 | 67 | var module = this; 68 | 69 | if (typeof(depsOrFn) == 'string') { 70 | depsOrFn = [depsOrFn]; 71 | } 72 | 73 | if (Array.isArray(depsOrFn)) { 74 | 75 | var map = []; 76 | 77 | depsOrFn.forEach(function (dep) { 78 | map.push(module.name + '-' + dep); 79 | }); 80 | 81 | depsOrFn = map; 82 | 83 | } 84 | 85 | var fulltaskname = module.name + '-' + taskname; 86 | gulp.task(fulltaskname, depsOrFn, fn); 87 | 88 | if(!noAutoRegister) { 89 | module.tasks.push(fulltaskname); 90 | } 91 | 92 | } 93 | 94 | // - - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - 95 | 96 | function moduleWatchTask(taskname, fn) { 97 | var module = this; 98 | var fulltaskname = module.name + '-' + taskname + '-watch'; 99 | 100 | module.task(taskname + '-watch', null, function(cb) { 101 | 102 | var w = fn(); 103 | 104 | if(!w) { 105 | throw new Error('No options returned from watch: ' + taskname); 106 | } 107 | 108 | if(!w.glob) { 109 | throw new Error('No glob watch property in options: ' + taskname); 110 | } 111 | 112 | w.tasks = w.tasks || [taskname]; 113 | 114 | var i = w.tasks.length; 115 | 116 | while(i--) { 117 | w.tasks[i] = module.name + '-' + w.tasks[i]; 118 | } 119 | 120 | var watcher = gulp.watch(w.glob, w.tasks); 121 | 122 | function onEvent(event) { 123 | console.log(event); 124 | } 125 | 126 | watcher.on('change', function(event) { 127 | console.log('File ' + event.path + ' was ' + event.type + ', running tasks...'); 128 | var exec = require('child_process').exec; 129 | 130 | exec('growlnotify --image gulp-tasks/run.png -n angular-project-template -m "' + module.name + '-' + taskname + ': build triggered."') 131 | }); 132 | 133 | cb(); 134 | }, true); 135 | 136 | module.watchTasks.push(fulltaskname); 137 | } 138 | 139 | // - - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - 140 | 141 | function moduleTouchFile() { 142 | 143 | var module = this; 144 | 145 | return through.obj(function (file, enc, callback) { 146 | module.touched.push(file.path); 147 | this.push(file); 148 | return callback(); 149 | }); 150 | 151 | } 152 | 153 | // - - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - 154 | }; 155 | 156 | -------------------------------------------------------------------------------- /gulp-tasks/run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McNull/angular-block-ui/0d01eee67a6f8b0fd6beeaf16f950d1870842702/gulp-tasks/run.png -------------------------------------------------------------------------------- /gulp-tasks/visual-studio.targets: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | release 9 | debug 10 | c:\program files (x86)\nodejs\node.exe 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /gulp-tasks/watch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/McNull/angular-block-ui/0d01eee67a6f8b0fd6beeaf16f950d1870842702/gulp-tasks/watch.png -------------------------------------------------------------------------------- /gulp-tasks/watch.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # At the moment of writing gulp doesn't handle thrown exceptions very well when watching for file modifications. 4 | # This ensures the watch is up and running. 5 | 6 | # https://github.com/gulpjs/gulp/issues/216 7 | 8 | gulp build 9 | 10 | until gulp watch 11 | do growlnotify -name gulp -m "gulp watch restarted" --image watch.png 12 | sleep 1 13 | done -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 4 | 5 | var config = require('./build-config.js'); 6 | 7 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 8 | 9 | var path = require('path'); 10 | var gulp = require('gulp'); 11 | var clean = require('gulp-clean'); 12 | var karma = require('gulp-karma'); 13 | 14 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 15 | 16 | require('./gulp-tasks/bower-task.js')(gulp); 17 | require('./gulp-tasks/modules-task.js')(gulp); 18 | require('./gulp-tasks/index-task.js')(gulp); 19 | 20 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 21 | // Builds the whole kitchensink including example website 22 | 23 | gulp.task('build', [ 'modules', 'bower', 'index', 'sandbox' ]); 24 | 25 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 26 | 27 | gulp.task('app-copy-readme', ['app-copy-clean'], function() { 28 | var path = require('path'); 29 | 30 | return gulp.src('README.md') 31 | .pipe(gulp.dest(path.join(config.folders.dest, 'app'))); 32 | }); 33 | 34 | var appCopy = gulp.tasks['app-copy']; 35 | appCopy.dep.push('app-copy-readme'); 36 | 37 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 38 | 39 | gulp.task('sandbox-clean', [ 'modules', 'bower' ], function () { 40 | return gulp.src(path.join(config.folders.dest, 'sandbox')) 41 | .pipe(clean()); 42 | }); 43 | 44 | gulp.task('sandbox', [ 'sandbox-clean', 'modules', 'bower' ], function () { 45 | return gulp.src(path.join(config.folders.src, 'sandbox/**/*')) 46 | .pipe(gulp.dest(path.join(config.folders.dest, 'sandbox'))); 47 | }); 48 | 49 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 50 | 51 | gulp.task('test-run', ['angular-block-ui'], function () { 52 | 53 | return gulp.src([ 54 | 'bower_components/angular/angular.js', 55 | 'bower_components/angular-mocks/angular-mocks.js', 56 | path.join(config.folders.dest, 'angular-block-ui/angular-block-ui.min.js'), 57 | path.join(config.folders.src, 'angular-block-ui/**/*.test.js') 58 | ]) 59 | .pipe(karma({ 60 | configFile: 'karma.conf.js', 61 | action: 'run' 62 | })).on('error', function (err) { 63 | throw err; 64 | }); 65 | 66 | }); 67 | 68 | gulp.task('test-watch', ['angular-block-ui'], function () { 69 | 70 | gulp.src([ 71 | 'bower_components/angular/angular.js', 72 | 'bower_components/angular-mocks/angular-mocks.js', 73 | path.join(config.folders.src, 'angular-block-ui/angular-block-ui.js'), 74 | path.join(config.folders.dest, 'angular-block-ui/angular-block-ui-templates.js'), 75 | path.join(config.folders.src, 'angular-block-ui/**/*.js') 76 | ]) 77 | .pipe(karma({ 78 | configFile: 'karma.conf.js', 79 | action: 'watch' 80 | })); 81 | 82 | }); 83 | 84 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 85 | 86 | gulp.task('dist-clean', function () { 87 | 88 | return gulp.src('dist/**/*', { read: false }).pipe(clean()); 89 | 90 | }); 91 | 92 | gulp.task('dist', ['dist-clean', 'angular-block-ui', 'test-run'], function () { 93 | 94 | var destGlob = path.join(config.folders.dest, 'angular-block-ui/**/*'); 95 | return gulp.src([ destGlob, 'README.md', 'LICENSE', '!**/angular-block-ui-templates.js' ]) 96 | .pipe(gulp.dest('dist')); 97 | 98 | }); 99 | 100 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - 101 | 102 | gulp.task('watch', [ 'modules-watch']); 103 | gulp.task('default', [ 'dist' ]); 104 | 105 | // - - - - 8-< - - - - - - - - - - - - - - - - - - - -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 14 2014 11:05:59 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['jasmine'], 14 | 15 | 16 | // list of files / patterns to load in the browser 17 | files: [ 18 | ], 19 | 20 | 21 | // list of files to exclude 22 | exclude: [ 23 | ], 24 | 25 | 26 | // preprocess matching files before serving them to the browser 27 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 28 | preprocessors: { 29 | }, 30 | 31 | 32 | // test results reporter to use 33 | // possible values: 'dots', 'progress' 34 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 35 | reporters: ['dots', 'growl'], 36 | 37 | 38 | // web server port 39 | port: 9876, 40 | 41 | 42 | // enable / disable colors in the output (reporters and logs) 43 | colors: true, 44 | 45 | 46 | // level of logging 47 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 48 | logLevel: config.LOG_INFO, 49 | 50 | 51 | // enable / disable watching file and executing tests whenever any file changes 52 | autoWatch: true, 53 | 54 | 55 | // start these browsers 56 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 57 | browsers: ['PhantomJS'], 58 | 59 | 60 | // Continuous Integration mode 61 | // if true, Karma captures browsers, runs the tests and exits 62 | singleRun: false 63 | }); 64 | }; 65 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-block-ui", 3 | "version": "0.2.2", 4 | "description": "An AngularJS module that allows you to block user interaction on AJAX requests.", 5 | "homepage": "https://github.com/McNull/angular-block-ui", 6 | "repository": "https://github.com/McNull/angular-block-ui", 7 | "main": "gulp", 8 | "scripts": { 9 | "test": "gulp test" 10 | }, 11 | "keywords": [ 12 | "angularjs", 13 | "angular", 14 | "gulp" 15 | ], 16 | "author": "(null) McNull", 17 | "license": "MIT", 18 | "dependencies": {}, 19 | "devDependencies": { 20 | "autoprefixer": "~2.2.0", 21 | "gulp": "~3.8.7", 22 | "gulp-clean": "~0.3.1", 23 | "gulp-concat": "~2.3.4", 24 | "gulp-if": "^1.2.5", 25 | "gulp-karma": "0.0.4", 26 | "gulp-less": "^1.3.6", 27 | "gulp-minify-css": "~0.3.7", 28 | "gulp-minify-html": "~0.1.4", 29 | "gulp-ng-annotate": "~0.3.0", 30 | "gulp-rimraf": "^0.1.1", 31 | "gulp-sourcemaps": "~1.1.1", 32 | "gulp-svgmin": "~0.4.6", 33 | "gulp-uglify": "~0.3.1", 34 | "karma": "~0.12.21", 35 | "karma-growl-reporter": "~0.1.1", 36 | "karma-jasmine": "~0.1.5", 37 | "karma-phantomjs-launcher": "~0.1.4", 38 | "lodash": "~2.4.1", 39 | "main-bower-files": "~1.0.2", 40 | "merge-stream": "~0.1.5", 41 | "through2": "~0.5.1", 42 | "vinyl": "~0.3.2" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/angular-block-ui/angular-block-ui.css: -------------------------------------------------------------------------------- 1 | .block-ui { 2 | position: relative; 3 | } 4 | 5 | body.block-ui { 6 | /* IE8 doesn't support .block-ui:not(body) */ 7 | 8 | position: static; 9 | } 10 | 11 | body.block-ui > .block-ui-container, 12 | .block-ui-main > .block-ui-container { 13 | position: fixed; 14 | } 15 | 16 | .block-ui-container { 17 | position: absolute; 18 | z-index: 10000; 19 | top: 0; 20 | right: 0; 21 | bottom: 0; 22 | left: 0; 23 | height: 0; 24 | overflow: hidden; 25 | opacity: 0; 26 | filter: alpha(opacity=00); 27 | } 28 | 29 | .block-ui-active > .block-ui-container { 30 | height: 100%; 31 | cursor: wait; 32 | } 33 | 34 | .block-ui-active .block-ui-active > .block-ui-container { 35 | height: 0; 36 | } 37 | 38 | .block-ui-visible > .block-ui-container { 39 | opacity: 1; 40 | filter: alpha(opacity=100); 41 | } 42 | 43 | .block-ui-overlay { 44 | width: 100%; 45 | height: 100%; 46 | opacity: 0.5; 47 | filter: alpha(opacity=50); 48 | background-color: white; 49 | } 50 | 51 | .block-ui-message-container { 52 | position: absolute; 53 | top: 35%; 54 | left: 0; 55 | right: 0; 56 | height: 0; 57 | text-align: center; 58 | z-index: 10001; 59 | } 60 | 61 | .block-ui-message { 62 | display: inline-block; 63 | text-align: left; 64 | background-color: #333; 65 | color: #f5f5f5; 66 | padding: 20px; 67 | border-radius: 4px; 68 | font-size: 20px; 69 | font-weight: bold; 70 | /* needed for IE */ 71 | 72 | filter: alpha(opacity=100); 73 | } -------------------------------------------------------------------------------- /src/angular-block-ui/angular-block-ui.js: -------------------------------------------------------------------------------- 1 | var blkUI = angular.module('blockUI', []); 2 | 3 | blkUI.config(function ($provide, $httpProvider) { 4 | 5 | $provide.decorator('$exceptionHandler', ['$delegate', '$injector', 6 | function ($delegate, $injector) { 7 | var blockUI, blockUIConfig; 8 | 9 | return function (exception, cause) { 10 | 11 | blockUIConfig = blockUIConfig || $injector.get('blockUIConfig'); 12 | 13 | if (blockUIConfig.resetOnException) { 14 | try { 15 | blockUI = blockUI || $injector.get('blockUI'); 16 | blockUI.instances.reset(); 17 | } catch (ex) { 18 | console.log('$exceptionHandler', exception); 19 | } 20 | } 21 | 22 | $delegate(exception, cause); 23 | }; 24 | } 25 | ]); 26 | 27 | $httpProvider.interceptors.push('blockUIHttpInterceptor'); 28 | }); 29 | 30 | blkUI.run(function ($document, blockUIConfig, $templateCache) { 31 | if (blockUIConfig.autoInjectBodyBlock) { 32 | $document.find('body').attr('block-ui', 'main'); 33 | } 34 | 35 | if (blockUIConfig.template) { 36 | 37 | // Swap the builtin template with the custom template. 38 | // Create a magic cache key and place the template in the cache. 39 | 40 | blockUIConfig.templateUrl = '$$block-ui-template$$'; 41 | $templateCache.put(blockUIConfig.templateUrl, blockUIConfig.template); 42 | } 43 | }); 44 | 45 | function moduleLoaded(name) { 46 | try { 47 | angular.module(name); 48 | } catch(ex) { 49 | return false; 50 | } 51 | return true; 52 | } -------------------------------------------------------------------------------- /src/angular-block-ui/angular-block-ui.ng.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{ state.message }}
4 |
-------------------------------------------------------------------------------- /src/angular-block-ui/block-navigation.js: -------------------------------------------------------------------------------- 1 | blkUI.config(function ($provide) { 2 | $provide.decorator('$location', decorateLocation); 3 | }); 4 | 5 | var decorateLocation = [ 6 | '$delegate', 'blockUI', 'blockUIConfig', 7 | function ($delegate, blockUI, blockUIConfig) { 8 | 9 | if (blockUIConfig.blockBrowserNavigation) { 10 | 11 | blockUI.$_blockLocationChange = true; 12 | 13 | var overrides = ['url', 'path', 'search', 'hash', 'state']; 14 | 15 | function hook(f) { 16 | var s = $delegate[f]; 17 | $delegate[f] = function () { 18 | 19 | // console.log(f, Date.now(), arguments); 20 | 21 | var result = s.apply($delegate, arguments); 22 | 23 | // The call was a setter if the $location service is returned. 24 | 25 | if (result === $delegate) { 26 | 27 | // Mark the mainblock ui to allow the location change. 28 | 29 | blockUI.$_blockLocationChange = false; 30 | } 31 | 32 | return result; 33 | }; 34 | } 35 | 36 | angular.forEach(overrides, hook); 37 | 38 | } 39 | 40 | return $delegate; 41 | }]; 42 | 43 | // Called from block-ui-directive for the 'main' instance. 44 | 45 | function blockNavigation($scope, mainBlockUI, blockUIConfig) { 46 | 47 | if (blockUIConfig.blockBrowserNavigation) { 48 | 49 | function registerLocationChange() { 50 | 51 | $scope.$on('$locationChangeStart', function (event) { 52 | 53 | // console.log('$locationChangeStart', mainBlockUI.$_blockLocationChange + ' ' + mainBlockUI.state().blockCount); 54 | 55 | if (mainBlockUI.$_blockLocationChange && mainBlockUI.state().blockCount > 0) { 56 | event.preventDefault(); 57 | } 58 | }); 59 | 60 | $scope.$on('$locationChangeSuccess', function () { 61 | mainBlockUI.$_blockLocationChange = blockUIConfig.blockBrowserNavigation; 62 | 63 | // console.log('$locationChangeSuccess', mainBlockUI.$_blockLocationChange + ' ' + mainBlockUI.state().blockCount); 64 | }); 65 | } 66 | 67 | if (moduleLoaded('ngRoute')) { 68 | 69 | // After the initial content has been loaded we'll spy on any location 70 | // changes and discard them when needed. 71 | 72 | var fn = $scope.$on('$viewContentLoaded', function () { 73 | 74 | // Unhook the view loaded and hook a function that will prevent 75 | // location changes while the block is active. 76 | 77 | fn(); 78 | registerLocationChange(); 79 | 80 | }); 81 | 82 | } else { 83 | registerLocationChange(); 84 | } 85 | 86 | } 87 | } -------------------------------------------------------------------------------- /src/angular-block-ui/block-ui-animations.css: -------------------------------------------------------------------------------- 1 | 2 | /* - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 3 | 4 | .block-ui-anim-fade > .block-ui-container { 5 | transition: height 0s linear 200ms, opacity 200ms ease 0s; 6 | } 7 | 8 | .block-ui-anim-fade.block-ui-active > .block-ui-container { 9 | /*this resets the initial delay of the height */ 10 | /*and sizes the block to full height at once at the start of the block. */ 11 | transition-delay: 0s; 12 | } 13 | 14 | /* - - - - - - 8-< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ -------------------------------------------------------------------------------- /src/angular-block-ui/block-ui-container-directive.js: -------------------------------------------------------------------------------- 1 | blkUI.directive('blockUiContainer', function (blockUIConfig, blockUiContainerLinkFn) { 2 | return { 3 | scope: true, 4 | restrict: 'A', 5 | templateUrl: blockUIConfig.templateUrl, 6 | compile: function($element) { 7 | return blockUiContainerLinkFn; 8 | } 9 | }; 10 | }).factory('blockUiContainerLinkFn', function (blockUI, blockUIUtils) { 11 | 12 | return function ($scope, $element, $attrs) { 13 | 14 | var srvInstance = $element.inheritedData('block-ui'); 15 | 16 | if (!srvInstance) { 17 | throw new Error('No parent block-ui service instance located.'); 18 | } 19 | 20 | // Expose the state on the scope 21 | 22 | $scope.state = srvInstance.state(); 23 | 24 | // $scope.$watch('state.blocking', function(value) { 25 | // $element.toggleClass('block-ui-visible', !!value); 26 | // }); 27 | // 28 | // $scope.$watch('state.blockCount > 0', function(value) { 29 | // $element.toggleClass('block-ui-active', !!value); 30 | // }); 31 | }; 32 | }); -------------------------------------------------------------------------------- /src/angular-block-ui/block-ui-container-directive.test.js: -------------------------------------------------------------------------------- 1 | describe('block-ui-container-directive', function() { 2 | 3 | var $scope, $ = angular.element, $parent, blockInstanceId = "theInstance", 4 | blockInstance, blockUI, $attrs = {}, $compile, $timeout; 5 | 6 | beforeEach(function() { 7 | 8 | module('blockUI'); 9 | 10 | inject(function(_$rootScope_, _blockUI_, _$compile_, _$timeout_) { 11 | 12 | $scope = _$rootScope_.$new(); 13 | blockUI = _blockUI_; 14 | $compile = _$compile_; 15 | $timeout = _$timeout_; 16 | 17 | }); 18 | 19 | blockInstance = blockUI.instances.get(blockInstanceId); 20 | 21 | $parent = $('
'); 22 | $parent.data('block-ui', blockInstance); 23 | 24 | }); 25 | 26 | afterEach(function() { 27 | blockUI.instances._destroy(blockInstance); 28 | }); 29 | 30 | describe('template', function() { 31 | 32 | var $element; 33 | 34 | beforeEach(function() { 35 | 36 | $element = $('
'); 37 | $parent.append($element); 38 | 39 | }); 40 | 41 | it('should compile the directive', function() { 42 | 43 | $element = $compile($element)($scope); 44 | $scope.$digest(); 45 | 46 | var $children = $element.children(); 47 | 48 | expect($children.length).toBe(2); 49 | 50 | var $overlay = $($children[0]); 51 | var $message = $($children[1]); 52 | 53 | // expect($element.hasClass('block-ui-container')).toBe(true); // done by blockUi directive 54 | expect($overlay.hasClass('block-ui-overlay')).toBe(true); 55 | expect($message.hasClass('block-ui-message-container')).toBe(true); 56 | 57 | }); 58 | 59 | }); 60 | 61 | describe('link', function() { 62 | 63 | var linkFn, $element; 64 | 65 | beforeEach(function() { 66 | inject(function(blockUiContainerLinkFn) { 67 | linkFn = blockUiContainerLinkFn; 68 | }); 69 | 70 | $element = $('
'); 71 | $parent.append($element); 72 | }); 73 | 74 | it('should expose the blockstate on the scope', function() { 75 | 76 | linkFn($scope, $element, $attrs); 77 | 78 | expect($scope.state).toBeDefined(); 79 | expect($scope.state).toBe(blockInstance.state()); 80 | 81 | }); 82 | 83 | // it('should set the block-ui-container class', function() { 84 | // 85 | // linkFn($scope, $element, $attrs); 86 | // 87 | // expect($element.hasClass('block-ui-container')).toBe(true); 88 | // 89 | // }); 90 | 91 | // it('should set the block-ui-visible class when in blocking state', function() { 92 | // 93 | // linkFn($scope, $element, $attrs); 94 | // expect($element.hasClass('block-ui-visible')).toBe(false); 95 | // 96 | // blockInstance.start(); 97 | // $timeout.flush(); 98 | // $scope.$digest(); 99 | // 100 | // expect($element.hasClass('block-ui-visible')).toBe(true); 101 | // 102 | // blockInstance.stop(); 103 | // $scope.$digest(); 104 | // 105 | // expect($element.hasClass('block-ui-visible')).toBe(false); 106 | // }); 107 | // 108 | // it('should set the block-ui-active class when blockcount > 0', function() { 109 | // 110 | // linkFn($scope, $element, $attrs); 111 | // expect($element.hasClass('block-ui-active')).toBe(false); 112 | // 113 | // blockInstance.start(); 114 | // $scope.$digest(); 115 | // 116 | // expect($element.hasClass('block-ui-active')).toBe(true); 117 | // 118 | // blockInstance.stop(); 119 | // $scope.$digest(); 120 | // 121 | // expect($element.hasClass('block-ui-active')).toBe(false); 122 | // }); 123 | 124 | }); 125 | }); 126 | -------------------------------------------------------------------------------- /src/angular-block-ui/block-ui-directive.js: -------------------------------------------------------------------------------- 1 | blkUI.directive('blockUi', function (blockUiCompileFn) { 2 | 3 | return { 4 | scope: true, 5 | restrict: 'A', 6 | compile: blockUiCompileFn 7 | }; 8 | 9 | }).factory('blockUiCompileFn', function (blockUiPreLinkFn) { 10 | 11 | return function ($element, $attrs) { 12 | 13 | // Class should be added here to prevent an animation delay error. 14 | 15 | $element.append('
'); 16 | 17 | return { 18 | pre: blockUiPreLinkFn 19 | }; 20 | 21 | }; 22 | 23 | }).factory('blockUiPreLinkFn', function (blockUI, blockUIUtils, blockUIConfig) { 24 | 25 | return function ($scope, $element, $attrs) { 26 | 27 | // If the element does not have the class "block-ui" set, we set the 28 | // default css classes from the config. 29 | 30 | if (!$element.hasClass('block-ui')) { 31 | $element.addClass(blockUIConfig.cssClass); 32 | } 33 | 34 | // Expose the blockUiMessageClass attribute value on the scope 35 | 36 | $attrs.$observe('blockUiMessageClass', function (value) { 37 | $scope.$_blockUiMessageClass = value; 38 | }); 39 | 40 | // Create the blockUI instance 41 | // Prefix underscore to prevent integers: 42 | // https://github.com/McNull/angular-block-ui/pull/8 43 | 44 | var instanceId = $attrs.blockUi || '_' + $scope.$id; 45 | var srvInstance = blockUI.instances.get(instanceId); 46 | 47 | // If this is the main (topmost) block element we'll also need to block any 48 | // location changes while the block is active. 49 | 50 | if (instanceId === 'main') { 51 | blockNavigation($scope, srvInstance, blockUIConfig); 52 | } else { 53 | // Locate the parent blockUI instance 54 | var parentInstance = $element.inheritedData('block-ui'); 55 | 56 | if (parentInstance) { 57 | // TODO: assert if parent is already set to something else 58 | srvInstance._parent = parentInstance; 59 | } 60 | } 61 | 62 | // Ensure the instance is released when the scope is destroyed 63 | 64 | $scope.$on('$destroy', function () { 65 | srvInstance.release(); 66 | }); 67 | 68 | // Increase the reference count 69 | 70 | srvInstance.addRef(); 71 | 72 | // Expose the state on the scope 73 | 74 | $scope.$_blockUiState = srvInstance.state(); 75 | 76 | $scope.$watch('$_blockUiState.blocking', function (value) { 77 | // Set the aria-busy attribute if needed 78 | $element.attr('aria-busy', !!value); 79 | $element.toggleClass('block-ui-visible', !!value); 80 | }); 81 | 82 | $scope.$watch('$_blockUiState.blockCount > 0', function (value) { 83 | $element.toggleClass('block-ui-active', !!value); 84 | }); 85 | 86 | // If a pattern is provided assign it to the state 87 | 88 | var pattern = $attrs.blockUiPattern; 89 | 90 | if (pattern) { 91 | var regExp = blockUIUtils.buildRegExp(pattern); 92 | srvInstance.pattern(regExp); 93 | } 94 | 95 | // Store a reference to the service instance on the element 96 | 97 | $element.data('block-ui', srvInstance); 98 | 99 | }; 100 | 101 | }); 102 | //.factory('blockUiPostLinkFn', function(blockUIUtils) { 103 | // 104 | // return function($scope, $element, $attrs) { 105 | // 106 | // var $message; 107 | // 108 | // $attrs.$observe('blockUiMessageClass', function(value) { 109 | // 110 | // $message = $message || blockUIUtils.findElement($element, function($e) { 111 | // return $e.hasClass('block-ui-message'); 112 | // }); 113 | // 114 | // $message.addClass(value); 115 | // 116 | // }); 117 | // }; 118 | // 119 | //}); -------------------------------------------------------------------------------- /src/angular-block-ui/block-ui-directive.test.js: -------------------------------------------------------------------------------- 1 | describe('block-ui-directive', function() { 2 | 3 | var $ = angular.element, $attrs = { 4 | $observe: function(key, cb) { 5 | $scope.$watch(function() { 6 | return $attrs[key]; 7 | }, function(value) { 8 | cb(value); 9 | }); 10 | 11 | } 12 | }, $compile, $scope, blockUI, $timeout, config, configCopy, preLinkFn, postLinkFn, compileFn; 13 | 14 | beforeEach(function() { 15 | module('blockUI'); 16 | 17 | inject(function(_blockUI_, _$timeout_, _$rootScope_, _$compile_, blockUIConfig, blockUiPreLinkFn, /*blockUiPostLinkFn,*/ blockUiCompileFn) { 18 | 19 | blockUI = _blockUI_; 20 | $timeout = _$timeout_; 21 | $compile = _$compile_; 22 | $scope = _$rootScope_.$new(); 23 | config = blockUIConfig; 24 | preLinkFn = blockUiPreLinkFn; 25 | // postLinkFn = blockUiPostLinkFn; 26 | compileFn = blockUiCompileFn; 27 | 28 | }); 29 | 30 | configCopy = angular.copy(config, configCopy); 31 | }); 32 | 33 | afterEach(function() { 34 | // Reset the config back to its original settings 35 | config = angular.copy(configCopy, config); 36 | }); 37 | 38 | describe('compile', function() { 39 | 40 | it('should append block-ui-container element', function() { 41 | 42 | var $element = $('
'); 43 | 44 | compileFn($element, $attrs); 45 | 46 | var child = $element.children()[0]; 47 | 48 | expect(child.attributes['block-ui-container']).toBeDefined(); 49 | }); 50 | 51 | it('should compile the directive', function() { 52 | 53 | var $element = $('
'); 54 | 55 | ////////////////////////////////////////////////////////////////// 56 | // TODO 57 | ////////////////////////////////////////////////////////////////// 58 | 59 | }); 60 | 61 | }); 62 | 63 | describe('pre-link', function() { 64 | 65 | describe('element css class', function() { 66 | 67 | it('should apply the default classes from the config', function() { 68 | 69 | var $element = $('
'); 70 | config.cssClass = 'my-first-class my-second-class'; 71 | 72 | preLinkFn($scope, $element, $attrs); 73 | 74 | var result = $element.hasClass(config.cssClass); 75 | 76 | expect(result).toBeTruthy(); 77 | 78 | }); 79 | 80 | it('should noy apply the default classes from the config if block-ui class already set', function() { 81 | 82 | var $element = $('
'); 83 | config.cssClass = 'my-first-class my-second-class'; 84 | 85 | preLinkFn($scope, $element, $attrs); 86 | 87 | var result = $element.hasClass(config.cssClass); 88 | 89 | expect(result).toBeFalsy(); 90 | 91 | }); 92 | 93 | }); 94 | 95 | 96 | describe('block-ui service instance', function() { 97 | 98 | it('should create set the service instance as data on the element', function() { 99 | 100 | var $element = $('
'); 101 | 102 | preLinkFn($scope, $element, $attrs); 103 | 104 | var result = $element.data('block-ui'); 105 | 106 | expect(result).toBeDefined(); 107 | 108 | }); 109 | 110 | it('should use scope id when no id is provided', function() { 111 | 112 | // Prefix underscore to prevent integers: 113 | // https://github.com/McNull/angular-block-ui/pull/8 114 | 115 | var expectedId = '_' + $scope.$id; 116 | 117 | var $element = $('
'); 118 | 119 | preLinkFn($scope, $element, $attrs); 120 | 121 | expect(blockUI.instances[expectedId]).toBeDefined(); 122 | }); 123 | 124 | it('should use the provided service instance', function() { 125 | 126 | var $element = $('
'); 127 | 128 | $attrs.blockUi = 'testInstance'; 129 | preLinkFn($scope, $element, $attrs); 130 | 131 | var expected = blockUI.instances.get('testInstance'); 132 | var result = $element.data('block-ui'); 133 | 134 | expect(result).toBeDefined(); 135 | expect(result).toBe(expected); 136 | 137 | }); 138 | 139 | }); // block-ui service instance 140 | 141 | describe('parent block-ui service', function() { 142 | 143 | it('should set the _parent property of the instance to the parent instance', function() { 144 | 145 | // arrange 146 | 147 | var $parent = $('
') 148 | var parentInstance = blockUI.instances.get('parentInstance'); 149 | $parent.data('block-ui', parentInstance); 150 | 151 | var $element = angular.element('
'); 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 | // //
357 | // //
358 | // //
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 | // //
384 | // //
385 | // //
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 |
20 |
21 |
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 | 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 | 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 |
23 |
24 |
25 | Login 26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 |
34 | 35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 | Search 43 |
44 | 45 | 46 |
47 |
48 | 49 | 50 |
51 | 52 |
53 |
54 |
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 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
NameLastnameEmailCountry
{{ item.first_name }}{{ item.last_name }}{{ item.email }}{{ item.country }}
 
19 | 20 |
    21 |
  • « 22 |
  • 23 |
  • 24 | {{ i }} 25 |
  • 26 |
  • » 27 |
  • 28 |
29 |
30 | -------------------------------------------------------------------------------- /src/app/examples/readme.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
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 |
31 |
32 |
33 |
34 |
35 |
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 |
19 |
20 | 21 | 22 | GitHub Project 23 |

angular-block-ui

24 |

Setting the main block-ui instance manually.

25 |
26 |
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 | 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 |
20 |

Blocking Table Rows

21 |

With angular-block-ui 22 |

23 |
24 | 25 | 42 |
45 |
46 |
47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 66 | 69 | 70 | 71 |
IdNameLastnameEmail
{{ person.id }}{{ person.firstName }}{{ person.lastName }}{{ person.email }} 64 | 65 | 67 |

njeke ekljelk

68 |
72 |
73 |
74 |
75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /src/sandbox/destroy-bug/my-pager.html: -------------------------------------------------------------------------------- 1 |
2 | 11 |
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 |

angular-block-ui

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 | 49 | 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 |
19 |
20 | 21 | 22 | GitHub Project 23 |

angular-block-ui

24 |

Setting the main block-ui instance manually.

25 |
26 |
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 | 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 | 49 |
50 | 51 | 52 |
53 |
54 | 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 | 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 | }); --------------------------------------------------------------------------------