├── .gitignore ├── Gruntfile.coffee ├── LICENSE ├── README.md ├── bower.json ├── build ├── please-wait.css ├── please-wait.js └── please-wait.min.js ├── package.json ├── spec └── please-wait.spec.coffee └── src ├── please-wait.coffee └── please-wait.scss /.gitignore: -------------------------------------------------------------------------------- 1 | compile/* 2 | node_modules 3 | .sass-cache 4 | npm-debug.log -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = (grunt) -> 2 | grunt.loadNpmTasks 'grunt-coffeelint' 3 | grunt.loadNpmTasks 'grunt-contrib-clean' 4 | grunt.loadNpmTasks 'grunt-contrib-coffee' 5 | grunt.loadNpmTasks 'grunt-contrib-concat' 6 | grunt.loadNpmTasks 'grunt-contrib-uglify' 7 | grunt.loadNpmTasks 'grunt-contrib-compass' 8 | grunt.loadNpmTasks 'grunt-contrib-jasmine' 9 | 10 | grunt.initConfig 11 | pkg: grunt.file.readJSON 'package.json' 12 | compass: 13 | dist: 14 | options: 15 | sassDir: 'src', 16 | cssDir: 'build' 17 | meta: 18 | banner: """ 19 | /** 20 | * <%= pkg.name %> 21 | * <%= pkg.description %>\n 22 | * @author <%= pkg.author.name %> <<%= pkg.author.email %>> 23 | * @copyright <%= pkg.author.name %> <%= grunt.template.today('yyyy') %> 24 | * @license <%= pkg.licenses[0].type %> <<%= pkg.licenses[0].url %>> 25 | * @link <%= pkg.homepage %> 26 | * @module <%= pkg.module %> 27 | * @version <%= pkg.version %> 28 | */\n 29 | """ 30 | coffeelint: 31 | src: 'src/**/*.coffee' 32 | options: 33 | max_line_length: 34 | level: 'ignore' 35 | clean: 36 | dist: 37 | build: ["compile/**", "build/**"] 38 | test: 39 | build: ["compile/**"] 40 | coffee: 41 | compile: 42 | files: [ 43 | expand: true 44 | cwd: 'src/' 45 | src: '**/*.coffee' 46 | dest: 'compile/' 47 | ext: '.js' 48 | ], 49 | options: 50 | bare: true 51 | test: 52 | files: [ 53 | expand: true, 54 | cwd: 'spec', 55 | src: '**/*.coffee', 56 | dest: 'compile/spec', 57 | ext: '.js' 58 | ] 59 | concat: 60 | options: 61 | banner: '<%= meta.banner %>' 62 | dist: 63 | src: 'compile/please-wait.js' 64 | dest: 'build/please-wait.js' 65 | uglify: 66 | options: 67 | banner: '<%= meta.banner %>' 68 | dist: 69 | src: ['build/please-wait.js'] 70 | dest: 'build/please-wait.min.js' 71 | jasmine: 72 | please_wait: 73 | src: 'compile/**/*.js' 74 | options: 75 | specs: 'compile/spec/*.spec.js', 76 | helpers: 'compile/spec/*.helper.js' 77 | 78 | grunt.registerTask 'default', ['coffeelint', 'clean', 'compass', 'coffee', 'concat', 'uglify'] 79 | grunt.registerTask 'test', [ 80 | 'coffeelint', 81 | 'clean:test', 82 | 'coffee', 83 | 'jasmine' 84 | ] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Pathgather 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PleaseWait.js 2 | =========== 3 | A simple library to show your users a beautiful splash page while your application loads. 4 | 5 | Documentation and Demo 6 | --------------------- 7 | Documentation and demo can be found [here](http://pathgather.github.io/please-wait/). 8 | 9 | About Pathgather 10 | --------------------- 11 | Pathgather is an NYC-based startup building a platform that dramatically accelerates learning for enterprises by bringing employees, training content, and existing enterprise systems into one engaging platform. 12 | 13 | Every Friday, we work on open-source software (our own or other projects). Want to join our always growing team? Peruse our [current opportunities](http://www.pathgather.com/jobs/) or reach out to us at ! -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "please-wait", 3 | "version": "0.0.5", 4 | "homepage": "https://github.com/Pathgather/please-wait", 5 | "authors": [ 6 | "Pathgather " 7 | ], 8 | "description": "A nice loading screen for your SPA while users wait for complete initialization", 9 | "main": ["build/please-wait.css", "build/please-wait.js"], 10 | "moduleType": [ 11 | "globals" 12 | ], 13 | "keywords": [ 14 | "loading", 15 | "single page app", 16 | "SPA", 17 | "loading screen", 18 | "spinner" 19 | ], 20 | "license": "MIT", 21 | "ignore": [ 22 | "**/.*", 23 | "node_modules", 24 | "bower_components", 25 | "test", 26 | "tests" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /build/please-wait.css: -------------------------------------------------------------------------------- 1 | /* line 17, ../src/please-wait.scss */ 2 | body.pg-loading { 3 | overflow: hidden; 4 | } 5 | 6 | /* line 21, ../src/please-wait.scss */ 7 | .pg-loading-screen { 8 | position: fixed; 9 | bottom: 0; 10 | left: 0; 11 | right: 0; 12 | top: 0; 13 | z-index: 1000000; 14 | opacity: 1; 15 | background-color: #FFF; 16 | -webkit-transition: background-color 0.4s ease-in-out 0s; 17 | -moz-transition: background-color 0.4s ease-in-out 0s; 18 | -ms-transition: background-color 0.4s ease-in-out 0s; 19 | -o-transition: background-color 0.4s ease-in-out 0s; 20 | transition: background-color 0.4s ease-in-out 0s; 21 | } 22 | /* line 32, ../src/please-wait.scss */ 23 | .pg-loading-screen.pg-loaded { 24 | opacity: 0; 25 | -webkit-animation: pgAnimLoaded 0.5s cubic-bezier(0.7, 0, 0.3, 1) both; 26 | -moz-animation: pgAnimLoaded 0.5s cubic-bezier(0.7, 0, 0.3, 1) both; 27 | -ms-animation: pgAnimLoaded 0.5s cubic-bezier(0.7, 0, 0.3, 1) both; 28 | -o-animation: pgAnimLoaded 0.5s cubic-bezier(0.7, 0, 0.3, 1) both; 29 | animation: pgAnimLoaded 0.5s cubic-bezier(0.7, 0, 0.3, 1) both; 30 | } 31 | /* line 38, ../src/please-wait.scss */ 32 | .pg-loading-screen.pg-loading .pg-loading-logo-header, .pg-loading-screen.pg-loading .pg-loading-html { 33 | opacity: 1; 34 | } 35 | /* line 42, ../src/please-wait.scss */ 36 | .pg-loading-screen.pg-loading .pg-loading-logo-header, .pg-loading-screen.pg-loading .pg-loading-html:not(.pg-loaded) { 37 | -webkit-animation: pgAnimLoading 1s cubic-bezier(0.7, 0, 0.3, 1) both; 38 | -moz-animation: pgAnimLoading 1s cubic-bezier(0.7, 0, 0.3, 1) both; 39 | -ms-animation: pgAnimLoading 1s cubic-bezier(0.7, 0, 0.3, 1) both; 40 | -o-animation: pgAnimLoading 1s cubic-bezier(0.7, 0, 0.3, 1) both; 41 | animation: pgAnimLoading 1s cubic-bezier(0.7, 0, 0.3, 1) both; 42 | } 43 | /* line 46, ../src/please-wait.scss */ 44 | .pg-loading-screen.pg-loading .pg-loading-html:not(.pg-loaded) { 45 | -webkit-animation-delay: 0.3s; 46 | -moz-animation-delay: 0.3s; 47 | -ms-animation-delay: 0.3s; 48 | -o-animation-delay: 0.3s; 49 | animation-delay: 0.3s; 50 | } 51 | /* line 51, ../src/please-wait.scss */ 52 | .pg-loading-screen .pg-loading-inner { 53 | height: 100%; 54 | width: 100%; 55 | margin: 0; 56 | padding: 0; 57 | position: static; 58 | } 59 | /* line 59, ../src/please-wait.scss */ 60 | .pg-loading-screen .pg-loading-center-outer { 61 | width: 100%; 62 | padding: 0; 63 | display: table !important; 64 | height: 100%; 65 | position: absolute; 66 | top: 0; 67 | left: 0; 68 | margin: 0; 69 | } 70 | /* line 70, ../src/please-wait.scss */ 71 | .pg-loading-screen .pg-loading-center-middle { 72 | padding: 0; 73 | vertical-align: middle; 74 | display: table-cell !important; 75 | margin: 0; 76 | text-align: center; 77 | } 78 | /* line 78, ../src/please-wait.scss */ 79 | .pg-loading-screen .pg-loading-logo-header, .pg-loading-screen .pg-loading-html { 80 | width: 100%; 81 | opacity: 0; 82 | } 83 | /* line 83, ../src/please-wait.scss */ 84 | .pg-loading-screen .pg-loading-logo-header { 85 | text-align: center; 86 | } 87 | /* line 86, ../src/please-wait.scss */ 88 | .pg-loading-screen .pg-loading-logo-header img { 89 | display: inline-block !important; 90 | } 91 | /* line 91, ../src/please-wait.scss */ 92 | .pg-loading-screen .pg-loading-html { 93 | margin-top: 90px; 94 | } 95 | /* line 94, ../src/please-wait.scss */ 96 | .pg-loading-screen .pg-loading-html.pg-loaded { 97 | -webkit-transition: opacity 0.5s cubic-bezier(0.7, 0, 0.3, 1); 98 | -moz-transition: opacity 0.5s cubic-bezier(0.7, 0, 0.3, 1); 99 | -ms-transition: opacity 0.5s cubic-bezier(0.7, 0, 0.3, 1); 100 | -o-transition: opacity 0.5s cubic-bezier(0.7, 0, 0.3, 1); 101 | transition: opacity 0.5s cubic-bezier(0.7, 0, 0.3, 1); 102 | } 103 | /* line 97, ../src/please-wait.scss */ 104 | .pg-loading-screen .pg-loading-html.pg-loaded.pg-removing { 105 | opacity: 0; 106 | } 107 | /* line 101, ../src/please-wait.scss */ 108 | .pg-loading-screen .pg-loading-html.pg-loaded.pg-loading { 109 | opacity: 1; 110 | } 111 | 112 | @-webkit-keyframes pgAnimLoading { 113 | from { 114 | opacity: 0; 115 | } 116 | } 117 | @-moz-keyframes pgAnimLoading { 118 | from { 119 | opacity: 0; 120 | } 121 | } 122 | @-o-keyframes pgAnimLoading { 123 | from { 124 | opacity: 0; 125 | } 126 | } 127 | @-ms-keyframes pgAnimLoading { 128 | from { 129 | opacity: 0; 130 | } 131 | } 132 | @keyframes pgAnimLoading { 133 | from { 134 | opacity: 0; 135 | } 136 | } 137 | @-webkit-keyframes pgAnimLoaded { 138 | from { 139 | opacity: 1; 140 | } 141 | } 142 | @-moz-keyframes pgAnimLoaded { 143 | from { 144 | opacity: 1; 145 | } 146 | } 147 | @-o-keyframes pgAnimLoaded { 148 | from { 149 | opacity: 1; 150 | } 151 | } 152 | @-ms-keyframes pgAnimLoaded { 153 | from { 154 | opacity: 1; 155 | } 156 | } 157 | @keyframes pgAnimLoaded { 158 | from { 159 | opacity: 1; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /build/please-wait.js: -------------------------------------------------------------------------------- 1 | /** 2 | * please-wait 3 | * Display a nice loading screen while your app loads 4 | 5 | * @author Pathgather 6 | * @copyright Pathgather 2015 7 | * @license MIT 8 | * @link https://github.com/Pathgather/please-wait 9 | * @module please-wait 10 | * @version 0.0.5 11 | */ 12 | (function(root, factory) { 13 | if (typeof exports === "object") { 14 | factory(exports); 15 | } else if (typeof define === "function" && define.amd) { 16 | define(["exports"], factory); 17 | } else { 18 | factory(root); 19 | } 20 | })(this, function(exports) { 21 | var PleaseWait, addClass, animationEvent, animationSupport, domPrefixes, elm, key, pfx, pleaseWait, removeClass, transEndEventNames, transitionEvent, transitionSupport, val, _i, _len; 22 | elm = document.createElement('fakeelement'); 23 | animationSupport = false; 24 | transitionSupport = false; 25 | animationEvent = 'animationend'; 26 | transitionEvent = null; 27 | domPrefixes = 'Webkit Moz O ms'.split(' '); 28 | transEndEventNames = { 29 | 'WebkitTransition': 'webkitTransitionEnd', 30 | 'MozTransition': 'transitionend', 31 | 'OTransition': 'oTransitionEnd', 32 | 'msTransition': 'MSTransitionEnd', 33 | 'transition': 'transitionend' 34 | }; 35 | for (key in transEndEventNames) { 36 | val = transEndEventNames[key]; 37 | if (elm.style[key] != null) { 38 | transitionEvent = val; 39 | transitionSupport = true; 40 | break; 41 | } 42 | } 43 | if (elm.style.animationName != null) { 44 | animationSupport = true; 45 | } 46 | if (!animationSupport) { 47 | for (_i = 0, _len = domPrefixes.length; _i < _len; _i++) { 48 | pfx = domPrefixes[_i]; 49 | if (elm.style["" + pfx + "AnimationName"] != null) { 50 | switch (pfx) { 51 | case 'Webkit': 52 | animationEvent = 'webkitAnimationEnd'; 53 | break; 54 | case 'Moz': 55 | animationEvent = 'animationend'; 56 | break; 57 | case 'O': 58 | animationEvent = 'oanimationend'; 59 | break; 60 | case 'ms': 61 | animationEvent = 'MSAnimationEnd'; 62 | } 63 | animationSupport = true; 64 | break; 65 | } 66 | } 67 | } 68 | addClass = function(classname, elem) { 69 | if (elem.classList) { 70 | return elem.classList.add(classname); 71 | } else { 72 | return elem.className += " " + classname; 73 | } 74 | }; 75 | removeClass = function(classname, elem) { 76 | if (elem.classList) { 77 | return elem.classList.remove(classname); 78 | } else { 79 | return elem.className = elem.className.replace(classname, "").trim(); 80 | } 81 | }; 82 | PleaseWait = (function() { 83 | PleaseWait._defaultOptions = { 84 | backgroundColor: null, 85 | logo: null, 86 | loadingHtml: null, 87 | template: "
\n
\n
\n

\n \n

\n
\n
\n
\n
\n
", 88 | onLoadedCallback: null 89 | }; 90 | 91 | function PleaseWait(options) { 92 | var defaultOptions, k, listener, v; 93 | defaultOptions = this.constructor._defaultOptions; 94 | this.options = {}; 95 | this.loaded = false; 96 | this.finishing = false; 97 | for (k in defaultOptions) { 98 | v = defaultOptions[k]; 99 | this.options[k] = options[k] != null ? options[k] : v; 100 | } 101 | this._loadingElem = document.createElement("div"); 102 | this._loadingHtmlToDisplay = []; 103 | this._loadingElem.className = "pg-loading-screen"; 104 | if (this.options.backgroundColor != null) { 105 | this._loadingElem.style.backgroundColor = this.options.backgroundColor; 106 | } 107 | this._loadingElem.innerHTML = this.options.template; 108 | this._loadingHtmlElem = this._loadingElem.getElementsByClassName("pg-loading-html")[0]; 109 | if (this._loadingHtmlElem != null) { 110 | this._loadingHtmlElem.innerHTML = this.options.loadingHtml; 111 | } 112 | this._readyToShowLoadingHtml = false; 113 | this._logoElem = this._loadingElem.getElementsByClassName("pg-loading-logo")[0]; 114 | if (this._logoElem != null) { 115 | this._logoElem.src = this.options.logo; 116 | } 117 | removeClass("pg-loaded", document.body); 118 | addClass("pg-loading", document.body); 119 | document.body.appendChild(this._loadingElem); 120 | addClass("pg-loading", this._loadingElem); 121 | this._onLoadedCallback = this.options.onLoadedCallback; 122 | listener = (function(_this) { 123 | return function(evt) { 124 | _this.loaded = true; 125 | _this._readyToShowLoadingHtml = true; 126 | addClass("pg-loaded", _this._loadingHtmlElem); 127 | if (animationSupport) { 128 | _this._loadingHtmlElem.removeEventListener(animationEvent, listener); 129 | } 130 | if (_this._loadingHtmlToDisplay.length > 0) { 131 | _this._changeLoadingHtml(); 132 | } 133 | if (_this.finishing) { 134 | if (evt != null) { 135 | evt.stopPropagation(); 136 | } 137 | return _this._finish(); 138 | } 139 | }; 140 | })(this); 141 | if (this._loadingHtmlElem != null) { 142 | if (animationSupport) { 143 | this._loadingHtmlElem.addEventListener(animationEvent, listener); 144 | } else { 145 | listener(); 146 | } 147 | this._loadingHtmlListener = (function(_this) { 148 | return function() { 149 | _this._readyToShowLoadingHtml = true; 150 | removeClass("pg-loading", _this._loadingHtmlElem); 151 | if (transitionSupport) { 152 | _this._loadingHtmlElem.removeEventListener(transitionEvent, _this._loadingHtmlListener); 153 | } 154 | if (_this._loadingHtmlToDisplay.length > 0) { 155 | return _this._changeLoadingHtml(); 156 | } 157 | }; 158 | })(this); 159 | this._removingHtmlListener = (function(_this) { 160 | return function() { 161 | _this._loadingHtmlElem.innerHTML = _this._loadingHtmlToDisplay.shift(); 162 | removeClass("pg-removing", _this._loadingHtmlElem); 163 | addClass("pg-loading", _this._loadingHtmlElem); 164 | if (transitionSupport) { 165 | _this._loadingHtmlElem.removeEventListener(transitionEvent, _this._removingHtmlListener); 166 | return _this._loadingHtmlElem.addEventListener(transitionEvent, _this._loadingHtmlListener); 167 | } else { 168 | return _this._loadingHtmlListener(); 169 | } 170 | }; 171 | })(this); 172 | } 173 | } 174 | 175 | PleaseWait.prototype.finish = function(immediately, onLoadedCallback) { 176 | if (immediately == null) { 177 | immediately = false; 178 | } 179 | if (window.document.hidden) { 180 | immediately = true; 181 | } 182 | this.finishing = true; 183 | if (onLoadedCallback != null) { 184 | this.updateOption('onLoadedCallback', onLoadedCallback); 185 | } 186 | if (this.loaded || immediately) { 187 | return this._finish(immediately); 188 | } 189 | }; 190 | 191 | PleaseWait.prototype.updateOption = function(option, value) { 192 | switch (option) { 193 | case 'backgroundColor': 194 | return this._loadingElem.style.backgroundColor = value; 195 | case 'logo': 196 | return this._logoElem.src = value; 197 | case 'loadingHtml': 198 | return this.updateLoadingHtml(value); 199 | case 'onLoadedCallback': 200 | return this._onLoadedCallback = value; 201 | default: 202 | throw new Error("Unknown option '" + option + "'"); 203 | } 204 | }; 205 | 206 | PleaseWait.prototype.updateOptions = function(options) { 207 | var k, v, _results; 208 | if (options == null) { 209 | options = {}; 210 | } 211 | _results = []; 212 | for (k in options) { 213 | v = options[k]; 214 | _results.push(this.updateOption(k, v)); 215 | } 216 | return _results; 217 | }; 218 | 219 | PleaseWait.prototype.updateLoadingHtml = function(loadingHtml, immediately) { 220 | if (immediately == null) { 221 | immediately = false; 222 | } 223 | if (this._loadingHtmlElem == null) { 224 | throw new Error("The loading template does not have an element of class 'pg-loading-html'"); 225 | } 226 | if (immediately) { 227 | this._loadingHtmlToDisplay = [loadingHtml]; 228 | this._readyToShowLoadingHtml = true; 229 | } else { 230 | this._loadingHtmlToDisplay.push(loadingHtml); 231 | } 232 | if (this._readyToShowLoadingHtml) { 233 | return this._changeLoadingHtml(); 234 | } 235 | }; 236 | 237 | PleaseWait.prototype._changeLoadingHtml = function() { 238 | this._readyToShowLoadingHtml = false; 239 | this._loadingHtmlElem.removeEventListener(transitionEvent, this._loadingHtmlListener); 240 | this._loadingHtmlElem.removeEventListener(transitionEvent, this._removingHtmlListener); 241 | removeClass("pg-loading", this._loadingHtmlElem); 242 | removeClass("pg-removing", this._loadingHtmlElem); 243 | if (transitionSupport) { 244 | addClass("pg-removing", this._loadingHtmlElem); 245 | return this._loadingHtmlElem.addEventListener(transitionEvent, this._removingHtmlListener); 246 | } else { 247 | return this._removingHtmlListener(); 248 | } 249 | }; 250 | 251 | PleaseWait.prototype._finish = function(immediately) { 252 | var listener; 253 | if (immediately == null) { 254 | immediately = false; 255 | } 256 | if (this._loadingElem == null) { 257 | return; 258 | } 259 | addClass("pg-loaded", document.body); 260 | if (typeof this._onLoadedCallback === "function") { 261 | this._onLoadedCallback.apply(this); 262 | } 263 | listener = (function(_this) { 264 | return function() { 265 | document.body.removeChild(_this._loadingElem); 266 | removeClass("pg-loading", document.body); 267 | if (animationSupport) { 268 | _this._loadingElem.removeEventListener(animationEvent, listener); 269 | } 270 | return _this._loadingElem = null; 271 | }; 272 | })(this); 273 | if (!immediately && animationSupport) { 274 | addClass("pg-loaded", this._loadingElem); 275 | return this._loadingElem.addEventListener(animationEvent, listener); 276 | } else { 277 | return listener(); 278 | } 279 | }; 280 | 281 | return PleaseWait; 282 | 283 | })(); 284 | pleaseWait = function(options) { 285 | if (options == null) { 286 | options = {}; 287 | } 288 | return new PleaseWait(options); 289 | }; 290 | exports.pleaseWait = pleaseWait; 291 | return pleaseWait; 292 | }); 293 | -------------------------------------------------------------------------------- /build/please-wait.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * please-wait 3 | * Display a nice loading screen while your app loads 4 | 5 | * @author Pathgather 6 | * @copyright Pathgather 2015 7 | * @license MIT 8 | * @link https://github.com/Pathgather/please-wait 9 | * @module please-wait 10 | * @version 0.0.5 11 | */ 12 | !function(a,b){"object"==typeof exports?b(exports):"function"==typeof define&&define.amd?define(["exports"],b):b(a)}(this,function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q;g=document.createElement("fakeelement"),e=!1,n=!1,d="animationend",m=null,f="Webkit Moz O ms".split(" "),l={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"};for(h in l)if(o=l[h],null!=g.style[h]){m=o,n=!0;break}if(null!=g.style.animationName&&(e=!0),!e)for(p=0,q=f.length;q>p;p++)if(i=f[p],null!=g.style[""+i+"AnimationName"]){switch(i){case"Webkit":d="webkitAnimationEnd";break;case"Moz":d="animationend";break;case"O":d="oanimationend";break;case"ms":d="MSAnimationEnd"}e=!0;break}return c=function(a,b){return b.classList?b.classList.add(a):b.className+=" "+a},k=function(a,b){return b.classList?b.classList.remove(a):b.className=b.className.replace(a,"").trim()},b=function(){function a(a){var b,f,g,h;b=this.constructor._defaultOptions,this.options={},this.loaded=!1,this.finishing=!1;for(f in b)h=b[f],this.options[f]=null!=a[f]?a[f]:h;this._loadingElem=document.createElement("div"),this._loadingHtmlToDisplay=[],this._loadingElem.className="pg-loading-screen",null!=this.options.backgroundColor&&(this._loadingElem.style.backgroundColor=this.options.backgroundColor),this._loadingElem.innerHTML=this.options.template,this._loadingHtmlElem=this._loadingElem.getElementsByClassName("pg-loading-html")[0],null!=this._loadingHtmlElem&&(this._loadingHtmlElem.innerHTML=this.options.loadingHtml),this._readyToShowLoadingHtml=!1,this._logoElem=this._loadingElem.getElementsByClassName("pg-loading-logo")[0],null!=this._logoElem&&(this._logoElem.src=this.options.logo),k("pg-loaded",document.body),c("pg-loading",document.body),document.body.appendChild(this._loadingElem),c("pg-loading",this._loadingElem),this._onLoadedCallback=this.options.onLoadedCallback,g=function(a){return function(b){return a.loaded=!0,a._readyToShowLoadingHtml=!0,c("pg-loaded",a._loadingHtmlElem),e&&a._loadingHtmlElem.removeEventListener(d,g),a._loadingHtmlToDisplay.length>0&&a._changeLoadingHtml(),a.finishing?(null!=b&&b.stopPropagation(),a._finish()):void 0}}(this),null!=this._loadingHtmlElem&&(e?this._loadingHtmlElem.addEventListener(d,g):g(),this._loadingHtmlListener=function(a){return function(){return a._readyToShowLoadingHtml=!0,k("pg-loading",a._loadingHtmlElem),n&&a._loadingHtmlElem.removeEventListener(m,a._loadingHtmlListener),a._loadingHtmlToDisplay.length>0?a._changeLoadingHtml():void 0}}(this),this._removingHtmlListener=function(a){return function(){return a._loadingHtmlElem.innerHTML=a._loadingHtmlToDisplay.shift(),k("pg-removing",a._loadingHtmlElem),c("pg-loading",a._loadingHtmlElem),n?(a._loadingHtmlElem.removeEventListener(m,a._removingHtmlListener),a._loadingHtmlElem.addEventListener(m,a._loadingHtmlListener)):a._loadingHtmlListener()}}(this))}return a._defaultOptions={backgroundColor:null,logo:null,loadingHtml:null,template:"
\n
\n
\n

\n \n

\n
\n
\n
\n
\n
",onLoadedCallback:null},a.prototype.finish=function(a,b){return null==a&&(a=!1),window.document.hidden&&(a=!0),this.finishing=!0,null!=b&&this.updateOption("onLoadedCallback",b),this.loaded||a?this._finish(a):void 0},a.prototype.updateOption=function(a,b){switch(a){case"backgroundColor":return this._loadingElem.style.backgroundColor=b;case"logo":return this._logoElem.src=b;case"loadingHtml":return this.updateLoadingHtml(b);case"onLoadedCallback":return this._onLoadedCallback=b;default:throw new Error("Unknown option '"+a+"'")}},a.prototype.updateOptions=function(a){var b,c,d;null==a&&(a={}),d=[];for(b in a)c=a[b],d.push(this.updateOption(b,c));return d},a.prototype.updateLoadingHtml=function(a,b){if(null==b&&(b=!1),null==this._loadingHtmlElem)throw new Error("The loading template does not have an element of class 'pg-loading-html'");return b?(this._loadingHtmlToDisplay=[a],this._readyToShowLoadingHtml=!0):this._loadingHtmlToDisplay.push(a),this._readyToShowLoadingHtml?this._changeLoadingHtml():void 0},a.prototype._changeLoadingHtml=function(){return this._readyToShowLoadingHtml=!1,this._loadingHtmlElem.removeEventListener(m,this._loadingHtmlListener),this._loadingHtmlElem.removeEventListener(m,this._removingHtmlListener),k("pg-loading",this._loadingHtmlElem),k("pg-removing",this._loadingHtmlElem),n?(c("pg-removing",this._loadingHtmlElem),this._loadingHtmlElem.addEventListener(m,this._removingHtmlListener)):this._removingHtmlListener()},a.prototype._finish=function(a){var b;return null==a&&(a=!1),null!=this._loadingElem?(c("pg-loaded",document.body),"function"==typeof this._onLoadedCallback&&this._onLoadedCallback.apply(this),b=function(a){return function(){return document.body.removeChild(a._loadingElem),k("pg-loading",document.body),e&&a._loadingElem.removeEventListener(d,b),a._loadingElem=null}}(this),!a&&e?(c("pg-loaded",this._loadingElem),this._loadingElem.addEventListener(d,b)):b()):void 0},a}(),j=function(a){return null==a&&(a={}),new b(a)},a.pleaseWait=j,j}); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "please-wait", 3 | "module": "please-wait", 4 | "author": "Pathgather", 5 | "description": "Display a nice loading screen while your app loads", 6 | "homepage": "https://github.com/Pathgather/please-wait", 7 | "author": { 8 | "name": "Pathgather", 9 | "email": "tech@pathgather.com" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/Pathgather/please-wait.git" 14 | }, 15 | "main": "build/please-wait.js", 16 | "version": "0.0.5", 17 | "devDependencies": { 18 | "grunt": "~0.4.5", 19 | "grunt-contrib-jshint": "~0.10.0", 20 | "grunt-contrib-uglify": "~0.5.0", 21 | "grunt-contrib-compass": "~1.0.1", 22 | "grunt-coffeelint": "~0.0.13", 23 | "grunt-contrib-coffee": "~0.12.0", 24 | "grunt-contrib-clean": "~0.6.0", 25 | "grunt-contrib-concat": "~0.5.0", 26 | "grunt-contrib-jasmine": "~0.8.1" 27 | }, 28 | "licenses": [ 29 | { 30 | "type": "MIT", 31 | "url": "http://opensource.org/licenses/mit-license.php" 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /spec/please-wait.spec.coffee: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe 'PleaseWait', -> 4 | getTransitionEvent = -> 5 | el = document.createElement('fakeelement') 6 | transitions = 7 | 'WebkitAnimation': 'webkitAnimationEnd', 8 | 'OAnimation': 'oAnimationEnd', 9 | 'msAnimation': 'MSAnimationEnd', 10 | 'MozAnimation': 'mozAnimationEnd' 11 | 'animation' : 'animationend' 12 | 13 | for key, val of transitions 14 | return val if el.style[key]? 15 | 16 | it "defines pleaseWait", -> 17 | expect(window.pleaseWait).toBeDefined() 18 | 19 | describe 'a new pleaseWait loading screen', -> 20 | originalHTML = null 21 | beforeEach () -> 22 | if !originalHTML? then originalHTML = document.body.innerHTML 23 | 24 | afterEach () -> 25 | # Reset the body to its original state before each run. We could call finish, but we'll test that below 26 | document.body.innerHTML = originalHTML 27 | 28 | describe "when using the default template", -> 29 | describe "when setting a logo", -> 30 | it "sets the logo", -> 31 | window.pleaseWait({logo: "logo.png"}) 32 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 33 | logo = addedScreen.getElementsByClassName("pg-loading-logo")[0] 34 | expect(logo.src).toContain("logo.png") 35 | 36 | describe "when setting loading HTML", -> 37 | it "adds the loading HTML", -> 38 | window.pleaseWait({loadingHtml: "
Spin!
"}) 39 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 40 | loadingHtml = addedScreen.getElementsByClassName("pg-loading-html")[0] 41 | expect(loadingHtml.innerHTML).toEqual("
Spin!
") 42 | 43 | describe "when using a custom template", -> 44 | it "adds the template to the body", -> 45 | window.pleaseWait({template: "
LOADING!
"}) 46 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 47 | expect(addedScreen.innerHTML).toEqual("
LOADING!
") 48 | 49 | describe "when the template has an img tag of class pg-loading-logo", -> 50 | it "sets the logo", -> 51 | window.pleaseWait({logo: "logo.png", template: "
"}) 52 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 53 | logo = addedScreen.getElementsByClassName("pg-loading-logo")[0] 54 | expect(logo.src).toContain("logo.png") 55 | 56 | describe "when the template has an element of class pg-loading-html", -> 57 | it "adds the loading HTML", -> 58 | window.pleaseWait({loadingHtml: "
Spin!
", template: "
"}) 59 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 60 | loadingHtml = addedScreen.getElementsByClassName("pg-loading-html")[0] 61 | expect(loadingHtml.innerHTML).toEqual("
Spin!
") 62 | 63 | describe "when specifying a background color", -> 64 | it "sets the loading screen's background color", -> 65 | window.pleaseWait({logo: 'logo.png', loadingHtml: "
", backgroundColor: "#CCCCCC"}) 66 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 67 | expect(addedScreen.style.backgroundColor).toEqual("rgb(204, 204, 204)") 68 | 69 | it "removes any existing pg-loaded classes from the body", -> 70 | document.body.className = "pg-loaded" 71 | window.pleaseWait() 72 | expect(document.body.className).toEqual("pg-loading") 73 | 74 | describe 'finish', -> 75 | loadingScreen = addedScreen = loadingHtml = onLoaded = null 76 | beforeEach -> 77 | onLoaded = jasmine.createSpy('onLoaded') 78 | loadingScreen = window.pleaseWait({logo: 'logo.png', loadingHtml: "
", onLoadedCallback: onLoaded}) 79 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 80 | loadingHtml = document.body.getElementsByClassName("pg-loading-html")[0] 81 | expect(addedScreen).toBeDefined() 82 | 83 | describe "when the loading screen has finished animating in", -> 84 | beforeEach -> 85 | event = document.createEvent('Event') 86 | event.initEvent(getTransitionEvent(), true, true) 87 | loadingHtml.dispatchEvent event 88 | expect(onLoaded).not.toHaveBeenCalled() 89 | 90 | it "removes the loading screen from the body after it transitions out", -> 91 | loadingScreen.finish() 92 | expect(onLoaded).toHaveBeenCalled() 93 | event = document.createEvent('Event') 94 | event.initEvent(getTransitionEvent(), true, true) 95 | addedScreen.dispatchEvent event 96 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 97 | expect(addedScreen).not.toBeDefined() 98 | 99 | describe "when the loading screen has not yet finished animating in", -> 100 | it "waits for the current animation to finish, then removes the loading screen from the body after it transitions out", -> 101 | loadingScreen.finish() 102 | 103 | # Make sure that animation events on the loading screen do not dismiss yet 104 | event = document.createEvent('Event') 105 | event.initEvent(getTransitionEvent(), true, true) 106 | addedScreen.dispatchEvent event 107 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 108 | expect(addedScreen).toBeDefined() 109 | 110 | # Finish loading in animation 111 | expect(onLoaded).not.toHaveBeenCalled() 112 | event = document.createEvent('Event') 113 | event.initEvent(getTransitionEvent(), true, true) 114 | loadingHtml.dispatchEvent event 115 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 116 | expect(addedScreen).toBeDefined() 117 | expect(onLoaded).toHaveBeenCalled() 118 | 119 | # Now, finish loading out animation and ensure the loading screen is dismissed 120 | event = document.createEvent('Event') 121 | event.initEvent(getTransitionEvent(), true, true) 122 | addedScreen.dispatchEvent event 123 | addedScreen = document.body.getElementsByClassName("pg-loading-screen")[0] 124 | expect(addedScreen).not.toBeDefined() 125 | 126 | describe 'when reloading multiple times', -> 127 | it "adds and removes pg-loaded & pg-loading from the body accordingly", -> 128 | document.body.className = "my-class" 129 | first = window.pleaseWait() 130 | expect(document.body.className).toEqual("my-class pg-loading") 131 | first.finish(true) 132 | expect(document.body.className).toEqual("my-class pg-loaded") 133 | second = window.pleaseWait() 134 | expect(document.body.className).toEqual("my-class pg-loading") 135 | second.finish(true) 136 | expect(document.body.className).toEqual("my-class pg-loaded") 137 | -------------------------------------------------------------------------------- /src/please-wait.coffee: -------------------------------------------------------------------------------- 1 | ((root, factory) -> 2 | if typeof exports is "object" 3 | # CommonJS 4 | factory exports 5 | else if typeof define is "function" and define.amd 6 | # AMD. Register as an anonymous module. 7 | define ["exports"], factory 8 | else 9 | # Browser globals 10 | factory root 11 | return 12 | ) this, (exports) -> 13 | elm = document.createElement('fakeelement') 14 | animationSupport = false 15 | transitionSupport = false 16 | animationEvent = 'animationend' 17 | transitionEvent = null 18 | domPrefixes = 'Webkit Moz O ms'.split(' ') 19 | transEndEventNames = 20 | 'WebkitTransition' : 'webkitTransitionEnd' 21 | 'MozTransition' : 'transitionend' 22 | 'OTransition' : 'oTransitionEnd' 23 | 'msTransition' : 'MSTransitionEnd' 24 | 'transition' : 'transitionend' 25 | 26 | for key, val of transEndEventNames 27 | if elm.style[key]? 28 | transitionEvent = val 29 | transitionSupport = true 30 | break 31 | 32 | if elm.style.animationName? then animationSupport = true 33 | 34 | if !animationSupport 35 | for pfx in domPrefixes 36 | if elm.style["#{pfx}AnimationName"]? 37 | switch pfx 38 | when 'Webkit' 39 | animationEvent = 'webkitAnimationEnd' 40 | when 'Moz' 41 | animationEvent = 'animationend' 42 | when 'O' 43 | animationEvent = 'oanimationend' 44 | when 'ms' 45 | animationEvent = 'MSAnimationEnd' 46 | animationSupport = true 47 | break 48 | 49 | # Helpers to add/remove classes, since we don't have our friend jQuery 50 | addClass = (classname, elem) -> 51 | if elem.classList 52 | elem.classList.add(classname) 53 | else 54 | elem.className += " #{classname}" 55 | 56 | removeClass = (classname, elem) -> 57 | if elem.classList 58 | elem.classList.remove(classname) 59 | else 60 | elem.className = elem.className.replace(classname, "").trim() 61 | 62 | class PleaseWait 63 | @_defaultOptions: 64 | backgroundColor: null 65 | logo: null 66 | loadingHtml: null 67 | template: """ 68 |
69 |
70 |
71 |

72 | 73 |

74 |
75 |
76 |
77 |
78 |
79 | """ 80 | onLoadedCallback: null 81 | 82 | constructor: (options) -> 83 | defaultOptions = @constructor._defaultOptions 84 | @options = {} 85 | @loaded = false 86 | @finishing = false 87 | 88 | # Set initial options, merging given options with the defaults 89 | for k, v of defaultOptions 90 | @options[k] = if options[k]? then options[k] else v 91 | 92 | # Create the loading screen element 93 | @_loadingElem = document.createElement("div") 94 | # Create an empty array to store the potential list of loading HTML (messages, spinners, etc) 95 | # we'll be displaying to the screen 96 | @_loadingHtmlToDisplay = [] 97 | # Add a global class for easy styling 98 | @_loadingElem.className = "pg-loading-screen" 99 | # Set the background color of the loading screen, if supplied 100 | @_loadingElem.style.backgroundColor = @options.backgroundColor if @options.backgroundColor? 101 | # Initialize the loading screen's HTML with the defined template. The default can be overwritten via options 102 | @_loadingElem.innerHTML = @options.template 103 | # Find the element that will contain the loading HTML displayed to the user (typically a spinner/message) 104 | # This can be changed via updateLoadingHtml 105 | @_loadingHtmlElem = @_loadingElem.getElementsByClassName("pg-loading-html")[0] 106 | # Set the initial loading HTML, if supplied 107 | @_loadingHtmlElem.innerHTML = @options.loadingHtml if @_loadingHtmlElem? 108 | # Set a flag that lets us know if the transitioning between loading HTML elements is finished. 109 | # If true, we can transition immediately to a new message/HTML 110 | @_readyToShowLoadingHtml = false 111 | # Find the element that displays the loading logo and set the src if supplied 112 | @_logoElem = @_loadingElem.getElementsByClassName("pg-loading-logo")[0] 113 | @_logoElem.src = @options.logo if @_logoElem? 114 | # Add the loading screen to the body 115 | removeClass("pg-loaded", document.body) 116 | addClass("pg-loading", document.body) 117 | document.body.appendChild(@_loadingElem) 118 | # Add the CSS class that will trigger the initial transitions of the logo/loading HTML 119 | addClass("pg-loading", @_loadingElem) 120 | # Register a callback to invoke when the loading screen is finished 121 | @_onLoadedCallback = @options.onLoadedCallback 122 | 123 | # Define a listener to look for any new loading HTML that needs to be displayed after the intiial transition finishes 124 | listener = (evt) => 125 | @loaded = true 126 | @_readyToShowLoadingHtml = true 127 | addClass("pg-loaded", @_loadingHtmlElem) 128 | if animationSupport then @_loadingHtmlElem.removeEventListener(animationEvent, listener) 129 | if @_loadingHtmlToDisplay.length > 0 then @_changeLoadingHtml() 130 | if @finishing 131 | # If we reach here, it means @finish() was called while we were animating in, so we should 132 | # call @_finish() immediately. This registers a new event listener, which will fire 133 | # immediately, instead of waiting for the *next* animation to end. We stop propagation now 134 | # to prevent this conflict 135 | evt?.stopPropagation() 136 | @_finish() 137 | 138 | if @_loadingHtmlElem? 139 | # Detect CSS animation support. If not found, we'll call the listener immediately. Otherwise, we'll wait 140 | if animationSupport 141 | @_loadingHtmlElem.addEventListener(animationEvent, listener) 142 | else 143 | listener() 144 | 145 | # Define listeners for the transtioning out and in of new loading HTML/messages 146 | @_loadingHtmlListener = => 147 | # New loading HTML has fully transitioned in. We're now ready to show a new message/HTML 148 | @_readyToShowLoadingHtml = true 149 | # Remove the CSS class that triggered the fade in animation 150 | removeClass("pg-loading", @_loadingHtmlElem) 151 | if transitionSupport then @_loadingHtmlElem.removeEventListener(transitionEvent, @_loadingHtmlListener) 152 | # Check if there's still HTML left in the queue to display. If so, let's show it 153 | if @_loadingHtmlToDisplay.length > 0 then @_changeLoadingHtml() 154 | 155 | @_removingHtmlListener = => 156 | # Last loading HTML to display has fully transitioned out. Time to transition the new in 157 | @_loadingHtmlElem.innerHTML = @_loadingHtmlToDisplay.shift() 158 | # Add the CSS class to trigger the fade in animation 159 | removeClass("pg-removing", @_loadingHtmlElem) 160 | addClass("pg-loading", @_loadingHtmlElem) 161 | if transitionSupport 162 | @_loadingHtmlElem.removeEventListener(transitionEvent, @_removingHtmlListener) 163 | @_loadingHtmlElem.addEventListener(transitionEvent, @_loadingHtmlListener) 164 | else 165 | @_loadingHtmlListener() 166 | 167 | finish: (immediately = false, onLoadedCallback) -> 168 | # Our nice CSS animations won't run until the window is visible. This is a problem when the 169 | # site is loading in a background tab, since the loading screen won't animate out until the 170 | # window regains focus, which makes it look like the site takes forever to load! On browsers 171 | # that support it (IE10+), use the visibility API to immediately hide the loading screen if 172 | # the window is hidden 173 | if window.document.hidden then immediately = true 174 | 175 | # NOTE: if @loaded is false, the screen is still initializing. In that case, set @finishing to 176 | # true and let the existing listener handle calling @_finish for us. Otherwise, we can call 177 | # @_finish now to start the dismiss animation 178 | @finishing = true 179 | if onLoadedCallback? then @updateOption('onLoadedCallback', onLoadedCallback) 180 | if @loaded || immediately 181 | # Screen has fully initialized, so we are ready to close 182 | @_finish(immediately) 183 | 184 | updateOption: (option, value) -> 185 | switch option 186 | when 'backgroundColor' 187 | @_loadingElem.style.backgroundColor = value 188 | when 'logo' 189 | @_logoElem.src = value 190 | when 'loadingHtml' 191 | @updateLoadingHtml(value) 192 | when 'onLoadedCallback' 193 | @_onLoadedCallback = value 194 | else 195 | throw new Error("Unknown option '#{option}'") 196 | 197 | updateOptions: (options={}) -> 198 | for k, v of options 199 | @updateOption(k, v) 200 | 201 | updateLoadingHtml: (loadingHtml, immediately=false) -> 202 | unless @_loadingHtmlElem? then throw new Error("The loading template does not have an element of class 'pg-loading-html'") 203 | if immediately 204 | # Ignore any loading HTML that may be queued up. Show this immediately 205 | @_loadingHtmlToDisplay = [loadingHtml] 206 | @_readyToShowLoadingHtml = true 207 | else 208 | # Add to an array of HTML to display to the user 209 | @_loadingHtmlToDisplay.push(loadingHtml) 210 | # If ready, let's display the new loading HTML 211 | if @_readyToShowLoadingHtml then @_changeLoadingHtml() 212 | 213 | # Private method to immediately change the loading HTML displayed 214 | _changeLoadingHtml: -> 215 | @_readyToShowLoadingHtml = false 216 | # Remove any old event listeners that may still be attached to the DOM 217 | @_loadingHtmlElem.removeEventListener(transitionEvent, @_loadingHtmlListener) 218 | @_loadingHtmlElem.removeEventListener(transitionEvent, @_removingHtmlListener) 219 | # Remove any old CSS transition classes that may still be on the element 220 | removeClass("pg-loading", @_loadingHtmlElem) 221 | removeClass("pg-removing", @_loadingHtmlElem) 222 | 223 | if transitionSupport 224 | # Add the CSS class that will cause the HTML to fade out 225 | addClass("pg-removing", @_loadingHtmlElem) 226 | @_loadingHtmlElem.addEventListener(transitionEvent, @_removingHtmlListener) 227 | else 228 | @_removingHtmlListener() 229 | 230 | _finish: (immediately = false) -> 231 | return unless @_loadingElem? 232 | # Add a class to the body to signal that the loading screen has finished and the app is ready. 233 | # We do this here so that the user can display their HTML behind PleaseWait before it is 234 | # fully transitioned out. Otherwise, the HTML flashes oddly, since there's a brief moment 235 | # of time where there is no loading screen and no HTML 236 | addClass("pg-loaded", document.body) 237 | if typeof @_onLoadedCallback == "function" then @_onLoadedCallback.apply(this) 238 | 239 | # Again, define a listener to run once the loading screen has fully transitioned out 240 | listener = => 241 | # Remove the loading screen from the body 242 | document.body.removeChild(@_loadingElem) 243 | # Remove the pg-loading class since we're done here 244 | removeClass("pg-loading", document.body) 245 | if animationSupport then @_loadingElem.removeEventListener(animationEvent, listener) 246 | # Reset the loading screen element since it's no longer attached to the DOM 247 | @_loadingElem = null 248 | 249 | # Detect CSS animation support. If not found, we'll call the listener immediately. Otherwise, we'll wait 250 | if !immediately && animationSupport 251 | # Set a class on the loading screen to trigger a fadeout animation 252 | addClass("pg-loaded", @_loadingElem) 253 | # When the loading screen is finished fading out, we'll remove it from the DOM 254 | @_loadingElem.addEventListener(animationEvent, listener) 255 | else 256 | listener() 257 | 258 | pleaseWait = (options = {}) -> 259 | new PleaseWait(options) 260 | 261 | exports.pleaseWait = pleaseWait 262 | return pleaseWait 263 | -------------------------------------------------------------------------------- /src/please-wait.scss: -------------------------------------------------------------------------------- 1 | @mixin prefixed($property, $value, $second:false) { 2 | @if $second { 3 | -webkit-#{$property}: $value, $second; 4 | -moz-#{$property}: $value, $second; 5 | -ms-#{$property}: $value, $second; 6 | -o-#{$property}: $value, $second; 7 | #{$property}: $value, $second; 8 | } @else { 9 | -webkit-#{$property}: $value; 10 | -moz-#{$property}: $value; 11 | -ms-#{$property}: $value; 12 | -o-#{$property}: $value; 13 | #{$property}: $value; 14 | } 15 | } 16 | 17 | body.pg-loading { 18 | overflow: hidden; 19 | } 20 | 21 | .pg-loading-screen { 22 | position: fixed; 23 | bottom: 0; 24 | left: 0; 25 | right: 0; 26 | top: 0; 27 | z-index: 1000000; 28 | opacity: 1; 29 | background-color: #FFF; 30 | @include prefixed(transition, background-color 0.4s ease-in-out 0s); 31 | 32 | &.pg-loaded { 33 | opacity: 0; 34 | @include prefixed(animation, pgAnimLoaded 0.5s cubic-bezier(0.7,0,0.3,1) both); 35 | } 36 | 37 | &.pg-loading { 38 | .pg-loading-logo-header, .pg-loading-html { 39 | opacity: 1; 40 | } 41 | 42 | .pg-loading-logo-header, .pg-loading-html:not(.pg-loaded) { 43 | @include prefixed(animation, pgAnimLoading 1s cubic-bezier(0.7,0,0.3,1) both); 44 | } 45 | 46 | .pg-loading-html:not(.pg-loaded) { 47 | @include prefixed(animation-delay, 0.3s); 48 | } 49 | } 50 | 51 | .pg-loading-inner { 52 | height: 100%; 53 | width: 100%; 54 | margin: 0; 55 | padding: 0; 56 | position: static; 57 | } 58 | 59 | .pg-loading-center-outer { 60 | width: 100%; 61 | padding: 0; 62 | display: table !important; 63 | height: 100%; 64 | position: absolute; 65 | top: 0; 66 | left: 0; 67 | margin: 0; 68 | } 69 | 70 | .pg-loading-center-middle { 71 | padding: 0; 72 | vertical-align: middle; 73 | display: table-cell !important; 74 | margin: 0; 75 | text-align: center; 76 | } 77 | 78 | .pg-loading-logo-header, .pg-loading-html { 79 | width: 100%; 80 | opacity: 0; 81 | } 82 | 83 | .pg-loading-logo-header { 84 | text-align: center; 85 | 86 | img { 87 | display: inline-block !important; 88 | } 89 | } 90 | 91 | .pg-loading-html { 92 | margin-top: 90px; 93 | 94 | &.pg-loaded { 95 | @include prefixed(transition, opacity 0.5s cubic-bezier(0.7,0,0.3,1)); 96 | 97 | &.pg-removing { 98 | opacity: 0; 99 | } 100 | 101 | &.pg-loading { 102 | opacity: 1; 103 | } 104 | } 105 | } 106 | } 107 | 108 | @-webkit-keyframes pgAnimLoading { 109 | from { 110 | opacity: 0; 111 | } 112 | } 113 | @-moz-keyframes pgAnimLoading { 114 | from { 115 | opacity: 0; 116 | } 117 | } 118 | @-o-keyframes pgAnimLoading { 119 | from { 120 | opacity: 0; 121 | } 122 | } 123 | @-ms-keyframes pgAnimLoading { 124 | from { 125 | opacity: 0; 126 | } 127 | } 128 | @keyframes pgAnimLoading { 129 | from { 130 | opacity: 0; 131 | } 132 | } 133 | 134 | @-webkit-keyframes pgAnimLoaded { 135 | from { 136 | opacity: 1; 137 | } 138 | } 139 | @-moz-keyframes pgAnimLoaded { 140 | from { 141 | opacity: 1; 142 | } 143 | } 144 | @-o-keyframes pgAnimLoaded { 145 | from { 146 | opacity: 1; 147 | } 148 | } 149 | @-ms-keyframes pgAnimLoaded { 150 | from { 151 | opacity: 1; 152 | } 153 | } 154 | @keyframes pgAnimLoaded { 155 | from { 156 | opacity: 1; 157 | } 158 | } 159 | --------------------------------------------------------------------------------