├── .editorconfig ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Examples ├── advancedUsage.html └── basicUsage.html ├── LICENSE ├── README.md ├── karma.conf.js ├── package.json ├── src ├── Config │ └── UsSpinnerConfig.ts ├── Constants │ └── SpinJSSpinner.ts ├── Directives │ └── AngularSpinner.ts ├── Interfaces │ ├── IUsSpinnerAttributes.d.ts │ ├── IUsSpinnerConfig.d.ts │ ├── IUsSpinnerScope.d.ts │ └── IUsSpinnerService.d.ts ├── Services │ └── UsSpinnerService.ts └── angular-spinner.ts ├── test ├── Config │ └── UsSpinnerConfig.test.ts ├── Directives │ └── AngularSpinner.test.ts └── index.ts ├── tsconfig.json ├── webpack.config.js └── webpack.production.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | 9 | # Change these settings to your own preference 10 | indent_style = tab 11 | indent_size = 4 12 | 13 | # We recommend you to keep these unchanged 14 | end_of_line = lf 15 | charset = utf-8 16 | trim_trailing_whitespace = true 17 | insert_final_newline = true 18 | 19 | [*.md] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules 3 | coverage 4 | .history 5 | .vscode 6 | dist -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | sudo: false 3 | node_js: 4 | - 6.9.1 5 | install: 6 | - npm install 7 | script: 8 | - npm test 9 | after_success: 10 | - cat ./coverage/*/lcov.info | ./node_modules/coveralls/bin/coveralls.js 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.0 - 2017-01-23 4 | - Breaking changes: Refactored the project to be written with TypeScript, contributed by [Attrash-Islam](https://github.com/Attrash-Islam) 5 | 6 | ## 0.8.1 - 2016-02-16 7 | - Bugfix: Default options overwriting ([#81](https://github.com/urish/angular-spinner/pull/81), contributed by [dmytroyarmak](https://github.com/dmytroyarmak)) 8 | 9 | ## 0.8.0 - 2015-10-29 10 | - Improve UMD (Universal Module Definition) code, fixes ([#61](https://github.com/urish/angular-spinner/issues/61)) 11 | - Theme support ([#66](https://github.com/urish/angular-spinner/pull/66), contributed by [marknadig](https://github.com/marknadig)) 12 | - Add `spinner-on` attribute ([#71](https://github.com/urish/angular-spinner/pull/71), contributed by [marknadig](https://github.com/marknadig)) 13 | 14 | ## 0.7.0 - 2015-09-09 15 | - Add CommonJS support, improve AMD support (for use with browserify, webpack, SystemJS, etc.) 16 | 17 | ## 0.6.2 - 2015-07-02 18 | - Relax Angular's dependency version lock ([#52](https://github.com/urish/angular-spinner/pull/52), contributed by [gottfrois](https://github.com/gottfrois)) 19 | 20 | ## 0.6.1 - 2015-01-06 21 | - Removed NBSP characters from source code ([#40](https://github.com/urish/angular-spinner/pull/40), contributed by [amolghotankar](https://github.com/amolghotankar)) 22 | - Return the created AngularJS module ([#37](https://github.com/urish/angular-spinner/pull/37), contributed by [k7sleeper](https://github.com/k7sleeper)) 23 | 24 | ## 0.6.0 - 2014-12-12 25 | - Added configurable default options ([#31](https://github.com/urish/angular-spinner/pull/31), contributed by [aleksih](https://github.com/aleksih)) 26 | - Added scope eval to allow for data binding support ([#21](https://github.com/urish/angular-spinner/pull/21), contributed by [jdamick](https://github.com/jdamick)) 27 | 28 | ## 0.5.1 - 2014-08-09 29 | - AMD / Require.js compatibility ([#11](https://github.com/urish/angular-spinner/pull/11), contributed by [floribon](https://github.com/floribon)) 30 | - Bugfix: Stop events are ignored if sent before the directive is fully initialized and `startActive` is true ([#22](https://github.com/urish/angular-spinner/pull/22), contributed by [vleborgne](https://github.com/vleborgne)) 31 | 32 | ## 0.5.0 - 2014-06-03 33 | 34 | - Add support for expressions in attributes ([#12](https://github.com/urish/angular-spinner/pull/12), contributed by [aaronroberson](https://github.com/aaronroberson)) 35 | - Generate source map for the minified version ([#14](https://github.com/urish/angular-spinner/issues/14)) 36 | - Add a `main` field to package.json ([#15](https://github.com/urish/angular-spinner/pull/15), contributed by [elfreyshira](https://github.com/elfreyshira)) 37 | - Enable support for AngularJS 1.3.x in bower.json 38 | 39 | ## 0.4.0 - 2014-03-15 40 | 41 | - Upgrade spin.js to 2.0.0. See breaking changes [here](http://fgnass.github.io/spin.js/#v2.0.0). 42 | 43 | ## 0.3.1 - 2014-01-31 44 | 45 | - Fixed an issue that caused the minified code to fail. 46 | 47 | ## 0.3.0 - 2014-01-26 48 | 49 | - Add ability to control spinner state with bundled service (([#6](https://github.com/urish/angular-spinner/pull/6), contributed by [lossendae](https://github.com/lossendae)) 50 | 51 | ## 0.2.1 - 2013-08-28 52 | 53 | - Add test coverage reporting 54 | - Stop the spinner on scope destroy 55 | - Support for AngularJS 1.2 56 | -------------------------------------------------------------------------------- /Examples/advancedUsage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

Hello Spinner!

7 | 8 | 9 |
Spinner active: {{spinneractive}}
Started: {{startcounter}} times
10 | 11 | 12 | 13 | 14 | 15 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Examples/basicUsage.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 |
11 | 12 | 13 | 14 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2017 Uri Shaked and contributors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # angular-spinner 2 | 3 | Angular directive to show an animated spinner (using [spin.js](http://fgnass.github.io/spin.js/)) 4 | 5 | Copyright (C) 2013, 2014, 2015, 2016, 2017 Uri Shaked, Islam Attrash and contributors 6 | 7 | [![Build Status](https://travis-ci.org/urish/angular-spinner.png?branch=master)](https://travis-ci.org/urish/angular-spinner) 8 | [![Coverage Status](https://coveralls.io/repos/urish/angular-spinner/badge.png)](https://coveralls.io/r/urish/angular-spinner) 9 | 10 | 11 | ## Usage 12 | 13 | Get angular-spinner 14 | 15 | - via npm: by running ``` $ npm install angular-spinner ``` from your console 16 | - via bower: by running ``` $ bower install angular-spinner ``` from your console 17 | 18 | Include angular-spinner.js in your application. 19 | 20 | ```js 21 | import 'angular-spinner'; 22 | 23 | OR: 24 | 25 | require('angular-spinner'); 26 | ``` 27 | 28 | OR by picking one of the following file (depends on the package manager): 29 | 30 | ```html 31 | 32 | 33 | ``` 34 | 35 | Add the module `angularSpinner` as a dependency to your app module: 36 | 37 | ```js 38 | var myapp = angular.module('myapp', ['angularSpinner']); 39 | ``` 40 | 41 | You can now start using the us-spinner directive to display an animated 42 | spinner. For example : 43 | 44 | ```html 45 | 46 | ``` 47 | 48 | You can also pass spinner options, for example: 49 | 50 | ```html 51 | 52 | ``` 53 | 54 | Possible configuration options are described in the [spin.js homepage](http://fgnass.github.io/spin.js/). 55 | 56 | You can direct the spinner to start and stop based on a scope expression, for example: 57 | 58 | ```html 59 | 60 | ``` 61 | 62 | 63 | ### Configuring default spinner options 64 | 65 | You can use `usSpinnerConfigProvider` to configure default options for all spinners globally. Any options passed from a directive still override these. 66 | 67 | ```js 68 | myapp.config(['usSpinnerConfigProvider', function (usSpinnerConfigProvider) { 69 | usSpinnerConfigProvider.setDefaults({color: 'blue'}); 70 | }]); 71 | ``` 72 | 73 | ## Themes 74 | 75 | Themes provide named default options for spinners. Any options passed from a directive still override these. 76 | 77 | ```js 78 | myapp.config(['usSpinnerConfigProvider', function (usSpinnerConfigProvider) { 79 | usSpinnerConfigProvider.setTheme('bigBlue', {color: 'blue', radius: 20}); 80 | usSpinnerConfigProvider.setTheme('smallRed', {color: 'red', radius: 6}); 81 | }]); 82 | ``` 83 | 84 | ```html 85 | 86 | ``` 87 | 88 | ### Using the usSpinnerService to control spinners 89 | 90 | ```html 91 | 92 | 93 | 94 | 95 | ``` 96 | 97 | The `usSpinnerService` service let you control spin start and stop by key. 98 | Whenever the key is not specified all the spinner will be affected (Start/Stop all spinners): 99 | 100 | ```js 101 | app.controller('MyController', ['$scope', 'usSpinnerService', function($scope, usSpinnerService){ 102 | $scope.startSpin = function(){ 103 | usSpinnerService.spin('spinner-1'); 104 | } 105 | $scope.stopSpin = function(){ 106 | usSpinnerService.stop('spinner-1'); 107 | } 108 | }]); 109 | ``` 110 | 111 | Note that when you specify a key, the spinner is rendered inactive. 112 | You can still render the spinner as active with the spinner-start-active parameter : 113 | ```html 114 | 115 | ``` 116 | 117 | spinner-start-active is ignored if spinner-on is specified. 118 | 119 | The spinner-key will be used as an identifier (not unique) allowing you to have several spinners controlled by the same key : 120 | 121 | ```html 122 | 123 | 124 | 125 | ... random html code ... 126 | 127 | 128 | 129 | ``` 130 | 131 | ### Example 132 | 133 | See [online example on Plunker](http://plnkr.co/edit/OUJTJbtG2F0VUvnIk1dv?p=preview). 134 | 135 | ## License 136 | 137 | Released under the terms of MIT License. 138 | 139 | ## Contributing 140 | 141 | 1. Fork repo. 142 | 2. `npm i` 143 | 3. Make your changes, add your tests. 144 | 4. `npm run test` 145 | 5. `npm run build` once all tests are passing. Commit, push, PR. 146 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | /* License: MIT. 2 | * Copyright (C) 2013, 2014, Uri Shaked and contributors. 3 | */ 4 | 5 | 'use strict'; 6 | 7 | var webpackConf = require('./webpack.config.js'); 8 | 9 | webpackConf.entry = {}; 10 | webpackConf.module.postLoaders = [ 11 | { 12 | test: /\.ts$/, 13 | loader: 'istanbul-instrumenter-loader', 14 | exclude: [ 15 | 'node_modules', 16 | /test/ 17 | ] 18 | } 19 | ]; 20 | 21 | module.exports = function (config) { 22 | config.set({ 23 | basePath: '', 24 | frameworks: ['jasmine', 'source-map-support'], 25 | logLevel: config.LOG_INFO, 26 | browsers: ['PhantomJS'], 27 | singleRun: true, 28 | reporters: ['dots', 'coverage'], 29 | files: [ 30 | 'node_modules/angular/angular.js', 31 | 'node_modules/angular-mocks/angular-mocks.js', 32 | 'src/angular-spinner.ts', 33 | 'test/index.ts' 34 | ], 35 | webpack: webpackConf, 36 | preprocessors: { 37 | 'src/angular-spinner.ts': ['webpack'], 38 | 'test/index.ts': ['webpack'] 39 | }, 40 | coverageReporter: { 41 | type: 'lcov', 42 | dir: 'coverage/' 43 | }, 44 | mime: { 45 | 'text/x-typescript': ['ts'] 46 | } 47 | }); 48 | }; 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-spinner", 3 | "version": "1.0.1", 4 | "repository": { 5 | "type": "git", 6 | "url": "http://github.com/urish/angular-spinner.git" 7 | }, 8 | "main": "./dist/angular-spinner.js", 9 | "dependencies": { 10 | "spin.js": "2.3.2" 11 | }, 12 | "scripts": { 13 | "clean": "rimraf ./dist", 14 | "build": "npm run clean && npm run build:browser && npm run build:browser:debug", 15 | "build:browser": "webpack ./src/angular-spinner.ts ./dist/angular-spinner.min.js --output-library-target=\"umd\" -p --config webpack.production.config.js", 16 | "build:browser:debug": "webpack ./src/angular-spinner.ts ./dist/angular-spinner.js --output-library-target=\"umd\" -d", 17 | "prepublish": "npm run build", 18 | "test": "karma start karma.conf.js" 19 | }, 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@types/angular": "1.6.1", 23 | "@types/angular-mocks": "1.5.8", 24 | "@types/jasmine": "2.5.40", 25 | "@types/jquery": "2.0.39", 26 | "@types/spin.js": "2.3.0", 27 | "angular": "1.6.1", 28 | "angular-mocks": "1.6.1", 29 | "coveralls": "2.11.15", 30 | "istanbul-instrumenter-loader": "1.0.0", 31 | "jasmine": "2.5.3", 32 | "karma": "1.3.0", 33 | "karma-coverage": "1.1.1", 34 | "karma-jasmine": "1.1.0", 35 | "karma-phantomjs-launcher": "1.0.2", 36 | "karma-source-map-support": "1.2.0", 37 | "karma-sourcemap-loader": "0.3.7", 38 | "karma-webpack": "2.0.1", 39 | "rimraf": "2.5.4", 40 | "ts-loader": "1.3.3", 41 | "typescript": "2.1.5", 42 | "webpack": "1.14.0" 43 | }, 44 | "engines": { 45 | "node": ">=0.10.0" 46 | }, 47 | "files": [ 48 | "dist/" 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /src/Config/UsSpinnerConfig.ts: -------------------------------------------------------------------------------- 1 | import { IUsSpinnerConfig } from '../Interfaces/IUsSpinnerConfig'; 2 | 3 | /** 4 | * UsSpinnerConfig 5 | */ 6 | export class UsSpinnerConfig implements ng.IServiceProvider, IUsSpinnerConfig { 7 | 8 | config:SpinnerOptions; 9 | themes: { 10 | [name: string]: SpinnerOptions; 11 | } 12 | 13 | constructor() { 14 | this.config = {}; 15 | this.themes = {}; 16 | } 17 | 18 | setDefaults(config:SpinnerOptions) { 19 | this.config = config || this.config; 20 | } 21 | 22 | setTheme(name:string, config:SpinnerOptions) { 23 | this.themes[name] = config; 24 | } 25 | 26 | $get () { 27 | let { config, themes } = this; 28 | 29 | return { 30 | config, 31 | themes 32 | }; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/Constants/SpinJSSpinner.ts: -------------------------------------------------------------------------------- 1 | import Spinner = require('spin.js'); 2 | 3 | /** 4 | * Exporting the Spinner prototype from spin.js library 5 | */ 6 | export const SpinJSSpinner = Spinner; 7 | -------------------------------------------------------------------------------- /src/Directives/AngularSpinner.ts: -------------------------------------------------------------------------------- 1 | import { IUsSpinnerConfig } from '../Interfaces/IUsSpinnerConfig'; 2 | import { IUsSpinnerAttributes } from '../Interfaces/IUsSpinnerAttributes'; 3 | import { IUsSpinnerScope } from '../Interfaces/IUsSpinnerScope'; 4 | import * as angular from 'angular'; 5 | 6 | export const usSpinner = (SpinJSSpinner:typeof Spinner, usSpinnerConfig:IUsSpinnerConfig) => { 7 | 8 | return { 9 | scope: true, 10 | link: (scope:IUsSpinnerScope, element:ng.IAugmentedJQuery, attr:IUsSpinnerAttributes) => { 11 | scope.spinner = null; 12 | 13 | scope.key = angular.isDefined(attr.spinnerKey) ? attr.spinnerKey : false; 14 | 15 | scope.startActive = (attr.spinnerStartActive) ? 16 | scope.$eval(attr.spinnerStartActive) : scope.key ? 17 | false : true; 18 | 19 | function stopSpinner() { 20 | if (scope.spinner) { 21 | scope.spinner.stop(); 22 | } 23 | } 24 | 25 | scope.spin = () => { 26 | if (scope.spinner) { 27 | scope.spinner.spin(element[0]); 28 | } 29 | }; 30 | 31 | scope.stop = () => { 32 | scope.startActive = false; 33 | stopSpinner(); 34 | }; 35 | 36 | scope.$watch(attr.usSpinner, (options:SpinnerOptions) => { 37 | stopSpinner(); 38 | 39 | // order of precedence: element options, theme, defaults. 40 | options = angular.extend( 41 | {}, 42 | usSpinnerConfig.config, 43 | attr.spinnerTheme ? usSpinnerConfig.themes[attr.spinnerTheme] : undefined, 44 | options); 45 | 46 | scope.spinner = new SpinJSSpinner(options); 47 | if ((!scope.key || scope.startActive) && !attr.spinnerOn) { 48 | scope.spinner.spin(element[0]); 49 | } 50 | }, true); 51 | 52 | if (attr.spinnerOn) { 53 | scope.$watch(attr.spinnerOn, (spin) => { 54 | if (spin) { 55 | scope.spin(); 56 | } else { 57 | scope.stop(); 58 | } 59 | }); 60 | } 61 | 62 | scope.$on('us-spinner:spin', (event, key) => { 63 | if (!key || key === scope.key) { 64 | scope.spin(); 65 | } 66 | }); 67 | 68 | scope.$on('us-spinner:stop', (event, key) => { 69 | if (!key || key === scope.key) { 70 | scope.stop(); 71 | } 72 | }); 73 | 74 | scope.$on('$destroy', () => { 75 | scope.stop(); 76 | scope.spinner = null; 77 | }); 78 | } 79 | }; 80 | } 81 | 82 | usSpinner.$inject = ['SpinJSSpinner', 'usSpinnerConfig']; 83 | -------------------------------------------------------------------------------- /src/Interfaces/IUsSpinnerAttributes.d.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * UsSpinner directive attributes interface 4 | * @extends ng.IAttributes 5 | */ 6 | export interface IUsSpinnerAttributes extends ng.IAttributes { 7 | /** 8 | * The spinner-key will be used as an identifier (not unique) allowing you to have several spinners controlled by the same key 9 | */ 10 | spinnerKey?:string, 11 | /** 12 | * Render the spinner as active if true 13 | * spinner-start-active is ignored if spinner-on is specified 14 | */ 15 | spinnerStartActive?:string, 16 | /** 17 | * Specifies the spinner theme name to use in this usSpinner directive instance 18 | */ 19 | spinnerTheme?:string, 20 | /** 21 | * usSpinner directive (can also include Spinner options) 22 | */ 23 | usSpinner:string, 24 | /** 25 | * Spinner-on expression to evaluate and when gets true the spinner been activated 26 | */ 27 | spinnerOn:string 28 | } 29 | -------------------------------------------------------------------------------- /src/Interfaces/IUsSpinnerConfig.d.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * UsSpinnerConfig interface 4 | */ 5 | export interface IUsSpinnerConfig { 6 | /** 7 | * Configure default options for all spinners globally 8 | * Any options passed from a directive still override these 9 | * @param config - Spinner options configuration 10 | */ 11 | setDefaults(config:SpinnerOptions); 12 | /** 13 | * Themes provide method named default options for spinners. 14 | * Any options passed from a directive still override these 15 | * @param name - Theme name 16 | * @param config - Spinner options configuration 17 | */ 18 | setTheme(name:string, config:SpinnerOptions); 19 | /** 20 | * Spinner default options 21 | */ 22 | config:SpinnerOptions; 23 | /** 24 | * Spinner options for spinners 25 | */ 26 | themes: { 27 | [name: string]: SpinnerOptions; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Interfaces/IUsSpinnerScope.d.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * UsSpinner directive scope interface 4 | * @extends ng.IScope 5 | */ 6 | export interface IUsSpinnerScope extends ng.IScope { 7 | startActive:boolean, 8 | spin(), 9 | stop(), 10 | spinner:Spinner | null, 11 | key:string | false | undefined 12 | } 13 | -------------------------------------------------------------------------------- /src/Interfaces/IUsSpinnerService.d.ts: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * UsSpinnerService interface 4 | * This service will allow you to control spinner element(s) by appended keys 5 | * You can append multiple key with two spinners and they will be triggered together 6 | */ 7 | export interface IUsSpinnerService { 8 | /** 9 | * Spins spinner element(s) which is linked with the passed @key 10 | * If @key is not supplied all us-spinner directive will be triggered to spin 11 | * @param key - A key which is linked with spinner items to controll them 12 | */ 13 | spin(key?:string); 14 | /** 15 | * Stops the spinner element(s) which is linked with the passed @key 16 | * If @key is not supplied all us-spinner directive will be triggered to stop 17 | * @param key - A key which is linked with spinner items to controll them 18 | */ 19 | stop(key?:string); 20 | } 21 | -------------------------------------------------------------------------------- /src/Services/UsSpinnerService.ts: -------------------------------------------------------------------------------- 1 | import { IUsSpinnerService } from '../Interfaces/IUsSpinnerService'; 2 | 3 | /** 4 | * UsSpinnerService 5 | * This service let you control spin, start and stop 6 | */ 7 | export class UsSpinnerService implements IUsSpinnerService { 8 | 9 | constructor(private $rootScope:ng.IRootScopeService) {} 10 | static $inject = ['$rootScope']; 11 | 12 | spin(key?:string) { 13 | this.$rootScope.$broadcast('us-spinner:spin', key); 14 | } 15 | 16 | stop(key?:string) { 17 | this.$rootScope.$broadcast('us-spinner:stop', key); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/angular-spinner.ts: -------------------------------------------------------------------------------- 1 | import { SpinJSSpinner } from './Constants/SpinJSSpinner'; 2 | import { UsSpinnerService } from './Services/UsSpinnerService'; 3 | import { usSpinner } from './Directives/AngularSpinner'; 4 | import { UsSpinnerConfig } from './Config/UsSpinnerConfig'; 5 | import * as angular from 'angular'; 6 | 7 | export const angularSpinner = angular 8 | .module('angularSpinner', []) 9 | .provider('usSpinnerConfig', UsSpinnerConfig) 10 | .constant('SpinJSSpinner', SpinJSSpinner) 11 | .service('usSpinnerService', UsSpinnerService) 12 | .directive('usSpinner', usSpinner); 13 | -------------------------------------------------------------------------------- /test/Config/UsSpinnerConfig.test.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | import { IUsSpinnerConfig } from '../../src/Interfaces/IUsSpinnerConfig'; 3 | 4 | beforeEach(angular.mock.module('angularSpinner')); 5 | 6 | describe('Provider: usSpinnerConfigProvider', function () { 7 | it('should have configurable options', function () { 8 | angular.mock.module(function (usSpinnerConfigProvider:IUsSpinnerConfig) { 9 | usSpinnerConfigProvider.setDefaults({color: 'black'}); 10 | }); 11 | 12 | inject(function (usSpinnerConfig:IUsSpinnerConfig) { 13 | expect(usSpinnerConfig.config.color).toBe('black'); 14 | }); 15 | }); 16 | it('should support themes', function () { 17 | angular.mock.module(function (usSpinnerConfigProvider:IUsSpinnerConfig) { 18 | usSpinnerConfigProvider.setTheme('bigRed', {color: 'red', speed: 2}); 19 | }); 20 | 21 | inject(function (usSpinnerConfig:IUsSpinnerConfig) { 22 | expect(usSpinnerConfig.themes['bigRed'].color).toBe('red'); 23 | }); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /test/Directives/AngularSpinner.test.ts: -------------------------------------------------------------------------------- 1 | import * as angular from 'angular'; 2 | import { IUsSpinnerConfig } from '../../src/Interfaces/IUsSpinnerConfig'; 3 | import { IUsSpinnerService } from '../../src/Interfaces/IUsSpinnerService'; 4 | 5 | beforeEach(angular.mock.module('angularSpinner')); 6 | 7 | describe('Directive: us-spinner', function () { 8 | var Spinner; 9 | 10 | beforeEach(angular.mock.module(function ($provide:ng.auto.IProvideService) { 11 | Spinner = jasmine.createSpy('Spinner'); 12 | Spinner.prototype.spin = jasmine.createSpy('Spinner.spin'); 13 | Spinner.prototype.stop = jasmine.createSpy('Spinner.stop'); 14 | 15 | $provide.constant('SpinJSSpinner', Spinner); 16 | })); 17 | 18 | it('should create a spinner object', 19 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 20 | var element = angular.element('
'); 21 | element = $compile(element)($rootScope); 22 | $rootScope.$digest(); 23 | expect(Spinner).toHaveBeenCalled(); 24 | })); 25 | 26 | it('should start spinning the spinner automatically', 27 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 28 | var element = angular.element('
'); 29 | element = $compile(element)($rootScope); 30 | $rootScope.$digest(); 31 | expect(Spinner.prototype.spin).toHaveBeenCalled(); 32 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 33 | })); 34 | 35 | it('should start spinning the second spinner without stopping the first one', 36 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 37 | var element = angular.element('
'); 38 | element = $compile(element)($rootScope); 39 | var secondElement = angular.element('
'); 40 | secondElement = $compile(secondElement)($rootScope); 41 | $rootScope.$digest(); 42 | expect(Spinner.prototype.spin.calls.count()).toBe(2); 43 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 44 | })); 45 | 46 | it('should set spinner options as given in attribute', 47 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 48 | var element = angular.element('
'); 49 | element = $compile(element)($rootScope); 50 | $rootScope.$digest(); 51 | expect(Spinner).toHaveBeenCalledWith({width: 15}); 52 | })); 53 | 54 | describe('with default options', function() { 55 | beforeEach(angular.mock.module(function(usSpinnerConfigProvider:IUsSpinnerConfig) { 56 | usSpinnerConfigProvider.setDefaults({width: 10, color: 'black'}); 57 | })); 58 | 59 | it('should add spinner default options to options', 60 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 61 | var element = angular.element('
'); 62 | element = $compile(element)($rootScope); 63 | $rootScope.$digest(); 64 | expect(Spinner).toHaveBeenCalledWith({width: 15, color: 'black'}); 65 | })); 66 | 67 | describe('and with theme options', function() { 68 | beforeEach(angular.mock.module(function(usSpinnerConfigProvider:IUsSpinnerConfig) { 69 | usSpinnerConfigProvider.setTheme('bigRed', {speed: 20, color: 'red'}); 70 | })); 71 | 72 | it('should add theme options to options', 73 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 74 | var element = angular.element('
'); 75 | element = $compile(element)($rootScope); 76 | $rootScope.$digest(); 77 | expect(Spinner).toHaveBeenCalledWith({width: 15, color: 'red', speed: 20}); 78 | })); 79 | 80 | it('should not change default options by spinner options or theme options', 81 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerConfig:IUsSpinnerConfig) { 82 | var element = angular.element('
'); 83 | element = $compile(element)($rootScope); 84 | $rootScope.$digest(); 85 | expect(usSpinnerConfig.config).toEqual({width: 10, color: 'black'}); 86 | })); 87 | }); 88 | }); 89 | 90 | it('should update spinner options in response to scope updates', 91 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 92 | $rootScope['actualWidth'] = 25; 93 | var element = angular.element('
'); 94 | element = $compile(element)($rootScope); 95 | $rootScope.$digest(); 96 | expect(Spinner).toHaveBeenCalledWith({width: 25}); 97 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 98 | 99 | $rootScope['actualWidth'] = 72; 100 | $rootScope.$digest(); 101 | expect(Spinner).toHaveBeenCalledWith({width: 72}); 102 | expect(Spinner.prototype.stop).toHaveBeenCalled(); 103 | expect(Spinner.prototype.spin.calls.count()).toBe(2); 104 | })); 105 | 106 | it('should spin in response to scope updates', 107 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 108 | $rootScope['shouldSpin'] = false; 109 | var element = angular.element('
'); 110 | element = $compile(element)($rootScope); 111 | $rootScope.$digest(); 112 | expect(Spinner).toHaveBeenCalled(); 113 | expect(Spinner.prototype.spin).not.toHaveBeenCalled(); 114 | 115 | $rootScope['shouldSpin'] = true; 116 | $rootScope.$digest(); 117 | expect(Spinner.prototype.spin).toHaveBeenCalled(); 118 | })); 119 | 120 | it('should stop the spinner when the scope is destroyed', 121 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 122 | var scope = $rootScope.$new(); 123 | var element = angular.element('
'); 124 | element = $compile(element)(scope); 125 | $rootScope.$digest(); 126 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 127 | scope.$destroy(); 128 | expect(Spinner.prototype.stop).toHaveBeenCalled(); 129 | })); 130 | 131 | it('should not start spinning automatically', 132 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 133 | var element = angular.element('
'); 134 | element = $compile(element)($rootScope); 135 | $rootScope.$digest(); 136 | expect(Spinner.prototype.spin).not.toHaveBeenCalled(); 137 | })); 138 | 139 | it('should start spinning when service trigger the spin event', 140 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerService:IUsSpinnerService) { 141 | var element = angular.element('
'); 142 | element = $compile(element)($rootScope); 143 | $rootScope.$digest(); 144 | expect(Spinner.prototype.spin).not.toHaveBeenCalled(); 145 | usSpinnerService.spin('spinner'); 146 | expect(Spinner.prototype.spin).toHaveBeenCalled(); 147 | })); 148 | 149 | it('should start spinning the spinner automatically and stop when service trigger the stop event', 150 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerService:IUsSpinnerService) { 151 | var element = angular.element('
'); 152 | element = $compile(element)($rootScope); 153 | $rootScope.$digest(); 154 | expect(Spinner.prototype.spin).toHaveBeenCalled(); 155 | usSpinnerService.stop('spinner'); 156 | expect(Spinner.prototype.stop).toHaveBeenCalled(); 157 | })); 158 | 159 | it('should not start spinning the spinner automatically from binding', 160 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 161 | $rootScope['spinnerActive'] = false; 162 | var element = angular.element('
'); 163 | element = $compile(element)($rootScope); 164 | $rootScope.$digest(); 165 | expect(Spinner.prototype.spin).not.toHaveBeenCalled(); 166 | })); 167 | 168 | it('should start spinning the spinner automatically from binding', 169 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService) { 170 | $rootScope['spinnerActive'] = true; 171 | var element = angular.element('
'); 172 | element = $compile(element)($rootScope); 173 | $rootScope.$digest(); 174 | expect(Spinner.prototype.spin).toHaveBeenCalled(); 175 | })); 176 | 177 | it('should start spinning the second spinner without starting the first one', 178 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerService:IUsSpinnerService) { 179 | var element = angular.element('
'); 180 | element = $compile(element)($rootScope); 181 | var secondElement = angular.element('
'); 182 | secondElement = $compile(secondElement)($rootScope); 183 | $rootScope.$digest(); 184 | usSpinnerService.spin('spinner2'); 185 | expect(Spinner.prototype.spin.calls.count()).toBe(1); 186 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 187 | })); 188 | 189 | it('should start spinning the spinners with the same key', 190 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerService:IUsSpinnerService) { 191 | $compile('
')($rootScope); 192 | $compile('
')($rootScope); 193 | $compile('
')($rootScope); 194 | $compile('
')($rootScope); 195 | $compile('
')($rootScope); 196 | $rootScope.$digest(); 197 | usSpinnerService.spin('spinner'); 198 | expect(Spinner.prototype.spin.calls.count()).toBe(3); 199 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 200 | usSpinnerService.stop('spinner'); 201 | expect(Spinner.prototype.stop.calls.count()).toBe(3); 202 | usSpinnerService.spin('spinner2'); 203 | expect(Spinner.prototype.spin.calls.count()).toBe(5); 204 | usSpinnerService.stop('spinner2'); 205 | expect(Spinner.prototype.stop.calls.count()).toBe(5); 206 | })); 207 | 208 | //Feature: Stop all/Start all spinners - Issue #28 209 | it('should start spinning all the spinners when usSpinnerService.spin() is called without specific key', 210 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerService:IUsSpinnerService) { 211 | $compile('
')($rootScope); 212 | $compile('
')($rootScope); 213 | $compile('
')($rootScope); 214 | $compile('
')($rootScope); 215 | $compile('
')($rootScope); 216 | $rootScope.$digest(); 217 | usSpinnerService.spin(); 218 | expect(Spinner.prototype.spin.calls.count()).toBe(5); 219 | expect(Spinner.prototype.stop).not.toHaveBeenCalled(); 220 | })); 221 | 222 | //Feature: Stop all/Start all spinners - Issue #28 223 | it('should stop spinning all the spinners when usSpinnerService.stop() is called without specific key', 224 | inject(function ($rootScope:ng.IRootScopeService, $compile:ng.ICompileService, usSpinnerService:IUsSpinnerService) { 225 | $compile('
')($rootScope); 226 | $compile('
')($rootScope); 227 | $compile('
')($rootScope); 228 | $compile('
')($rootScope); 229 | $compile('
')($rootScope); 230 | $rootScope.$digest(); 231 | usSpinnerService.stop(); 232 | expect(Spinner.prototype.stop.calls.count()).toBe(5); 233 | expect(Spinner.prototype.spin).not.toHaveBeenCalled(); 234 | })); 235 | 236 | }); 237 | -------------------------------------------------------------------------------- /test/index.ts: -------------------------------------------------------------------------------- 1 | import './Config/UsSpinnerConfig.test'; 2 | import './Directives/AngularSpinner.test'; 3 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "strictNullChecks": true, 6 | "sourceMap": true 7 | }, 8 | "include": [ 9 | "src", 10 | "test" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | devtool: 'inline-source-map', 6 | resolve: { 7 | // Add `.ts` as a resolvable extension. 8 | extensions: ['', '.webpack.js', '.web.js', '.ts', '.js'] 9 | }, 10 | externals: { 11 | // require("angular") is external and available 12 | // on the global var angular 13 | "angular": "angular" 14 | }, 15 | module: { 16 | loaders: [ 17 | // all files with a `.ts` extension will be handled by `ts-loader` 18 | { test: /\.ts$/, loader: 'ts-loader' } 19 | ] 20 | }, 21 | plugins: [ 22 | // existing plugins go here 23 | new webpack.SourceMapDevToolPlugin({ 24 | filename: null, // if no value is provided the sourcemap is inlined 25 | test: /\.(ts)($|\?)/i // process .ts files only 26 | }) 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /webpack.production.config.js: -------------------------------------------------------------------------------- 1 | 2 | var webpack = require('webpack'); 3 | var webpackConfig = require('./webpack.config.js'); 4 | 5 | //Remove sourcemaps from production version 6 | webpackConfig.devtool = undefined; 7 | webpackConfig.plugins = undefined; 8 | webpackConfig.ts = { 9 | compilerOptions: { 10 | "sourceMap": false 11 | } 12 | }; 13 | 14 | module.exports = webpackConfig; 15 | --------------------------------------------------------------------------------