├── .editorconfig ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .jshintrc ├── .travis.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── Gruntfile.js ├── README.md ├── bower.json ├── css ├── myth │ ├── ngDialog-theme-default.css │ ├── ngDialog-theme-plain.css │ └── ngDialog.css ├── ngDialog-custom-width.css ├── ngDialog-theme-default.css ├── ngDialog-theme-default.min.css ├── ngDialog-theme-plain.css ├── ngDialog-theme-plain.min.css ├── ngDialog.css └── ngDialog.min.css ├── example ├── README.md ├── browser-back-button │ ├── index.html │ └── ui-router-1.0.0-rc.1.html ├── externalTemplate.html ├── index.html ├── inside-directive │ └── inside-directive-plain.js ├── paddingTest.html └── server.js ├── js ├── ngDialog.js └── ngDialog.min.js ├── karma.conf.js ├── package.json ├── protractor.conf.js ├── server.js ├── tests ├── build-systems │ └── browserify │ │ ├── .gitignore │ │ ├── README.md │ │ ├── app.js │ │ ├── gulpfile.js │ │ ├── index.html │ │ └── package.json ├── protractor │ ├── close.js │ ├── closeByNavigation.js │ ├── open.js │ └── test.js └── unit │ ├── before.js │ ├── ngDialog.js │ ├── ngDialog_close.js │ ├── ngDialog_closeThisDialog.js │ └── ngDialog_insideDirective.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [package.json] 13 | [*.spec.js] 14 | indent_size = 2 15 | 16 | [*.md] 17 | trim_trailing_whitespace = false 18 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/rules 2 | { 3 | "env": { 4 | "browser": true, 5 | "node": true, 6 | "mocha": true 7 | }, 8 | "rules": { 9 | "strict": 0, 10 | "no-extra-strict": 0, 11 | "quotes": [2, "single"], 12 | "no-underscore-dangle": 0, 13 | "no-unused-vars": 1, 14 | "no-unused-expressions": 0, 15 | "new-cap": 0, 16 | "consistent-return": 0, 17 | "no-use-before-define": 0, 18 | "no-shadow-restricted-names": 0 19 | }, 20 | "globals": { 21 | "angular": true, 22 | "define": true, 23 | "expect": true, 24 | "inject": true, 25 | "jasmine": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | **What version of ng-dialog are you using?** 6 | 7 | **What version of AngularJS are you using?** 8 | 9 | **What browsers are affected?** 10 | 11 | **Please provide either a JSFiddle, Plunkr example that replicates the issue** 12 | 13 | **Please describe the issue** 14 | 15 | **What did you expect to happen?** 16 | 17 | **What actually happened?** 18 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 4 | 5 | **What issue is this PR resolving? Alternatively, please describe the bugfix/enhancement this PR aims to provide** 6 | 19 | 20 | **Have you provided unit tests that either prove the bugfix or cover the enhancement?** 21 | 22 | **Related issues** 23 | 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Directories 2 | node_modules 3 | /bower_components 4 | /coverage 5 | 6 | # Files 7 | .DS_Store 8 | *.log 9 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "angular", 4 | "define" 5 | ], 6 | 7 | "asi" : false, 8 | "bitwise" : true, 9 | "boss" : false, 10 | "browser" : true, 11 | "curly" : true, 12 | "debug": false, 13 | "devel": false, 14 | "eqeqeq": true, 15 | "evil": false, 16 | "expr": true, 17 | "forin": false, 18 | "immed": true, 19 | "jquery" : true, 20 | "latedef" : false, 21 | "laxbreak": false, 22 | "multistr": true, 23 | "newcap": true, 24 | "noarg": true, 25 | "node" : true, 26 | "noempty": false, 27 | "nonew": true, 28 | "onevar": false, 29 | "plusplus": false, 30 | "regexp": false, 31 | "strict": false, 32 | "sub": false, 33 | "trailing" : true, 34 | "undef": true, 35 | "unused": "vars" 36 | } 37 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 4 5 | addons: 6 | sauce_connect: 7 | username: "ngDialog" 8 | access_key: "916ebec2-5857-4740-aa4f-047db7472e8c" 9 | before_script: 10 | - export DISPLAY=:99.0 11 | - sh -e /etc/init.d/xvfb start 12 | - npm install 13 | - npm run webdriver-update 14 | - npm run webdriver & 15 | - npm install -g bower 16 | - sleep 3 17 | script: 18 | - npm run serve & 19 | - sleep 3 20 | - npm run protractor 21 | - npm run protractor-a11y 22 | - npm run protractor-console 23 | - npm test 24 | 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.0.0 2 | - [x] Changes close element to button with proper accessibility rules ([PR-553](https://github.com/likeastore/ngDialog/pull/533)) 3 | 4 | # 0.5.0 5 | - [x] Angular version in `package.json` is now `1.4.x` ([ISSUE-244](https://github.com/likeastore/ngDialog/issues/244)) 6 | - [x] fixed spelling of `ariaLabelledById` and `ariaLabelledBySelector` inside README file by [@rylan](https://github.com/rylan) ([PR-242](https://github.com/likeastore/ngDialog/pull/242)) 7 | - [x] fixed bug with $templateCache when template was already cached before calling ngDialog by [@mixer2](https://github.com/mixer2) ([PR-241](https://github.com/likeastore/ngDialog/pull/241)) 8 | - [x] add dialog close value to the $broadcast'ed events by [@Kidlike](https://github.com/Kidlike) ([PR-252](https://github.com/likeastore/ngDialog/pull/252)) 9 | - [x] fix for removing package version from bower.json as it's ignored by bower by [@kkirsche](https://github.com/kkirsche) ([PR-255](https://github.com/likeastore/ngDialog/pull/255)) 10 | - [x] fix for non-working `ngDialog.close()` when no arguments are provided by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-243](https://github.com/likeastore/ngDialog/issues/243)) 11 | - [x] added documentation for `controllerAs` option by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-248](https://github.com/likeastore/ngDialog/issues/248)) 12 | - [x] new option `disableAnimation` that could be used for disabling animation of dialog by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-159](https://github.com/likeastore/ngDialog/issues/159)) 13 | - [x] new attribute `ng-dialog-overlay` for ngDialog directive by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-198](https://github.com/likeastore/ngDialog/issues/198)) 14 | - [x] new attribute `ng-dialog-bind-to-controller` for ngDialog directive by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-236](https://github.com/likeastore/ngDialog/issues/236)) 15 | - [x] fix for error when `controllerAs` is used together with inline controller definition by [@andrewogburn](https://github.com/andrewogburn) ([PR-260](https://github.com/likeastore/ngDialog/pull/260), [ISSUE-259](https://github.com/likeastore/ngDialog/issues/259)) 16 | - [x] added method `getOpenDialogs()` that returns array of all opened dialogs by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-240](https://github.com/likeastore/ngDialog/issues/240)) 17 | - [x] added two new events emmited by ngDialog - `ngDialog.templateLoading` and `ngDialog.templateLoaded` by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-231](https://github.com/likeastore/ngDialog/issues/231)) 18 | - [x] added `ngDialogId` field to scope of opened dialog (this field is equal to id of dialog) by [@egor-smirnov](https://github.com/egor-smirnov) ([ISSUE-274](https://github.com/likeastore/ngDialog/issues/274), [ISSUE-264](https://github.com/likeastore/ngDialog/issues/264)) 19 | - [x] fix for odd timing issue when using the `closeByNavigation` option alongside `angular-ui-router package` by [@jdelibas](https://github.com/jdelibas) ([PR-277](https://github.com/likeastore/ngDialog/pull/277)) 20 | - [x] fix for disabling of body scroll when dialog is opened for some cases by [@marmotz](https://github.com/marmotz) ([PR-280](https://github.com/likeastore/ngDialog/pull/280), [ISSUE-206](https://github.com/likeastore/ngDialog/issues/206)) 21 | - [x] fix for avoiding require multiple angular when it's required already when using CommonJS by [@michaeleekk](https://github.com/michaeleekk) ([PR-284](https://github.com/likeastore/ngDialog/pull/284)) 22 | - [x] fix for `frunt build` that was resetting html.ngdialog changes by [@davidvuong](https://github.com/davidvuong) ([PR-285](https://github.com/likeastore/ngDialog/pull/285)) 23 | - [x] moved Angular to dev.dependencies by [@platdesign](https://github.com/platdesign) ([PR-287](https://github.com/likeastore/ngDialog/pull/287)) 24 | - [x] fix for unboudning all keydown events when dialog is closed by [@daanoz](https://github.com/daanoz) ([PR-291](https://github.com/likeastore/ngDialog/pull/291)) 25 | - [x] ignore elements with tabindex=-1 when tabbing by [@roaks3](https://github.com/roaks3) ([PR-292](https://github.com/likeastore/ngDialog/pull/292), [ISSUE-281](https://github.com/likeastore/ngDialog/issues/281)) 26 | 27 | That was huge. Thanks everybody! 28 | 29 | # 0.4.0 30 | 31 | - [x] new `resolve` option for defining locals for ngDialog controller by [@rur](https://github.com/rur) ([PR-182](https://github.com/likeastore/ngDialog/pull/182)) 32 | - [x] support for `controllerAs` pattern by [@andrewogburn](https://github.com/andrewogburn) and [@sprbikkel](https://github.com/sprbikkel) ([PR-205](https://github.com/likeastore/ngDialog/pull/205), [PR-224](https://github.com/likeastore/ngDialog/pull/224)) 33 | - [x] added accessibility improvements (keyboard focus management / ARIA attribute) by [@richardszalay](https://github.com/richardszalay) ([PR-166](https://github.com/likeastore/ngDialog/pull/166)) 34 | - [x] added `isOpen(id)` public method by [@kasimoglou](https://github.com/kasimoglou) ([PR-219](https://github.com/likeastore/ngDialog/pull/219)) 35 | - [x] fix for `esc` should only close top dialog by [@jemise111](https://github.com/jemise111) ([PR-226](https://github.com/likeastore/ngDialog/pull/226)) 36 | - [x] fix for flickering dialogs in Internet Explorer by [@MvHMontySCOUT](https://github.com/MvHMontySCOUT) ([PR-207](https://github.com/likeastore/ngDialog/pull/207), discussion - [ISSUE-142](https://github.com/likeastore/ngDialog/issues/142)) 37 | - [x] fix issue when opening multiple dialogs simultaneously by [@bchelli](https://github.com/bchelli) ([PR-221](https://github.com/likeastore/ngDialog/pull/221)) 38 | - [x] various minor bug fixes, general improvements and examples updates 39 | 40 | Thanks everybody, you're awesome! :dancer: :+1: 41 | 42 | # 0.3.12 43 | 44 | - [x] better `box-sizing` policy 45 | 46 | # 0.3.11 47 | 48 | - [x] prevent the modal from closing if preCloseCallback returns a falsy value 49 | 50 | # 0.3.10 51 | 52 | - [x] fix negative dialogs count 53 | 54 | # 0.3.9 55 | 56 | - [x] fix destroy scope with animation for multiple dialog [ISSUE-125](https://github.com/likeastore/ngDialog/issues/125) 57 | 58 | # 0.3.8 59 | 60 | - [x] Make ngDialog work with AngularJS 1.3 when `$compileProvider` debug info is disabled - `$compileProvider.debugInfoEnabled(false)`. 61 | 62 | # 0.3.7 63 | 64 | - [x] support for [UMD pattern](https://github.com/umdjs/umd) 65 | - [x] get rid of `module` variable in source code 66 | - [x] get rid of `window` dependency in favor of `$window` 67 | 68 | # 0.3.6 69 | 70 | - [x] finally (after many requests) `$scope.ngDialogData` holds reference to the objects passed instead of copying them. 71 | 72 | # 0.3.5 73 | 74 | - [x] fix for HammerJS 1.1 breaking dialog 75 | 76 | # 0.3.4 77 | 78 | - [x] add support for `overlay` option (https://github.com/likeastore/ngDialog/issues/117) 79 | 80 | # 0.3.3 81 | 82 | - [x] successful tests and support for Angular.js `1.3.x` 83 | 84 | # 0.3.2 85 | 86 | - [x] fixed an issue with Hammer.js manager 87 | 88 | # 0.3.1 89 | 90 | - [x] `ngDialog.closing` event 91 | - [x] `closeByNavigation` option 92 | - [x] `templateUrl` option 93 | 94 | # 0.3.0 95 | 96 | - [x] `.openConfirm()` method 97 | - [x] `.setForceBodyReload()` method 98 | - [x] add support for `.setDefaults()` method 99 | - [x] fix scroll jump bug 100 | - [x] fix event broadcasting to occur at the times they should 101 | - [x] fix for `ngDialogData` being passed after controller instantiation 102 | - [x] allow objects for `ngDialogData` 103 | - [x] `cache` option 104 | - [x] `preCloseCallback` option 105 | - [x] `appendTo` option 106 | - [x] `name` option 107 | - [x] minor code fixes and optimizations, examples improvements 108 | 109 | # 0.2.2 110 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | ngDialog is in use by many people. In order to ensure quality and prevent regressions, all contributions require unit tests proving that the contribution: 4 | 5 | 1. Fixes a bug 6 | 2. Performs new functionality as expected 7 | 3. Behaves in a predictable manner when misused (bad input given as an option for example) 8 | 9 | In addition, where a contribution is aimed at resolving a bug or implementing a feature that can only be measured in a real browser, an e2e test proving the expected behaviour should be included. 10 | 11 | # README 12 | 13 | If your PR adds new behaviour or modifies existing behaviour, the README should be updated. 14 | 15 | # Coding style 16 | 17 | > All code in any code-base should look like a single person typed it, no matter how many people contributed. 18 | 19 | This section describes the coding style guide of the repo. You might not agree with it and that's fine, but if you're going to send PRs, treat this guide as a law. 20 | 21 | ##### There are not too much of rules to follow: 22 | 23 | - indent style is 4 spaces 24 | - always use single quotes 25 | - one space after `if`, `for`, `while`, etc. 26 | - no spaces between `(`,`)` and statement content 27 | - use one `var` per variable unless you don't assign any values to it (and it's short enough) 28 | - always `'use strict'` mode 29 | - always use strict comparisons: `===` and `!==` 30 | - use semicolons 31 | - don't use comma-first notation 32 | 33 | ##### These tools will help your IDE to remind you with some of the rules listed above: 34 | 35 | - [EditorConfig](http://editorconfig.org) 36 | - [JSHint](http://jshint.com) 37 | - [ESLint](http://eslint.org) 38 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | uglify: { 6 | options: { 7 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> (<%= pkg.homepage %>) */\n' 8 | }, 9 | ngDialog: { 10 | files: { 11 | './js/ngDialog.min.js': ['./js/ngDialog.js'] 12 | } 13 | } 14 | }, 15 | jshint: { 16 | options: { 17 | ignores: ['./js/ngDialog.min.js'] 18 | }, 19 | files: ['*.js'] 20 | }, 21 | myth: { 22 | dist: { 23 | files: { 24 | './css/ngDialog.css': './css/myth/ngDialog.css', 25 | './css/ngDialog-theme-default.css': './css/myth/ngDialog-theme-default.css', 26 | './css/ngDialog-theme-plain.css': './css/myth/ngDialog-theme-plain.css' 27 | } 28 | } 29 | }, 30 | cssmin: { 31 | options: { 32 | banner: '/*! <%= pkg.name %> - v<%= pkg.version %> (<%= pkg.homepage %>) */\n' 33 | }, 34 | minify: { 35 | files: { 36 | 'css/ngDialog.min.css': ['css/ngDialog.css'], 37 | 'css/ngDialog-theme-default.min.css': ['css/ngDialog-theme-default.css'], 38 | 'css/ngDialog-theme-plain.min.css': ['css/ngDialog-theme-plain.css'] 39 | } 40 | } 41 | } 42 | }); 43 | 44 | grunt.loadNpmTasks('grunt-contrib-jshint'); 45 | grunt.loadNpmTasks('grunt-contrib-uglify'); 46 | grunt.loadNpmTasks('grunt-myth'); 47 | grunt.loadNpmTasks('grunt-contrib-cssmin'); 48 | 49 | grunt.registerTask('default', ['jshint']); 50 | grunt.registerTask('build', ['uglify', 'myth', 'cssmin']); 51 | grunt.registerTask('css', ['myth', 'cssmin']); 52 | }; 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ngDialog 3 | 4 | [![build status](http://img.shields.io/travis/likeastore/ngDialog.svg)](https://travis-ci.org/likeastore/ngDialog) 5 | [![npm version](http://badge.fury.io/js/ng-dialog.svg)](http://badge.fury.io/js/ng-dialog) 6 | [![github tag](https://img.shields.io/github/tag/likeastore/ngDialog.svg)](https://github.com/likeastore/ngDialog/tags) 7 | [![Download Count](https://img.shields.io/npm/dm/ng-dialog.svg)](http://www.npmjs.com/package/ng-dialog) 8 | [![Code Climate](https://codeclimate.com/github/likeastore/ngDialog/badges/gpa.svg)](https://codeclimate.com/github/likeastore/ngDialog) 9 | 10 | > Modal dialogs and popups provider for [AngularJS](http://angularjs.org/) applications. 11 | 12 | ngDialog is ~10KB (minified), has minimalistic API, is highly customizable through themes and has only AngularJS as dependency. 13 | 14 | ### [Demo](http://likeastore.github.io/ngDialog) 15 | 16 | ## Install 17 | 18 | You can download all necessary ngDialog files manually, or install it with bower: 19 | 20 | ```bash 21 | bower install ng-dialog 22 | ``` 23 | 24 | or npm: 25 | 26 | ```bash 27 | npm install ng-dialog 28 | ``` 29 | 30 | ## Usage 31 | 32 | You need only to include ``ngDialog.js``, ``ngDialog.css`` and ``ngDialog-theme-default.css`` (as minimal setup) to your project and then you can start using the ``ngDialog`` provider in your directives, controllers and services. For example: 33 | 34 | ```html 35 | 36 | 37 | 38 | ``` 39 | 40 | Define the className to be the ``ngDialog-theme-default``. 41 | 42 | For example in controllers: 43 | 44 | ```javascript 45 | var app = angular.module('exampleApp', ['ngDialog']); 46 | 47 | app.controller('MainCtrl', function ($scope, ngDialog) { 48 | $scope.clickToOpen = function () { 49 | ngDialog.open({ template: 'popupTmpl.html', className: 'ngdialog-theme-default' }); 50 | }; 51 | }); 52 | ``` 53 | 54 | ## Collaboration 55 | 56 | Your help is appreciated! If you've found a bug or if something is not clear, please raise an issue. 57 | 58 | Ideally, if you've found an issue, you will submit a PR that meets our [contributor guidelines][contributor-guidelines]. 59 | 60 | ### Running Tests 61 | 62 | ```bash 63 | git clone git@github.com:likeastore/ngDialog.git 64 | cd ngDialog 65 | npm i 66 | npm run test 67 | ``` 68 | 69 | ## API 70 | 71 | ngDialog service provides easy to use and minimalistic API, but in the same time it's powerful enough. Here is the list of accessible methods that you can use: 72 | 73 | === 74 | 75 | ### ``.open(options)`` 76 | 77 | Method allows to open dialog window, creates new dialog instance on each call. It accepts ``options`` object as the only argument. 78 | 79 | #### Options: 80 | 81 | ##### ``template {String}`` 82 | 83 | Dialog template can be loaded through ``path`` to external html template or `` 90 | ``` 91 | 92 | ```javascript 93 | ngDialog.open({ template: 'templateId' }); 94 | ``` 95 | 96 | Also it is possible to use a simple string as template together with ``plain`` option. 97 | 98 | ##### Pro Tip about templates 99 | 100 | It's not always necessary to place your external html template inside `` 206 | ``` 207 | 208 | ##### ``scope.closeThisDialog(value)`` 209 | 210 | In addition ``.closeThisDialog(value)`` method gets injected to passed ``$scope``. This allows you to close the dialog straight from the handler in a popup element, for example: 211 | 212 | ```html 213 |
214 | 215 | 216 |
217 | ``` 218 | 219 | Any value passed to this function will be attached to the object which resolves on the close promise for this dialog. For dialogs opened with the ``openConfirm()`` method the value is used as the reject reason. 220 | 221 | ##### ``data {String | Object | Array}`` 222 | 223 | Any serializable data that you want to be stored in the controller's dialog scope. (``$scope.ngDialogData``). From version `0.3.6` `$scope.ngDialogData` keeps references to the objects instead of copying them. 224 | 225 | Additionally, you will have the dialog id available as ``$scope.ngDialogId``. If you are using ``$scope.ngDialogData``, it'll be also available under ``$scope.ngDialogData.ngDialogId``. 226 | 227 | ##### ``className {String}`` 228 | 229 | This option allows you to control the dialog's look, you can use built-in [themes](https://github.com/likeastore/ngDialog#themes) or create your own styled modals. 230 | 231 | This example enables one of the built-in ngDialog themes - ``ngdialog-theme-default`` (do not forget to include necessary css files): 232 | 233 | ```javascript 234 | ngDialog.open({ 235 | template: 'templateId', 236 | className: 'ngdialog-theme-default' 237 | }); 238 | ``` 239 | Note: If the className is not mentioned, the dialog will not display correctly. 240 | 241 | Check [themes](https://github.com/likeastore/ngDialog#themes) block to learn more. 242 | 243 | ##### ``appendClassName {String}`` 244 | 245 | Unlike the `className` property, which overrides any default classes specified through the `setDefaults()` method ([see docs](https://github.com/likeastore/ngDialog#setdefaultsoptions)), `appendClassName` allows for the addition of a class on top of any defaults. 246 | 247 | For example, the following would add both the `ngdialog-theme-default` and `ngdialog-custom` classes to the dialog opened: 248 | 249 | ```javascript 250 | ngDialogProvider.setDefaults({ 251 | className: 'ngdialog-theme-default' 252 | }); 253 | ``` 254 | ```javascript 255 | ngDialog.open({ 256 | template: 'template.html', 257 | appendClassName: 'ngdialog-custom' 258 | }); 259 | ``` 260 | 261 | ##### ``disableAnimation {Boolean}`` 262 | 263 | If ``true`` then animation for the dialog will be disabled, default ``false``. 264 | 265 | ##### ``overlay {Boolean}`` 266 | 267 | If ``false`` it allows to hide the overlay div behind the modals, default ``true``. 268 | 269 | ##### ``showClose {Boolean}`` 270 | 271 | If ``false`` it allows to hide the close button on modals, default ``true``. 272 | 273 | ##### ``closeByEscape {Boolean}`` 274 | 275 | It allows to close modals by clicking the ``Esc`` key, default ``true``. 276 | 277 | This will close all open modals if there are several of them opened at the same time. 278 | 279 | ##### ``closeByNavigation {Boolean}`` 280 | 281 | It allows to close modals on state change (history.back, $state.go, etc.), default ``false``. 282 | Compatible with ui-router and angular-router. 283 | Set this value to true if you want your modal to close when you go back or change state. 284 | Set this value to false if you want your modal to stay open when you change state within your app. 285 | 286 | This will close all open modals if there are several of them opened at the same time. 287 | 288 | ##### ``closeByDocument {Boolean}`` 289 | 290 | It allows to close modals by clicking on overlay background, default ``true``. If [Hammer.js](https://github.com/EightMedia/hammer.js) is loaded, it will listen for ``tap`` instead of ``click``. 291 | 292 | ##### ``appendTo {String}`` 293 | 294 | Specify your element where to append dialog instance, accepts selector string (e.g. ``#yourId``, ``.yourClass``). If not specified appends dialog to ``body`` as default behavior. 295 | 296 | ##### ``cache {Boolean}`` 297 | 298 | Pass ``false`` to disable template caching. Useful for developing purposes, default is ``true``. 299 | 300 | ##### ``name {String} | {Number}`` 301 | 302 | Give a name for a dialog instance. It is useful for identifying specific dialog if there are multiple dialog boxes opened. 303 | 304 | #### ``onOpenCallback {String} | {Function}`` 305 | 306 | Provide either the name of a function or a function to be called after the dialog is opened. This callback can be used instead of the `ngdialog.opened` event. 307 | It provides with a way to register a hook for when the dialog is appended to the DOM and about to be shown to the user. 308 | 309 | ##### ``preCloseCallback {String} | {Function}`` 310 | 311 | Provide either the name of a function or a function to be called before the dialog is closed. If the callback function specified in the option returns ``false`` then the dialog will not be closed. Alternatively, if the callback function returns a promise that gets resolved the dialog will be closed. 312 | 313 | The ``preCloseCallback`` function receives as a parameter ``value`` which is the same value sent to ``.close(id, value)``. 314 | 315 | The primary use case for this feature is a dialog which contains user actions (e.g. editing data) for which you want the ability to confirm whether to discard unsaved changes upon exiting the dialog (e.g. via the escape key). 316 | 317 | This example uses an inline function with a ``window.confirm`` call in the ``preCloseCallback`` function: 318 | 319 | ```javascript 320 | ngDialog.open({ 321 | preCloseCallback: function(value) { 322 | if (confirm('Are you sure you want to close without saving your changes?')) { 323 | return true; 324 | } 325 | return false; 326 | } 327 | }); 328 | ``` 329 | 330 | In another example, a callback function with a nested confirm ngDialog is used: 331 | 332 | ```javascript 333 | ngDialog.open({ 334 | preCloseCallback: function(value) { 335 | var nestedConfirmDialog = ngDialog.openConfirm({ 336 | template:'\ 337 |

Are you sure you want to close the parent dialog?

\ 338 |
\ 339 | \ 340 | \ 341 |
', 342 | plain: true 343 | }); 344 | 345 | // NOTE: return the promise from openConfirm 346 | return nestedConfirmDialog; 347 | } 348 | }); 349 | ``` 350 | 351 | ##### ``trapFocus {Boolean}`` 352 | 353 | When ``true``, ensures that the focused element remains within the dialog to conform to accessibility recommendations. Default value is ``true`` 354 | 355 | ##### ``preserveFocus {Boolean}`` 356 | 357 | When ``true``, closing the dialog restores focus to the element that launched it. Designed to improve keyboard accessibility. Default value is ``true`` 358 | 359 | ##### ``ariaAuto {Boolean}`` 360 | 361 | When ``true``, automatically selects appropriate values for any unspecified accessibility attributes. Default value is ``true`` 362 | 363 | See [Accessibility](#Accessibility) for more information. 364 | 365 | ##### ``ariaRole {String}`` 366 | 367 | Specifies the value for the ``role`` attribute that should be applied to the dialog element. Default value is ``null`` (unspecified) 368 | 369 | See [Accessibility](#Accessibility) for more information. 370 | 371 | ##### ``ariaLabelledById {String}`` 372 | 373 | Specifies the value for the ``aria-labelledby`` attribute that should be applied to the dialog element. Default value is ``null`` (unspecified) 374 | 375 | If specified, the value is not validated against the DOM. See [Accessibility](#Accessibility) for more information. 376 | 377 | ##### ``ariaLabelledBySelector {String}`` 378 | 379 | Specifies the CSS selector for the element to be referenced by the ``aria-labelledby`` attribute on the dialog element. Default value is ``null`` (unspecified) 380 | 381 | If specified, the first matching element is used. See [Accessibility](#Accessibility) for more information. 382 | 383 | ##### ``ariaDescribedById {String}`` 384 | 385 | Specifies the value for the ``aria-describedby`` attribute that should be applied to the dialog element. Default value is ``null`` (unspecified) 386 | 387 | If specified, the value is not validated against the DOM. See [Accessibility](#Accessibility) for more information. 388 | 389 | ##### ``ariaDescribedBySelector {String}`` 390 | 391 | Specifies the CSS selector for the element to be referenced by the ``aria-describedby`` attribute on the dialog element. Default value is ``null`` (unspecified) 392 | 393 | If specified, the first matching element is used. See [Accessibility](#Accessibility) for more information. 394 | 395 | ##### ``width {Number | String}`` 396 | 397 | This option allows you to control the dialog's width. Default value is `null` (unspecified) 398 | 399 | If you provide a Number, 'px' will be appended. To use a custom metric, use a String, e.g. `'40%'`. 400 | 401 | For example, the following will add `width: 400px;` to the dialog when opened: 402 | 403 | ``` 404 | ngDialog.open({ 405 | template: 'template.html', 406 | width: 400 407 | }); 408 | ``` 409 | 410 | In another example, the following will add `width: 40%;`: 411 | 412 | ``` 413 | ngDialog.open({ 414 | template: 'template.html', 415 | width: '40%' 416 | }); 417 | ``` 418 | 419 | ##### ``height {Number | String}`` 420 | 421 | This option allows you to control the dialog's height. Default value is `null` (unspecified) 422 | 423 | If you provide a Number, 'px' will be appended. To use a custom metric, use a String, e.g. `'40%'`. 424 | 425 | For example, the following will add `height: 400px;` to the dialog when opened: 426 | 427 | ``` 428 | ngDialog.open({ 429 | template: 'template.html', 430 | height: 400 431 | }); 432 | ``` 433 | 434 | In another example, the following will add `height: 40%;`: 435 | 436 | ``` 437 | ngDialog.open({ 438 | template: 'template.html', 439 | height: '40%' 440 | }); 441 | ``` 442 | 443 | #### Returns: 444 | 445 | The ``open()`` method returns an object with some useful properties. 446 | 447 | ##### ``id {String}`` 448 | 449 | This is the ID of the dialog which was just created. It is the ID on the dialog's DOM element. 450 | 451 | ##### ``close(value) {Function}`` 452 | 453 | This is a function which will close the dialog which was opened by the current call to ``open()``. It takes an optional value to pass to the close promise. 454 | 455 | ##### ``closePromise {Promise}`` 456 | 457 | A promise which will resolve when the dialog is closed. It is resolved with an object containing: ``id`` - the ID of the closed dialog, ``value`` - the value the dialog was closed with, ``$dialog`` - the dialog element which at this point has been removed from the DOM and ``remainingDialogs`` - the number of dialogs still open. 458 | 459 | The value property will be a special string if the dialog is dismissed by one of the built in mechanisms: `'$escape'`, `'$closeButton'` or `'$document'`. 460 | 461 | This allows you do to something like this: 462 | 463 | ```javascript 464 | var dialog = ngDialog.open({ 465 | template: 'templateId' 466 | }); 467 | 468 | dialog.closePromise.then(function (data) { 469 | console.log(data.id + ' has been dismissed.'); 470 | }); 471 | ``` 472 | 473 | === 474 | 475 | ### ``.setDefaults(options)`` 476 | 477 | You're able to set default settings through ``ngDialogProvider``: 478 | 479 | ```javascript 480 | var app = angular.module('myApp', ['ngDialog']); 481 | app.config(['ngDialogProvider', function (ngDialogProvider) { 482 | ngDialogProvider.setDefaults({ 483 | className: 'ngdialog-theme-default', 484 | plain: true, 485 | showClose: true, 486 | closeByDocument: true, 487 | closeByEscape: true 488 | }); 489 | }]); 490 | ``` 491 | 492 | === 493 | 494 | ### ``.openConfirm(options)`` 495 | 496 | Opens a dialog that by default does not close when hitting escape or clicking outside the dialog window. The function returns a promise that is either resolved or rejected depending on the way the dialog was closed. 497 | 498 | #### Options: 499 | 500 | The options are the same as the regular [``.open()``](https://github.com/likeastore/ngDialog#options) method with an extra function added to the scope: 501 | 502 | ##### ``scope.confirm()`` 503 | 504 | In addition to the ``.closeThisDialog()`` method. The method ``.confirm()`` is also injected to passed ``$scope``. Use this method to close the dialog and ``resolve`` the promise that was returned when opening the modal. 505 | 506 | The function accepts a single optional parameter which is used as the value of the resolved promise. 507 | 508 | ```html 509 |
510 | Some message 511 | 512 | 513 |
514 | ``` 515 | 516 | #### Returns: 517 | 518 | An Angular promise object that is resolved if the ``.confirm()`` function is used to close the dialog, otherwise the promise is rejected. The resolve value and the reject reason is defined by the value passed to the ``confirm()`` or ``closeThisDialog()`` call respectively. 519 | 520 | === 521 | 522 | ### ``.isOpen(id)`` 523 | 524 | Method accepts dialog's ``id`` and returns a ``Boolean`` value indicating whether the specified dialog is open. 525 | 526 | === 527 | 528 | ### ``.close(id, value)`` 529 | 530 | Method accepts dialog's ``id`` as string argument to close specific dialog window, if ``id`` is not specified it will close all currently active modals (same behavior as ``.closeAll()``). Takes an optional value to resolve the dialog promise with (or all dialog promises). 531 | 532 | === 533 | 534 | ### ``.closeAll(value)`` 535 | 536 | Method manages closing all active modals on the page. Takes an optional value to resolve all of the dialog promises with. 537 | 538 | === 539 | 540 | ### ``.getOpenDialogs()`` 541 | 542 | Method that returns array which includes the ids of opened dialogs. 543 | 544 | === 545 | 546 | ### ``.setForceHtmlReload({Boolean})`` 547 | 548 | Adds an additional listener on every ``$locationChangeSuccess`` event and gets update version of ``html`` into dialog. May be useful in some rare cases when you're dependant on DOM changes, defaults to ``false``. Use it in module's config as provider instance: 549 | 550 | ```javascript 551 | var app = angular.module('exampleApp', ['ngDialog']); 552 | 553 | app.config(function (ngDialogProvider) { 554 | ngDialogProvider.setForceHtmlReload(true); 555 | }); 556 | ``` 557 | 558 | === 559 | 560 | ### ``.setForceBodyReload({Boolean})`` 561 | 562 | Adds additional listener on every ``$locationChangeSuccess`` event and gets updated version of ``body`` into dialog. Maybe useful in some rare cases when you're dependant on DOM changes, defaults to ``false``. Use it in module's config as provider instance: 563 | 564 | ```javascript 565 | var app = angular.module('exampleApp', ['ngDialog']); 566 | 567 | app.config(function (ngDialogProvider) { 568 | ngDialogProvider.setForceBodyReload(true); 569 | }); 570 | ``` 571 | 572 | === 573 | 574 | ### ``.setOpenOnePerName({Boolean})`` 575 | Default value: false 576 | 577 | Define whether or not opening a dialog with the same name more than once simultaneously is allowed. Assigning true prevents opening a second dialog. 578 | 579 | Setting it in the ngDialogProvider: 580 | ```javascript 581 | var app = angular.module('exampleApp', ['ngDialog']); 582 | 583 | app.config(function (ngDialogProvider) { 584 | ngDialogProvider.setOpenOnePerName(true); 585 | }); 586 | ``` 587 | 588 | Make sure to remember to add a 'name' when opening a dialog. 589 | **ngDialog 'open' and 'openConfirm' functions will return `undefined` if the dialog was not opened.** 590 | 591 | ## Directive 592 | 593 | By default the ngDialog module is served with the ``ngDialog`` directive which can be used as attribute for buttons, links, etc. Almost all ``.open()`` options are available through tag attributes as well, the only difference is that ``ng-template`` id or path of template file is required. 594 | 595 | Some imaginary button, for example, will look like: 596 | 597 | ```html 598 | 605 | ``` 606 | 607 | You could optionally use ``ng-dialog-bind-to-controller`` to bind scope you've defined via parameter of directive to controller. 608 | More information about bindToController is available [here](http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html). 609 | 610 | Directive contains one more additional but very useful option, it's an attribute named ``ng-dialog-close-previous``. It allows you to close previously opened dialogs automatically. 611 | 612 | ## Events 613 | 614 | Everytime ngDialog is opened or closed we're broadcasting three events (dispatching events downwards to all child scopes): 615 | 616 | - ``ngDialog.opened`` 617 | 618 | - ``ngDialog.closing`` 619 | 620 | - ``ngDialog.closed`` 621 | 622 | This allows you to register your own listeners, example: 623 | 624 | ```javascript 625 | $rootScope.$on('ngDialog.opened', function (e, $dialog) { 626 | console.log('ngDialog opened: ' + $dialog.attr('id')); 627 | }); 628 | ``` 629 | 630 | ``ngDialog.closing`` is different than ``ngDialog.closed`` in that it is fired immediately when the dialog begins closing, whereas ``ngDialog.closed`` is fired after all animations are complete. Both will be fired even when animation end support is not detected. 631 | 632 | Additionally we trigger following 2 events related to loading of template for dialog: 633 | 634 | - ``ngDialog.templateLoading`` 635 | 636 | - ``ngDialog.templateLoaded`` 637 | 638 | In case you are loading your templates from an external location, you could use above events to show some kind of loader. 639 | 640 | Finally, we trigger the following event when adding padding to or removing padding from the body tag to compensate for scrollbar toggling: 641 | 642 | - ``ngDialog.setPadding`` 643 | 644 | The ``ngDialog.setPadding`` event will communicate the pixel value being added to the body tag so you can add it to any other elements in your layout at the same time (often fixed-position elements will need this). 645 | 646 | 647 | ## Themes 648 | 649 | Currently _ngDialog_ contains two default themes that show how easily you can create your own. Check ``example`` folder for demonstration purposes. 650 | 651 | ## Accessibility 652 | 653 | ngDialog supports accessible keyboard navigation via the ``trapFocus`` and ``preserveFocus`` options. 654 | 655 | The ``role``, ``aria-labelledby`` and ``aria-describedby`` attributes are also supported, and are rendered as follows. 656 | 657 | Dialog ``role`` attribute: 658 | 659 | * ``options.ariaRole``, if specified 660 | * "dialog" if ``options.ariaAuto`` is ``true`` and the dialog contains any focusable elements 661 | * "alertdialog" is ``options.ariaAuto`` is ``true`` and the dialog does *not* contain any focusable elements 662 | 663 | Dialog ``aria-labelledby`` attribute: 664 | 665 | * ``options.ariaLabelledById``, if specified 666 | * If ``options.ariaLabelledBySelector`` is specified, the first matching element will be found and assigned an id (if required) and that id will be used 667 | * If ``options.ariaAuto`` is ``true``, the first heading element in the dialog (h1-6) will be found and processed as per ``ariaLabelledBySelector`` 668 | 669 | Dialog ``aria-describedby`` attribute: 670 | 671 | * ``options.ariaDescribedById``, if specified 672 | * If ``options.ariaDescribedBySelector`` is specified, the first matching element will be found and assigned an id (if required) and that id will be used 673 | * If ``options.ariaAuto`` is ``true``, the first content element in the dialog (article,section,p) will be found and processed as per ``ariaDescribedBySelector`` 674 | 675 | Dialog Content ``role`` attribute: 676 | 677 | * Always assigned a value of "document" 678 | 679 | ## CDN 680 | 681 | _ngDialog_ is available for public on [cdnjs](http://cdnjs.com/libraries/ng-dialog). For example, please use following urls for version ``0.4.0``. 682 | 683 | ```html 684 | //cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.4.0/css/ngDialog.min.css 685 | //cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.4.0/css/ngDialog-theme-default.min.css 686 | //cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.4.0/css/ngDialog-theme-plain.min.css 687 | //cdnjs.cloudflare.com/ajax/libs/ng-dialog/0.4.0/js/ngDialog.min.js 688 | ``` 689 | 690 | ## References 691 | 692 | _ngDialog_ default styles are heavily inspired by awesome [Hubspot/Vex](https://github.com/HubSpot/vex) jQuery modals. 693 | 694 | ## License 695 | 696 | MIT Licensed 697 | 698 | Copyright (c) 2013-2015, Likeastore.com 699 | 700 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 701 | 702 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 703 | 704 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 705 | 706 | [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/likeastore/ngdialog/trend.png)](https://bitdeli.com/free "Bitdeli Badge") 707 | 708 | [contributor-guidelines]: https://github.com/likeastore/ngDialog/blob/master/CONTRIBUTING.md 709 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-dialog", 3 | "homepage": "https://github.com/likeastore/ngDialog", 4 | "description": "Modal dialogs and popups provider for Angular.js applications", 5 | "main": [ 6 | "js/ngDialog.js", 7 | "css/ngDialog.css", 8 | "css/ngDialog-theme-default.css" 9 | ], 10 | "keywords": [ 11 | "angular.js", 12 | "modals", 13 | "popups", 14 | "dialog", 15 | "ng", 16 | "provider", 17 | "factory", 18 | "directive" 19 | ], 20 | "authors": [ 21 | "Dmitri Voronianski" 22 | ], 23 | "license": "MIT", 24 | "ignore": [ 25 | "**/.*", 26 | "node_modules", 27 | "bower_components", 28 | "test", 29 | "tests", 30 | "example", 31 | "css/myth", 32 | "Gruntfile.js" 33 | ], 34 | "dependencies": { 35 | "angular": ">=1.5" 36 | }, 37 | "devDependencies": { 38 | "angular-mocks": ">=1.5" 39 | }, 40 | "resolutions": { 41 | "angular": "1.6.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /css/myth/ngDialog-theme-default.css: -------------------------------------------------------------------------------- 1 | @keyframes ngdialog-flyin { 2 | 0% { 3 | opacity: 0; 4 | transform: translateY(-40px); 5 | } 6 | 7 | 100% { 8 | opacity: 1; 9 | transform: translateY(0); 10 | } 11 | } 12 | 13 | @keyframes ngdialog-flyout { 14 | 0% { 15 | opacity: 1; 16 | transform: translateY(0); 17 | } 18 | 19 | 100% { 20 | opacity: 0; 21 | transform: translateY(-40px); 22 | } 23 | } 24 | 25 | .ngdialog.ngdialog-theme-default { 26 | padding-bottom: 160px; 27 | padding-top: 160px; 28 | } 29 | 30 | .ngdialog.ngdialog-theme-default.ngdialog-closing .ngdialog-content { 31 | animation: ngdialog-flyout .5s; 32 | } 33 | 34 | .ngdialog.ngdialog-theme-default .ngdialog-content { 35 | animation: ngdialog-flyin .5s; 36 | background: #f0f0f0; 37 | border-radius: 5px; 38 | color: #444; 39 | font-family: 'Helvetica',sans-serif; 40 | font-size: 1.1em; 41 | line-height: 1.5em; 42 | margin: 0 auto; 43 | max-width: 100%; 44 | padding: 1em; 45 | position: relative; 46 | width: 450px; 47 | } 48 | 49 | .ngdialog.ngdialog-theme-default .ngdialog-close { 50 | border: none; 51 | background: transparent; 52 | cursor: pointer; 53 | position: absolute; 54 | right: 0; 55 | top: 0; 56 | } 57 | 58 | .ngdialog.ngdialog-theme-default .ngdialog-close:before { 59 | display: block; 60 | padding: 3px; 61 | background: transparent; 62 | color: #bbb; 63 | content: '\00D7'; 64 | font-size: 26px; 65 | font-weight: 400; 66 | line-height: 26px; 67 | text-align: center; 68 | } 69 | 70 | .ngdialog.ngdialog-theme-default .ngdialog-close:hover:before,.ngdialog.ngdialog-theme-default .ngdialog-close:active:before { 71 | color: #777; 72 | } 73 | 74 | .ngdialog.ngdialog-theme-default .ngdialog-message { 75 | margin-bottom: .5em; 76 | } 77 | 78 | .ngdialog.ngdialog-theme-default .ngdialog-input { 79 | margin-bottom: 1em; 80 | } 81 | 82 | .ngdialog.ngdialog-theme-default .ngdialog-input textarea,.ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"],.ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"],.ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"],.ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"] { 83 | background: #fff; 84 | border: 0; 85 | border-radius: 3px; 86 | font-family: inherit; 87 | font-size: inherit; 88 | font-weight: inherit; 89 | margin: 0 0 .25em; 90 | min-height: 2.5em; 91 | padding: .25em .67em; 92 | width: 100%; 93 | } 94 | 95 | .ngdialog.ngdialog-theme-default .ngdialog-input textarea:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"]:focus { 96 | box-shadow: inset 0 0 0 2px #8dbdf1; 97 | outline: none; 98 | } 99 | 100 | .ngdialog.ngdialog-theme-default .ngdialog-buttons { 101 | *zoom: 1; 102 | } 103 | 104 | .ngdialog.ngdialog-theme-default .ngdialog-buttons:after { 105 | content: ''; 106 | display: table; 107 | clear: both; 108 | } 109 | 110 | .ngdialog.ngdialog-theme-default .ngdialog-button { 111 | border: 0; 112 | border-radius: 3px; 113 | cursor: pointer; 114 | float: right; 115 | font-family: inherit; 116 | font-size: .8em; 117 | letter-spacing: .1em; 118 | line-height: 1em; 119 | margin: 0 0 0 .5em; 120 | padding: .75em 2em; 121 | text-transform: uppercase; 122 | } 123 | 124 | .ngdialog.ngdialog-theme-default .ngdialog-button:focus { 125 | animation: ngdialog-pulse 1.1s infinite; 126 | outline: none; 127 | } 128 | 129 | @media (max-width: 568px) { 130 | .ngdialog.ngdialog-theme-default .ngdialog-button:focus { 131 | animation: none; 132 | } 133 | } 134 | 135 | .ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-primary { 136 | background: #3288e6; 137 | color: #fff; 138 | } 139 | 140 | .ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-secondary { 141 | background: #e0e0e0; 142 | color: #777; 143 | } 144 | -------------------------------------------------------------------------------- /css/myth/ngDialog-theme-plain.css: -------------------------------------------------------------------------------- 1 | .ngdialog.ngdialog-theme-plain { 2 | padding-bottom: 160px; 3 | padding-top: 160px; 4 | } 5 | 6 | .ngdialog.ngdialog-theme-plain .ngdialog-content { 7 | background: #fff; 8 | color: #444; 9 | font-family: 'Helvetica Neue',sans-serif; 10 | font-size: 1.1em; 11 | line-height: 1.5em; 12 | margin: 0 auto; 13 | max-width: 100%; 14 | padding: 1em; 15 | position: relative; 16 | width: 450px; 17 | } 18 | 19 | .ngdialog.ngdialog-theme-plain .ngdialog-content h1,.ngdialog.ngdialog-theme-plain .ngdialog-content h2,.ngdialog.ngdialog-theme-plain .ngdialog-content h3,.ngdialog.ngdialog-theme-plain .ngdialog-content h4,.ngdialog.ngdialog-theme-plain .ngdialog-content h5,.ngdialog.ngdialog-theme-plain .ngdialog-content h6,.ngdialog.ngdialog-theme-plain .ngdialog-content p,.ngdialog.ngdialog-theme-plain .ngdialog-content ul,.ngdialog.ngdialog-theme-plain .ngdialog-content li { 20 | color: inherit; 21 | } 22 | 23 | .ngdialog.ngdialog-theme-plain .ngdialog-close { 24 | border: none; 25 | background: transparent; 26 | cursor: pointer; 27 | position: absolute; 28 | right: 0; 29 | top: 0; 30 | } 31 | 32 | .ngdialog.ngdialog-theme-plain .ngdialog-close:before { 33 | background: transparent; 34 | color: #bbb; 35 | content: "\00D7"; 36 | font-size: 26px; 37 | font-weight: 400; 38 | line-height: 26px; 39 | text-align: center; 40 | } 41 | 42 | .ngdialog.ngdialog-theme-plain .ngdialog-close:hover:before,.ngdialog.ngdialog-theme-plain .ngdialog-close:active:before { 43 | color: #777; 44 | } 45 | 46 | .ngdialog.ngdialog-theme-plain .ngdialog-message { 47 | margin-bottom: .5em; 48 | } 49 | 50 | .ngdialog.ngdialog-theme-plain .ngdialog-input { 51 | margin-bottom: 1em; 52 | } 53 | 54 | .ngdialog.ngdialog-theme-plain .ngdialog-input textarea,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="text"],.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="password"],.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="email"],.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="url"] { 55 | background: #f0f0f0; 56 | border: 0; 57 | font-family: inherit; 58 | font-size: inherit; 59 | font-weight: inherit; 60 | margin: 0 0 .25em; 61 | min-height: 2.5em; 62 | padding: .25em .67em; 63 | width: 100%; 64 | } 65 | 66 | .ngdialog.ngdialog-theme-plain .ngdialog-input textarea:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="text"]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="password"]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="email"]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type="url"]:focus { 67 | box-shadow: inset 0 0 0 2px rgba(0,0,0,0.2); 68 | outline: none; 69 | } 70 | 71 | .ngdialog.ngdialog-theme-plain .ngdialog-buttons:after { 72 | clear: both; 73 | content: ''; 74 | display: table; 75 | } 76 | 77 | .ngdialog.ngdialog-theme-plain .ngdialog-button { 78 | border: 0; 79 | cursor: pointer; 80 | float: right; 81 | font-family: inherit; 82 | font-size: .8em; 83 | letter-spacing: .1em; 84 | line-height: 1em; 85 | margin: 0 0 0 .5em; 86 | padding: .75em 2em; 87 | text-transform: uppercase; 88 | } 89 | 90 | .ngdialog.ngdialog-theme-plain .ngdialog-button:focus { 91 | animation: ngdialog-pulse 1.1s infinite; 92 | outline: none; 93 | } 94 | 95 | @media (max-width: 568px) { 96 | .ngdialog.ngdialog-theme-plain .ngdialog-button:focus { 97 | animation: none; 98 | } 99 | } 100 | 101 | .ngdialog.ngdialog-theme-plain .ngdialog-button.ngdialog-button-primary { 102 | background: #3288e6; 103 | color: #fff; 104 | } 105 | 106 | .ngdialog.ngdialog-theme-plain .ngdialog-button.ngdialog-button-secondary { 107 | background: #e0e0e0; 108 | color: #777; 109 | } 110 | -------------------------------------------------------------------------------- /css/myth/ngDialog.css: -------------------------------------------------------------------------------- 1 | @keyframes ngdialog-fadeout { 2 | 0% { 3 | opacity: 1; 4 | } 5 | 100% { 6 | opacity: 0; 7 | } 8 | } 9 | 10 | @keyframes ngdialog-fadein { 11 | 0% { 12 | opacity: 0; 13 | } 14 | 100% { 15 | opacity: 1; 16 | } 17 | } 18 | 19 | .ngdialog { 20 | box-sizing: border-box; 21 | } 22 | 23 | .ngdialog *, 24 | .ngdialog *:before, 25 | .ngdialog *:after { 26 | box-sizing: inherit; 27 | } 28 | 29 | .ngdialog { 30 | position: fixed; 31 | overflow: auto; 32 | -webkit-overflow-scrolling: touch; 33 | z-index: 10000; 34 | top: 0; 35 | right: 0; 36 | bottom: 0; 37 | left: 0; 38 | } 39 | 40 | .ngdialog.ngdialog-disabled-animation, 41 | .ngdialog.ngdialog-disabled-animation .ngdialog-overlay, 42 | .ngdialog.ngdialog-disabled-animation .ngdialog-content { 43 | animation: none!important; 44 | } 45 | 46 | .ngdialog-overlay { 47 | position: fixed; 48 | background: rgba(0, 0, 0, 0.4); 49 | top: 0; 50 | right: 0; 51 | bottom: 0; 52 | left: 0; 53 | -webkit-backface-visibility: hidden; 54 | animation: ngdialog-fadein 0.5s; 55 | } 56 | 57 | .ngdialog-no-overlay { 58 | pointer-events: none; 59 | } 60 | 61 | .ngdialog.ngdialog-closing .ngdialog-overlay { 62 | -webkit-backface-visibility: hidden; 63 | animation: ngdialog-fadeout 0.5s; 64 | } 65 | 66 | .ngdialog-content { 67 | background: white; 68 | -webkit-backface-visibility: hidden; 69 | animation: ngdialog-fadein 0.5s; 70 | pointer-events: all; 71 | } 72 | 73 | .ngdialog.ngdialog-closing .ngdialog-content { 74 | -webkit-backface-visibility: hidden; 75 | animation: ngdialog-fadeout 0.5s; 76 | } 77 | 78 | .ngdialog-close:before { 79 | font-family: 'Helvetica', Arial, sans-serif; 80 | content: '\00D7'; 81 | cursor: pointer; 82 | } 83 | 84 | html.ngdialog-open, 85 | body.ngdialog-open { 86 | overflow: hidden; 87 | } 88 | -------------------------------------------------------------------------------- /css/ngDialog-custom-width.css: -------------------------------------------------------------------------------- 1 | .ngdialog.ngdialog-theme-plain.custom-width .ngdialog-content { 2 | width: 150px; 3 | } 4 | -------------------------------------------------------------------------------- /css/ngDialog-theme-default.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes ngdialog-flyin { 2 | 0% { 3 | opacity: 0; 4 | -webkit-transform: translateY(-40px); 5 | transform: translateY(-40px); 6 | } 7 | 8 | 100% { 9 | opacity: 1; 10 | -webkit-transform: translateY(0); 11 | transform: translateY(0); 12 | } 13 | } 14 | 15 | @keyframes ngdialog-flyin { 16 | 0% { 17 | opacity: 0; 18 | -webkit-transform: translateY(-40px); 19 | transform: translateY(-40px); 20 | } 21 | 22 | 100% { 23 | opacity: 1; 24 | -webkit-transform: translateY(0); 25 | transform: translateY(0); 26 | } 27 | } 28 | 29 | @-webkit-keyframes ngdialog-flyout { 30 | 0% { 31 | opacity: 1; 32 | -webkit-transform: translateY(0); 33 | transform: translateY(0); 34 | } 35 | 36 | 100% { 37 | opacity: 0; 38 | -webkit-transform: translateY(-40px); 39 | transform: translateY(-40px); 40 | } 41 | } 42 | 43 | @keyframes ngdialog-flyout { 44 | 0% { 45 | opacity: 1; 46 | -webkit-transform: translateY(0); 47 | transform: translateY(0); 48 | } 49 | 50 | 100% { 51 | opacity: 0; 52 | -webkit-transform: translateY(-40px); 53 | transform: translateY(-40px); 54 | } 55 | } 56 | 57 | .ngdialog.ngdialog-theme-default { 58 | padding-bottom: 160px; 59 | padding-top: 160px; 60 | } 61 | 62 | .ngdialog.ngdialog-theme-default.ngdialog-closing .ngdialog-content { 63 | -webkit-animation: ngdialog-flyout .5s; 64 | animation: ngdialog-flyout .5s; 65 | } 66 | 67 | .ngdialog.ngdialog-theme-default .ngdialog-content { 68 | -webkit-animation: ngdialog-flyin .5s; 69 | animation: ngdialog-flyin .5s; 70 | background: #f0f0f0; 71 | border-radius: 5px; 72 | color: #444; 73 | font-family: 'Helvetica',sans-serif; 74 | font-size: 1.1em; 75 | line-height: 1.5em; 76 | margin: 0 auto; 77 | max-width: 100%; 78 | padding: 1em; 79 | position: relative; 80 | width: 450px; 81 | } 82 | 83 | .ngdialog.ngdialog-theme-default .ngdialog-close { 84 | border: none; 85 | background: transparent; 86 | cursor: pointer; 87 | position: absolute; 88 | right: 0; 89 | top: 0; 90 | } 91 | 92 | .ngdialog.ngdialog-theme-default .ngdialog-close:before { 93 | display: block; 94 | padding: 3px; 95 | background: transparent; 96 | color: #bbb; 97 | content: '\00D7'; 98 | font-size: 26px; 99 | font-weight: 400; 100 | line-height: 26px; 101 | text-align: center; 102 | } 103 | 104 | .ngdialog.ngdialog-theme-default .ngdialog-close:hover:before, 105 | .ngdialog.ngdialog-theme-default .ngdialog-close:active:before { 106 | color: #777; 107 | } 108 | 109 | .ngdialog.ngdialog-theme-default .ngdialog-message { 110 | margin-bottom: .5em; 111 | } 112 | 113 | .ngdialog.ngdialog-theme-default .ngdialog-input { 114 | margin-bottom: 1em; 115 | } 116 | 117 | .ngdialog.ngdialog-theme-default .ngdialog-input textarea, 118 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"], 119 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"], 120 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"], 121 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"] { 122 | background: #fff; 123 | border: 0; 124 | border-radius: 3px; 125 | font-family: inherit; 126 | font-size: inherit; 127 | font-weight: inherit; 128 | margin: 0 0 .25em; 129 | min-height: 2.5em; 130 | padding: .25em .67em; 131 | width: 100%; 132 | } 133 | 134 | .ngdialog.ngdialog-theme-default .ngdialog-input textarea:focus, 135 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"]:focus, 136 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"]:focus, 137 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"]:focus, 138 | .ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"]:focus { 139 | box-shadow: inset 0 0 0 2px #8dbdf1; 140 | outline: none; 141 | } 142 | 143 | .ngdialog.ngdialog-theme-default .ngdialog-buttons { 144 | *zoom: 1; 145 | } 146 | 147 | .ngdialog.ngdialog-theme-default .ngdialog-buttons:after { 148 | content: ''; 149 | display: table; 150 | clear: both; 151 | } 152 | 153 | .ngdialog.ngdialog-theme-default .ngdialog-button { 154 | border: 0; 155 | border-radius: 3px; 156 | cursor: pointer; 157 | float: right; 158 | font-family: inherit; 159 | font-size: .8em; 160 | letter-spacing: .1em; 161 | line-height: 1em; 162 | margin: 0 0 0 .5em; 163 | padding: .75em 2em; 164 | text-transform: uppercase; 165 | } 166 | 167 | .ngdialog.ngdialog-theme-default .ngdialog-button:focus { 168 | -webkit-animation: ngdialog-pulse 1.1s infinite; 169 | animation: ngdialog-pulse 1.1s infinite; 170 | outline: none; 171 | } 172 | 173 | @media (max-width: 568px) { 174 | .ngdialog.ngdialog-theme-default .ngdialog-button:focus { 175 | -webkit-animation: none; 176 | animation: none; 177 | } 178 | } 179 | 180 | .ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-primary { 181 | background: #3288e6; 182 | color: #fff; 183 | } 184 | 185 | .ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-secondary { 186 | background: #e0e0e0; 187 | color: #777; 188 | } -------------------------------------------------------------------------------- /css/ngDialog-theme-default.min.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes ngdialog-flyin{0%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes ngdialog-flyin{0%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@-webkit-keyframes ngdialog-flyout{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}}@keyframes ngdialog-flyout{0%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(-40px);transform:translateY(-40px)}}.ngdialog.ngdialog-theme-default{padding-bottom:160px;padding-top:160px}.ngdialog.ngdialog-theme-default.ngdialog-closing .ngdialog-content{-webkit-animation:ngdialog-flyout .5s;animation:ngdialog-flyout .5s}.ngdialog.ngdialog-theme-default .ngdialog-content{-webkit-animation:ngdialog-flyin .5s;animation:ngdialog-flyin .5s;background:#f0f0f0;border-radius:5px;color:#444;font-family:Helvetica,sans-serif;font-size:1.1em;line-height:1.5em;margin:0 auto;max-width:100%;padding:1em;position:relative;width:450px}.ngdialog.ngdialog-theme-default .ngdialog-close{border:none;background:0 0;cursor:pointer;position:absolute;right:0;top:0}.ngdialog.ngdialog-theme-default .ngdialog-close:before{display:block;padding:3px;background:0 0;color:#bbb;content:'\00D7';font-size:26px;font-weight:400;line-height:26px;text-align:center}.ngdialog.ngdialog-theme-default .ngdialog-close:active:before,.ngdialog.ngdialog-theme-default .ngdialog-close:hover:before{color:#777}.ngdialog.ngdialog-theme-default .ngdialog-message{margin-bottom:.5em}.ngdialog.ngdialog-theme-default .ngdialog-input{margin-bottom:1em}.ngdialog.ngdialog-theme-default .ngdialog-input input[type=text],.ngdialog.ngdialog-theme-default .ngdialog-input input[type=password],.ngdialog.ngdialog-theme-default .ngdialog-input input[type=email],.ngdialog.ngdialog-theme-default .ngdialog-input input[type=url],.ngdialog.ngdialog-theme-default .ngdialog-input textarea{background:#fff;border:0;border-radius:3px;font-family:inherit;font-size:inherit;font-weight:inherit;margin:0 0 .25em;min-height:2.5em;padding:.25em .67em;width:100%}.ngdialog.ngdialog-theme-default .ngdialog-input input[type=text]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type=password]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type=email]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input input[type=url]:focus,.ngdialog.ngdialog-theme-default .ngdialog-input textarea:focus{box-shadow:inset 0 0 0 2px #8dbdf1;outline:0}.ngdialog.ngdialog-theme-default .ngdialog-buttons:after{content:'';display:table;clear:both}.ngdialog.ngdialog-theme-default .ngdialog-button{border:0;border-radius:3px;cursor:pointer;float:right;font-family:inherit;font-size:.8em;letter-spacing:.1em;line-height:1em;margin:0 0 0 .5em;padding:.75em 2em;text-transform:uppercase}.ngdialog.ngdialog-theme-default .ngdialog-button:focus{-webkit-animation:ngdialog-pulse 1.1s infinite;animation:ngdialog-pulse 1.1s infinite;outline:0}@media (max-width:568px){.ngdialog.ngdialog-theme-default .ngdialog-button:focus{-webkit-animation:none;animation:none}}.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-primary{background:#3288e6;color:#fff}.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-secondary{background:#e0e0e0;color:#777} -------------------------------------------------------------------------------- /css/ngDialog-theme-plain.css: -------------------------------------------------------------------------------- 1 | .ngdialog.ngdialog-theme-plain { 2 | padding-bottom: 160px; 3 | padding-top: 160px; 4 | } 5 | 6 | .ngdialog.ngdialog-theme-plain .ngdialog-content { 7 | background: #fff; 8 | color: #444; 9 | font-family: 'Helvetica Neue',sans-serif; 10 | font-size: 1.1em; 11 | line-height: 1.5em; 12 | margin: 0 auto; 13 | max-width: 100%; 14 | padding: 1em; 15 | position: relative; 16 | width: 450px; 17 | } 18 | 19 | .ngdialog.ngdialog-theme-plain .ngdialog-content h1, 20 | .ngdialog.ngdialog-theme-plain .ngdialog-content h2, 21 | .ngdialog.ngdialog-theme-plain .ngdialog-content h3, 22 | .ngdialog.ngdialog-theme-plain .ngdialog-content h4, 23 | .ngdialog.ngdialog-theme-plain .ngdialog-content h5, 24 | .ngdialog.ngdialog-theme-plain .ngdialog-content h6, 25 | .ngdialog.ngdialog-theme-plain .ngdialog-content p, 26 | .ngdialog.ngdialog-theme-plain .ngdialog-content ul, 27 | .ngdialog.ngdialog-theme-plain .ngdialog-content li { 28 | color: inherit; 29 | } 30 | 31 | .ngdialog.ngdialog-theme-plain .ngdialog-close { 32 | border: none; 33 | background: transparent; 34 | cursor: pointer; 35 | position: absolute; 36 | right: 0; 37 | top: 0; 38 | } 39 | 40 | .ngdialog.ngdialog-theme-plain .ngdialog-close:before { 41 | background: transparent; 42 | color: #bbb; 43 | content: "\00D7"; 44 | font-size: 26px; 45 | font-weight: 400; 46 | line-height: 26px; 47 | text-align: center; 48 | } 49 | 50 | .ngdialog.ngdialog-theme-plain .ngdialog-close:hover:before, 51 | .ngdialog.ngdialog-theme-plain .ngdialog-close:active:before { 52 | color: #777; 53 | } 54 | 55 | .ngdialog.ngdialog-theme-plain .ngdialog-message { 56 | margin-bottom: .5em; 57 | } 58 | 59 | .ngdialog.ngdialog-theme-plain .ngdialog-input { 60 | margin-bottom: 1em; 61 | } 62 | 63 | .ngdialog.ngdialog-theme-plain .ngdialog-input textarea, 64 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="text"], 65 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="password"], 66 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="email"], 67 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="url"] { 68 | background: #f0f0f0; 69 | border: 0; 70 | font-family: inherit; 71 | font-size: inherit; 72 | font-weight: inherit; 73 | margin: 0 0 .25em; 74 | min-height: 2.5em; 75 | padding: .25em .67em; 76 | width: 100%; 77 | } 78 | 79 | .ngdialog.ngdialog-theme-plain .ngdialog-input textarea:focus, 80 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="text"]:focus, 81 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="password"]:focus, 82 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="email"]:focus, 83 | .ngdialog.ngdialog-theme-plain .ngdialog-input input[type="url"]:focus { 84 | box-shadow: inset 0 0 0 2px rgba(0,0,0,0.2); 85 | outline: none; 86 | } 87 | 88 | .ngdialog.ngdialog-theme-plain .ngdialog-buttons:after { 89 | clear: both; 90 | content: ''; 91 | display: table; 92 | } 93 | 94 | .ngdialog.ngdialog-theme-plain .ngdialog-button { 95 | border: 0; 96 | cursor: pointer; 97 | float: right; 98 | font-family: inherit; 99 | font-size: .8em; 100 | letter-spacing: .1em; 101 | line-height: 1em; 102 | margin: 0 0 0 .5em; 103 | padding: .75em 2em; 104 | text-transform: uppercase; 105 | } 106 | 107 | .ngdialog.ngdialog-theme-plain .ngdialog-button:focus { 108 | -webkit-animation: ngdialog-pulse 1.1s infinite; 109 | animation: ngdialog-pulse 1.1s infinite; 110 | outline: none; 111 | } 112 | 113 | @media (max-width: 568px) { 114 | .ngdialog.ngdialog-theme-plain .ngdialog-button:focus { 115 | -webkit-animation: none; 116 | animation: none; 117 | } 118 | } 119 | 120 | .ngdialog.ngdialog-theme-plain .ngdialog-button.ngdialog-button-primary { 121 | background: #3288e6; 122 | color: #fff; 123 | } 124 | 125 | .ngdialog.ngdialog-theme-plain .ngdialog-button.ngdialog-button-secondary { 126 | background: #e0e0e0; 127 | color: #777; 128 | } -------------------------------------------------------------------------------- /css/ngDialog-theme-plain.min.css: -------------------------------------------------------------------------------- 1 | .ngdialog.ngdialog-theme-plain{padding-bottom:160px;padding-top:160px}.ngdialog.ngdialog-theme-plain .ngdialog-content{background:#fff;color:#444;font-family:'Helvetica Neue',sans-serif;font-size:1.1em;line-height:1.5em;margin:0 auto;max-width:100%;padding:1em;position:relative;width:450px}.ngdialog.ngdialog-theme-plain .ngdialog-content h1,.ngdialog.ngdialog-theme-plain .ngdialog-content h2,.ngdialog.ngdialog-theme-plain .ngdialog-content h3,.ngdialog.ngdialog-theme-plain .ngdialog-content h4,.ngdialog.ngdialog-theme-plain .ngdialog-content h5,.ngdialog.ngdialog-theme-plain .ngdialog-content h6,.ngdialog.ngdialog-theme-plain .ngdialog-content li,.ngdialog.ngdialog-theme-plain .ngdialog-content p,.ngdialog.ngdialog-theme-plain .ngdialog-content ul{color:inherit}.ngdialog.ngdialog-theme-plain .ngdialog-close{border:none;background:0 0;cursor:pointer;position:absolute;right:0;top:0}.ngdialog.ngdialog-theme-plain .ngdialog-close:before{background:0 0;color:#bbb;content:"\00D7";font-size:26px;font-weight:400;line-height:26px;text-align:center}.ngdialog.ngdialog-theme-plain .ngdialog-close:active:before,.ngdialog.ngdialog-theme-plain .ngdialog-close:hover:before{color:#777}.ngdialog.ngdialog-theme-plain .ngdialog-message{margin-bottom:.5em}.ngdialog.ngdialog-theme-plain .ngdialog-input{margin-bottom:1em}.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=text],.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=password],.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=email],.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=url],.ngdialog.ngdialog-theme-plain .ngdialog-input textarea{background:#f0f0f0;border:0;font-family:inherit;font-size:inherit;font-weight:inherit;margin:0 0 .25em;min-height:2.5em;padding:.25em .67em;width:100%}.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=text]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=password]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=email]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input input[type=url]:focus,.ngdialog.ngdialog-theme-plain .ngdialog-input textarea:focus{box-shadow:inset 0 0 0 2px rgba(0,0,0,.2);outline:0}.ngdialog.ngdialog-theme-plain .ngdialog-buttons:after{clear:both;content:'';display:table}.ngdialog.ngdialog-theme-plain .ngdialog-button{border:0;cursor:pointer;float:right;font-family:inherit;font-size:.8em;letter-spacing:.1em;line-height:1em;margin:0 0 0 .5em;padding:.75em 2em;text-transform:uppercase}.ngdialog.ngdialog-theme-plain .ngdialog-button:focus{-webkit-animation:ngdialog-pulse 1.1s infinite;animation:ngdialog-pulse 1.1s infinite;outline:0}@media (max-width:568px){.ngdialog.ngdialog-theme-plain .ngdialog-button:focus{-webkit-animation:none;animation:none}}.ngdialog.ngdialog-theme-plain .ngdialog-button.ngdialog-button-primary{background:#3288e6;color:#fff}.ngdialog.ngdialog-theme-plain .ngdialog-button.ngdialog-button-secondary{background:#e0e0e0;color:#777} -------------------------------------------------------------------------------- /css/ngDialog.css: -------------------------------------------------------------------------------- 1 | @-webkit-keyframes ngdialog-fadeout { 2 | 0% { 3 | opacity: 1; 4 | } 5 | 6 | 100% { 7 | opacity: 0; 8 | } 9 | } 10 | 11 | @keyframes ngdialog-fadeout { 12 | 0% { 13 | opacity: 1; 14 | } 15 | 16 | 100% { 17 | opacity: 0; 18 | } 19 | } 20 | 21 | @-webkit-keyframes ngdialog-fadein { 22 | 0% { 23 | opacity: 0; 24 | } 25 | 26 | 100% { 27 | opacity: 1; 28 | } 29 | } 30 | 31 | @keyframes ngdialog-fadein { 32 | 0% { 33 | opacity: 0; 34 | } 35 | 36 | 100% { 37 | opacity: 1; 38 | } 39 | } 40 | 41 | .ngdialog { 42 | box-sizing: border-box; 43 | } 44 | 45 | .ngdialog *, 46 | .ngdialog *:before, 47 | .ngdialog *:after { 48 | box-sizing: inherit; 49 | } 50 | 51 | .ngdialog { 52 | position: fixed; 53 | overflow: auto; 54 | -webkit-overflow-scrolling: touch; 55 | z-index: 10000; 56 | top: 0; 57 | right: 0; 58 | bottom: 0; 59 | left: 0; 60 | /* fix for Scrollbars not clickable on overflow #552 */ 61 | background: rgba(0, 0, 0, 0.4); 62 | animation: ngdialog-fadein 0.5s; 63 | /* end fix for Scrollbars not clickable on overflow #552 */ 64 | } 65 | 66 | .ngdialog.ngdialog-disabled-animation, 67 | .ngdialog.ngdialog-disabled-animation .ngdialog-overlay, 68 | .ngdialog.ngdialog-disabled-animation .ngdialog-content { 69 | -webkit-animation: none!important; 70 | animation: none!important; 71 | } 72 | 73 | .ngdialog-overlay { 74 | position: fixed; 75 | top: 0; 76 | right: 0; 77 | bottom: 0; 78 | left: 0; 79 | -webkit-backface-visibility: hidden; 80 | -webkit-animation: ngdialog-fadein 0.5s; 81 | animation: ngdialog-fadein 0.5s; 82 | /* fix for Scrollbars not clickable on overflow #552 */ 83 | margin-right: 15px; 84 | background: transparent; 85 | /* end fix for Scrollbars not clickable on overflow #552 */ 86 | } 87 | 88 | .ngdialog-no-overlay { 89 | pointer-events: none; 90 | } 91 | 92 | .ngdialog.ngdialog-closing .ngdialog-overlay { 93 | -webkit-backface-visibility: hidden; 94 | -webkit-animation: ngdialog-fadeout 0.5s; 95 | animation: ngdialog-fadeout 0.5s; 96 | } 97 | 98 | .ngdialog-content { 99 | background: white; 100 | -webkit-backface-visibility: hidden; 101 | -webkit-animation: ngdialog-fadein 0.5s; 102 | animation: ngdialog-fadein 0.5s; 103 | pointer-events: all; 104 | } 105 | 106 | .ngdialog.ngdialog-closing .ngdialog-content { 107 | -webkit-backface-visibility: hidden; 108 | -webkit-animation: ngdialog-fadeout 0.5s; 109 | animation: ngdialog-fadeout 0.5s; 110 | } 111 | 112 | .ngdialog-close:before { 113 | font-family: 'Helvetica', Arial, sans-serif; 114 | content: '\00D7'; 115 | cursor: pointer; 116 | } 117 | 118 | html.ngdialog-open, 119 | body.ngdialog-open { 120 | overflow: hidden; 121 | } 122 | -------------------------------------------------------------------------------- /css/ngDialog.min.css: -------------------------------------------------------------------------------- 1 | .ngdialog,.ngdialog-overlay{position:fixed;top:0;right:0;bottom:0;left:0}@-webkit-keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@keyframes ngdialog-fadeout{0%{opacity:1}100%{opacity:0}}@-webkit-keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}@keyframes ngdialog-fadein{0%{opacity:0}100%{opacity:1}}.ngdialog{box-sizing:border-box;overflow:auto;-webkit-overflow-scrolling:touch;z-index:10000}.ngdialog *,.ngdialog :after,.ngdialog :before{box-sizing:inherit}.ngdialog.ngdialog-disabled-animation,.ngdialog.ngdialog-disabled-animation .ngdialog-content,.ngdialog.ngdialog-disabled-animation .ngdialog-overlay{-webkit-animation:none!important;animation:none!important}.ngdialog-overlay{background:rgba(0,0,0,.4);-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadein .5s;animation:ngdialog-fadein .5s}.ngdialog-no-overlay{pointer-events:none}.ngdialog.ngdialog-closing .ngdialog-overlay{-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadeout .5s;animation:ngdialog-fadeout .5s}.ngdialog-content{background:#fff;-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadein .5s;animation:ngdialog-fadein .5s;pointer-events:all}.ngdialog.ngdialog-closing .ngdialog-content{-webkit-backface-visibility:hidden;-webkit-animation:ngdialog-fadeout .5s;animation:ngdialog-fadeout .5s}.ngdialog-close:before{font-family:Helvetica,Arial,sans-serif;content:'\00D7';cursor:pointer}body.ngdialog-open,html.ngdialog-open{overflow:hidden} -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Usage examples 2 | 3 | ### Static file 4 | 5 | You can try ``index.html`` file simply by opening it in a browser. 6 | 7 | ### Server demo 8 | 9 | Or you can check usage of external templates by starting a web server in this folder. At first install npm dependencies from a route folder: 10 | 11 | ```bash 12 | $ ngDialog_folder: npm install 13 | ``` 14 | 15 | Then go to examples folder and start server: 16 | 17 | ```bash 18 | $ ngDialog_folder: cd example 19 | $ ngDialog_folder/example: node server.js 20 | >> IP: 172.29.63.33 21 | >> Strata web server version 0.20.1 22 | >> Listening on 0.0.0.0:1982, CTRL+C to stop 23 | ``` 24 | 25 | And check in browser url ``0.0.0.0:1982/example/index.html``. 26 | -------------------------------------------------------------------------------- /example/browser-back-button/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ngDialog demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 49 | 50 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 120 | 121 | -------------------------------------------------------------------------------- /example/browser-back-button/ui-router-1.0.0-rc.1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ngDialog demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 43 | 44 | 49 | 50 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /example/externalTemplate.html: -------------------------------------------------------------------------------- 1 |

External modal template with external scope: {{value}}

-------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngDialog demo 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 38 | 39 | 40 | 41 | 42 | 43 | Open via service 44 | 50 | Default theme 51 | Default theme without animation 52 | Plain theme 53 | Plain theme with custom width 54 | Inline controller 55 | Controller with usage of ControllerAs syntax 56 | Open with external template for modal 57 | Open with external template for modal (disabled cache) 58 | Open and use return value to close later 59 | Open and use promise to know when closed 60 | Open confirm modal 61 | Open default modal with pre-close callback inlined 62 | 70 | Open confirm modal with pre-close callback on scope 71 | Open confirm modal with pre-close inlined with nested confirm. 72 | Open without overlay 73 | Open with js specific width 74 | Open with js specific height 75 | 76 | 77 | 78 | 97 | 98 | 110 | 111 | 121 | 122 | 132 | 133 | 136 | 137 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 455 | 456 | 457 | -------------------------------------------------------------------------------- /example/inside-directive/inside-directive-plain.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | angular.module('inside-directive', []) 3 | .controller('InsideDirective', InsideDirective) 4 | 5 | InsideDirective.$inject = ['$scope']; 6 | 7 | function InsideDirective($scope) { 8 | this.$scope = $scope; 9 | } 10 | 11 | angular.module('inside-directive').directive('inside-directive-plain', exampleDirective); 12 | 13 | exampleDirective.$inject = ['$rootScope', 'ngDialog']; 14 | 15 | function exampleDirective($rootScope, ngDialog) { 16 | return { 17 | restrict: 'A', 18 | link: function(scope, element, attrs) { 19 | element.on('click', function() { 20 | scope.$dialog = ngDialog.open({ 21 | template: ' test', 22 | plain: true, 23 | controller: 'InsideDirective', 24 | className: 'inside-directive-plain', 25 | name: 'inside-directive-plain', 26 | showclose: false 27 | }); 28 | }); 29 | 30 | } 31 | }; 32 | }; 33 | 34 | })(); 35 | -------------------------------------------------------------------------------- /example/paddingTest.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ngDialog padding test 7 | 8 | 9 | 10 | 11 | 12 | 24 | 25 | 26 | 27 | 28 | 29 |
Fixed header
30 | Open dialog 31 | 32 | 33 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /example/server.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var server = require('strata'); 3 | var address = require('network-address'); 4 | 5 | var root = path.resolve('../'); 6 | 7 | server.use(server.commonLogger); 8 | server.use(server.file, root); 9 | server.run(); 10 | console.log('>> ' + address()); 11 | -------------------------------------------------------------------------------- /js/ngDialog.js: -------------------------------------------------------------------------------- 1 | /* 2 | * ngDialog - easy modals and popup windows 3 | * http://github.com/likeastore/ngDialog 4 | * (c) 2013-2015 MIT License, https://likeastore.com 5 | */ 6 | 7 | (function (root, factory) { 8 | if (typeof module !== 'undefined' && module.exports) { 9 | // CommonJS 10 | if (typeof angular === 'undefined') { 11 | factory(require('angular')); 12 | } else { 13 | factory(angular); 14 | } 15 | module.exports = 'ngDialog'; 16 | } else if (typeof define === 'function' && define.amd) { 17 | // AMD 18 | define(['angular'], factory); 19 | } else { 20 | // Global Variables 21 | factory(root.angular); 22 | } 23 | }(this, function (angular) { 24 | 'use strict'; 25 | 26 | var m = angular.module('ngDialog', []); 27 | 28 | var $el = angular.element; 29 | var isDef = angular.isDefined; 30 | var style = (document.body || document.documentElement).style; 31 | var animationEndSupport = isDef(style.animation) || isDef(style.WebkitAnimation) || isDef(style.MozAnimation) || isDef(style.MsAnimation) || isDef(style.OAnimation); 32 | var animationEndEvent = 'animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend'; 33 | var focusableElementSelector = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]'; 34 | var disabledAnimationClass = 'ngdialog-disabled-animation'; 35 | var forceElementsReload = { html: false, body: false }; 36 | var scopes = {}; 37 | var openIdStack = []; 38 | var activeBodyClasses = []; 39 | var keydownIsBound = false; 40 | var openOnePerName = false; 41 | var closeByNavigationDialogStack = []; 42 | 43 | var UI_ROUTER_VERSION_LEGACY = 'legacy'; 44 | var UI_ROUTER_VERSION_ONE_PLUS = '1.0.0+'; 45 | 46 | m.provider('ngDialog', function () { 47 | var defaults = this.defaults = { 48 | className: 'ngdialog-theme-default', 49 | appendClassName: '', 50 | disableAnimation: false, 51 | plain: false, 52 | showClose: true, 53 | closeByDocument: true, 54 | closeByEscape: true, 55 | closeByNavigation: false, 56 | appendTo: false, 57 | preCloseCallback: false, 58 | onOpenCallback: false, 59 | overlay: true, 60 | cache: true, 61 | trapFocus: true, 62 | preserveFocus: true, 63 | ariaAuto: true, 64 | ariaRole: null, 65 | ariaLabelledById: null, 66 | ariaLabelledBySelector: null, 67 | ariaDescribedById: null, 68 | ariaDescribedBySelector: null, 69 | bodyClassName: 'ngdialog-open', 70 | width: null, 71 | height: null 72 | }; 73 | 74 | this.setForceHtmlReload = function (_useIt) { 75 | forceElementsReload.html = _useIt || false; 76 | }; 77 | 78 | this.setForceBodyReload = function (_useIt) { 79 | forceElementsReload.body = _useIt || false; 80 | }; 81 | 82 | this.setDefaults = function (newDefaults) { 83 | angular.extend(defaults, newDefaults); 84 | }; 85 | 86 | this.setOpenOnePerName = function (isOpenOne) { 87 | openOnePerName = isOpenOne || false; 88 | }; 89 | 90 | var globalID = 0, dialogsCount = 0, closeByDocumentHandler, defers = {}; 91 | 92 | this.$get = ['$document', '$templateCache', '$compile', '$q', '$http', '$rootScope', '$timeout', '$window', '$controller', '$injector', 93 | function ($document, $templateCache, $compile, $q, $http, $rootScope, $timeout, $window, $controller, $injector) { 94 | var $elements = []; 95 | 96 | var privateMethods = { 97 | onDocumentKeydown: function (event) { 98 | if (event.keyCode === 27) { 99 | publicMethods.close('$escape'); 100 | } 101 | }, 102 | 103 | activate: function($dialog) { 104 | var options = $dialog.data('$ngDialogOptions'); 105 | 106 | if (options.trapFocus) { 107 | $dialog.on('keydown', privateMethods.onTrapFocusKeydown); 108 | 109 | // Catch rogue changes (eg. after unfocusing everything by clicking a non-focusable element) 110 | $elements.body.on('keydown', privateMethods.onTrapFocusKeydown); 111 | } 112 | }, 113 | 114 | deactivate: function ($dialog) { 115 | $dialog.off('keydown', privateMethods.onTrapFocusKeydown); 116 | $elements.body.off('keydown', privateMethods.onTrapFocusKeydown); 117 | }, 118 | 119 | deactivateAll: function (els) { 120 | angular.forEach(els,function(el) { 121 | var $dialog = angular.element(el); 122 | privateMethods.deactivate($dialog); 123 | }); 124 | }, 125 | 126 | setBodyPadding: function (width) { 127 | var originalBodyPadding = parseInt(($elements.body.css('padding-right') || 0), 10); 128 | $elements.body.css('padding-right', (originalBodyPadding + width) + 'px'); 129 | $elements.body.data('ng-dialog-original-padding', originalBodyPadding); 130 | $rootScope.$broadcast('ngDialog.setPadding', width); 131 | }, 132 | 133 | resetBodyPadding: function () { 134 | var originalBodyPadding = $elements.body.data('ng-dialog-original-padding'); 135 | if (originalBodyPadding) { 136 | $elements.body.css('padding-right', originalBodyPadding + 'px'); 137 | } else { 138 | $elements.body.css('padding-right', ''); 139 | } 140 | $rootScope.$broadcast('ngDialog.setPadding', 0); 141 | }, 142 | 143 | performCloseDialog: function ($dialog, value) { 144 | var options = $dialog.data('$ngDialogOptions'); 145 | var id = $dialog.attr('id'); 146 | var scope = scopes[id]; 147 | privateMethods.deactivate($dialog); 148 | 149 | if (!scope) { 150 | // Already closed 151 | return; 152 | } 153 | 154 | if (typeof $window.Hammer !== 'undefined') { 155 | var hammerTime = scope.hammerTime; 156 | hammerTime.off('tap', closeByDocumentHandler); 157 | hammerTime.destroy && hammerTime.destroy(); 158 | delete scope.hammerTime; 159 | } else { 160 | $dialog.unbind('click'); 161 | } 162 | 163 | if (dialogsCount === 1) { 164 | $elements.body.unbind('keydown', privateMethods.onDocumentKeydown); 165 | } 166 | 167 | if (!$dialog.hasClass('ngdialog-closing')){ 168 | dialogsCount -= 1; 169 | } 170 | 171 | var previousFocus = $dialog.data('$ngDialogPreviousFocus'); 172 | if (previousFocus && previousFocus.focus) { 173 | previousFocus.focus(); 174 | } 175 | 176 | $rootScope.$broadcast('ngDialog.closing', $dialog, value); 177 | dialogsCount = dialogsCount < 0 ? 0 : dialogsCount; 178 | if (animationEndSupport && !options.disableAnimation) { 179 | scope.$destroy(); 180 | $dialog.unbind(animationEndEvent).bind(animationEndEvent, function () { 181 | privateMethods.closeDialogElement($dialog, value); 182 | }).addClass('ngdialog-closing'); 183 | } else { 184 | scope.$destroy(); 185 | privateMethods.closeDialogElement($dialog, value); 186 | } 187 | if (defers[id]) { 188 | defers[id].resolve({ 189 | id: id, 190 | value: value, 191 | $dialog: $dialog, 192 | remainingDialogs: dialogsCount 193 | }); 194 | delete defers[id]; 195 | } 196 | if (scopes[id]) { 197 | delete scopes[id]; 198 | } 199 | openIdStack.splice(openIdStack.indexOf(id), 1); 200 | if (!openIdStack.length) { 201 | $elements.body.unbind('keydown', privateMethods.onDocumentKeydown); 202 | keydownIsBound = false; 203 | } 204 | 205 | if (dialogsCount == 0) 206 | { 207 | closeByDocumentHandler = undefined; 208 | } 209 | }, 210 | 211 | closeDialogElement: function($dialog, value) { 212 | var options = $dialog.data('$ngDialogOptions'); 213 | $dialog.remove(); 214 | 215 | activeBodyClasses.splice(activeBodyClasses.indexOf(options.bodyClassName), 1); 216 | if (activeBodyClasses.indexOf(options.bodyClassName) === -1) { 217 | $elements.html.removeClass(options.bodyClassName); 218 | $elements.body.removeClass(options.bodyClassName); 219 | } 220 | 221 | if (dialogsCount === 0) { 222 | privateMethods.resetBodyPadding(); 223 | } 224 | 225 | $rootScope.$broadcast('ngDialog.closed', $dialog, value); 226 | }, 227 | 228 | closeDialog: function ($dialog, value) { 229 | var preCloseCallback = $dialog.data('$ngDialogPreCloseCallback'); 230 | 231 | if (preCloseCallback && angular.isFunction(preCloseCallback)) { 232 | 233 | var preCloseCallbackResult = preCloseCallback.call($dialog, value); 234 | 235 | if (angular.isObject(preCloseCallbackResult)) { 236 | if (preCloseCallbackResult.closePromise) { 237 | preCloseCallbackResult.closePromise.then(function () { 238 | privateMethods.performCloseDialog($dialog, value); 239 | }, function () { 240 | return false; 241 | }); 242 | } else { 243 | preCloseCallbackResult.then(function () { 244 | privateMethods.performCloseDialog($dialog, value); 245 | }, function () { 246 | return false; 247 | }); 248 | } 249 | } else if (preCloseCallbackResult !== false) { 250 | privateMethods.performCloseDialog($dialog, value); 251 | } else { 252 | return false; 253 | } 254 | } else { 255 | privateMethods.performCloseDialog($dialog, value); 256 | } 257 | }, 258 | 259 | onTrapFocusKeydown: function(ev) { 260 | var el = angular.element(ev.currentTarget); 261 | var $dialog; 262 | 263 | if (el.hasClass('ngdialog')) { 264 | $dialog = el; 265 | } else { 266 | $dialog = privateMethods.getActiveDialog(); 267 | 268 | if ($dialog === null) { 269 | return; 270 | } 271 | } 272 | 273 | var isTab = (ev.keyCode === 9); 274 | var backward = (ev.shiftKey === true); 275 | 276 | if (isTab) { 277 | privateMethods.handleTab($dialog, ev, backward); 278 | } 279 | }, 280 | 281 | handleTab: function($dialog, ev, backward) { 282 | var focusableElements = privateMethods.getFocusableElements($dialog); 283 | 284 | if (focusableElements.length === 0) { 285 | if (document.activeElement && document.activeElement.blur) { 286 | document.activeElement.blur(); 287 | } 288 | return; 289 | } 290 | 291 | var currentFocus = document.activeElement; 292 | var focusIndex = Array.prototype.indexOf.call(focusableElements, currentFocus); 293 | 294 | var isFocusIndexUnknown = (focusIndex === -1); 295 | var isFirstElementFocused = (focusIndex === 0); 296 | var isLastElementFocused = (focusIndex === focusableElements.length - 1); 297 | 298 | var cancelEvent = false; 299 | 300 | if (backward) { 301 | if (isFocusIndexUnknown || isFirstElementFocused) { 302 | focusableElements[focusableElements.length - 1].focus(); 303 | cancelEvent = true; 304 | } 305 | } else { 306 | if (isFocusIndexUnknown || isLastElementFocused) { 307 | focusableElements[0].focus(); 308 | cancelEvent = true; 309 | } 310 | } 311 | 312 | if (cancelEvent) { 313 | ev.preventDefault(); 314 | ev.stopPropagation(); 315 | } 316 | }, 317 | 318 | autoFocus: function($dialog) { 319 | var dialogEl = $dialog[0]; 320 | 321 | // Browser's (Chrome 40, Forefix 37, IE 11) don't appear to honor autofocus on the dialog, but we should 322 | var autoFocusEl = dialogEl.querySelector('*[autofocus]'); 323 | if (autoFocusEl !== null) { 324 | autoFocusEl.focus(); 325 | 326 | if (document.activeElement === autoFocusEl) { 327 | return; 328 | } 329 | 330 | // Autofocus element might was display: none, so let's continue 331 | } 332 | 333 | var focusableElements = privateMethods.getFocusableElements($dialog); 334 | 335 | if (focusableElements.length > 0) { 336 | focusableElements[0].focus(); 337 | return; 338 | } 339 | 340 | // We need to focus something for the screen readers to notice the dialog 341 | var contentElements = privateMethods.filterVisibleElements(dialogEl.querySelectorAll('h1,h2,h3,h4,h5,h6,p,span')); 342 | 343 | if (contentElements.length > 0) { 344 | var contentElement = contentElements[0]; 345 | $el(contentElement).attr('tabindex', '-1').css('outline', '0'); 346 | contentElement.focus(); 347 | } 348 | }, 349 | 350 | getFocusableElements: function ($dialog) { 351 | var dialogEl = $dialog[0]; 352 | 353 | var rawElements = dialogEl.querySelectorAll(focusableElementSelector); 354 | 355 | // Ignore untabbable elements, ie. those with tabindex = -1 356 | var tabbableElements = privateMethods.filterTabbableElements(rawElements); 357 | 358 | return privateMethods.filterVisibleElements(tabbableElements); 359 | }, 360 | 361 | filterTabbableElements: function (els) { 362 | var tabbableFocusableElements = []; 363 | 364 | for (var i = 0; i < els.length; i++) { 365 | var el = els[i]; 366 | 367 | if ($el(el).attr('tabindex') !== '-1') { 368 | tabbableFocusableElements.push(el); 369 | } 370 | } 371 | 372 | return tabbableFocusableElements; 373 | }, 374 | 375 | filterVisibleElements: function (els) { 376 | var visibleFocusableElements = []; 377 | 378 | for (var i = 0; i < els.length; i++) { 379 | var el = els[i]; 380 | 381 | if (el.offsetWidth > 0 || el.offsetHeight > 0) { 382 | visibleFocusableElements.push(el); 383 | } 384 | } 385 | 386 | return visibleFocusableElements; 387 | }, 388 | 389 | getActiveDialog: function () { 390 | var dialogs = document.querySelectorAll('.ngdialog'); 391 | 392 | if (dialogs.length === 0) { 393 | return null; 394 | } 395 | 396 | // TODO: This might be incorrect if there are a mix of open dialogs with different 'appendTo' values 397 | return $el(dialogs[dialogs.length - 1]); 398 | }, 399 | 400 | applyAriaAttributes: function ($dialog, options) { 401 | if (options.ariaAuto) { 402 | if (!options.ariaRole) { 403 | var detectedRole = (privateMethods.getFocusableElements($dialog).length > 0) ? 404 | 'dialog' : 405 | 'alertdialog'; 406 | 407 | options.ariaRole = detectedRole; 408 | } 409 | 410 | if (!options.ariaLabelledBySelector) { 411 | options.ariaLabelledBySelector = 'h1,h2,h3,h4,h5,h6'; 412 | } 413 | 414 | if (!options.ariaDescribedBySelector) { 415 | options.ariaDescribedBySelector = 'article,section,p'; 416 | } 417 | } 418 | 419 | if (options.ariaRole) { 420 | $dialog.attr('role', options.ariaRole); 421 | } 422 | 423 | privateMethods.applyAriaAttribute( 424 | $dialog, 'aria-labelledby', options.ariaLabelledById, options.ariaLabelledBySelector); 425 | 426 | privateMethods.applyAriaAttribute( 427 | $dialog, 'aria-describedby', options.ariaDescribedById, options.ariaDescribedBySelector); 428 | }, 429 | 430 | applyAriaAttribute: function($dialog, attr, id, selector) { 431 | if (id) { 432 | $dialog.attr(attr, id); 433 | return; 434 | } 435 | 436 | if (selector) { 437 | var dialogId = $dialog.attr('id'); 438 | 439 | var firstMatch = $dialog[0].querySelector(selector); 440 | 441 | if (!firstMatch) { 442 | return; 443 | } 444 | 445 | var generatedId = dialogId + '-' + attr; 446 | 447 | $el(firstMatch).attr('id', generatedId); 448 | 449 | $dialog.attr(attr, generatedId); 450 | 451 | return generatedId; 452 | } 453 | }, 454 | 455 | detectUIRouter: function() { 456 | // Detect if ui-router module is installed 457 | // Returns ui-router version string if installed 458 | // Otherwise false 459 | 460 | if ($injector.has('$transitions')) { 461 | // Only 1.0.0+ ui.router allows us to inject $transitions 462 | return UI_ROUTER_VERSION_ONE_PLUS; 463 | } 464 | else if ($injector.has('$state')) { 465 | // The legacy ui.router allows us to inject $state 466 | return UI_ROUTER_VERSION_LEGACY; 467 | } 468 | return false; 469 | }, 470 | 471 | getRouterLocationEventName: function() { 472 | if (privateMethods.detectUIRouter()) { 473 | return '$stateChangeStart'; 474 | } 475 | return '$locationChangeStart'; 476 | } 477 | }; 478 | 479 | var publicMethods = { 480 | __PRIVATE__: privateMethods, 481 | 482 | /* 483 | * @param {Object} options: 484 | * - template {String} - id of ng-template, url for partial, plain string (if enabled) 485 | * - plain {Boolean} - enable plain string templates, default false 486 | * - scope {Object} 487 | * - controller {String} 488 | * - controllerAs {String} 489 | * - className {String} - dialog theme class 490 | * - appendClassName {String} - dialog theme class to be appended to defaults 491 | * - disableAnimation {Boolean} - set to true to disable animation 492 | * - showClose {Boolean} - show close button, default true 493 | * - closeByEscape {Boolean} - default true 494 | * - closeByDocument {Boolean} - default true 495 | * - preCloseCallback {String|Function} - user supplied function name/function called before closing dialog (if set) 496 | * - onOpenCallback {String|Function} - user supplied function name/function called after opening dialog (if set) 497 | * - bodyClassName {String} - class added to body at open dialog 498 | * @return {Object} dialog 499 | */ 500 | open: function (opts) { 501 | var dialogID = null; 502 | opts = opts || {}; 503 | if (openOnePerName && opts.name) { 504 | dialogID = opts.name.toLowerCase().replace(/\s/g, '-') + '-dialog'; 505 | if (this.isOpen(dialogID)) { 506 | return; 507 | } 508 | } 509 | var options = angular.copy(defaults); 510 | var localID = ++globalID; 511 | dialogID = dialogID || 'ngdialog' + localID; 512 | openIdStack.push(dialogID); 513 | 514 | // Merge opts.data with predefined via setDefaults 515 | if (typeof options.data !== 'undefined') { 516 | if (typeof opts.data === 'undefined') { 517 | opts.data = {}; 518 | } 519 | opts.data = angular.merge(angular.copy(options.data), opts.data); 520 | } 521 | 522 | angular.extend(options, opts); 523 | 524 | var defer; 525 | defers[dialogID] = defer = $q.defer(); 526 | 527 | var scope; 528 | scopes[dialogID] = scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new(); 529 | 530 | var $dialog, $dialogParent, $dialogContent; 531 | 532 | var resolve = angular.extend({}, options.resolve); 533 | 534 | angular.forEach(resolve, function (value, key) { 535 | resolve[key] = angular.isString(value) ? $injector.get(value) : $injector.invoke(value, null, null, key); 536 | }); 537 | 538 | $q.all({ 539 | template: loadTemplate(options.template || options.templateUrl), 540 | locals: $q.all(resolve) 541 | }).then(function (setup) { 542 | var template = setup.template, 543 | locals = setup.locals; 544 | 545 | if (options.showClose) { 546 | template += ''; 547 | } 548 | 549 | var hasOverlayClass = options.overlay ? '' : ' ngdialog-no-overlay'; 550 | $dialog = $el('
'); 551 | $dialog.html((options.overlay ? 552 | '
' + template + '
' : 553 | '
' + template + '
')); 554 | 555 | $dialog.data('$ngDialogOptions', options); 556 | 557 | scope.ngDialogId = dialogID; 558 | 559 | if (options.data && angular.isString(options.data)) { 560 | var firstLetter = options.data.replace(/^\s*/, '')[0]; 561 | scope.ngDialogData = (firstLetter === '{' || firstLetter === '[') ? angular.fromJson(options.data) : new String(options.data); 562 | scope.ngDialogData.ngDialogId = dialogID; 563 | } else if (options.data && angular.isObject(options.data)) { 564 | scope.ngDialogData = options.data; 565 | scope.ngDialogData.ngDialogId = dialogID; 566 | } 567 | 568 | if (options.className) { 569 | $dialog.addClass(options.className); 570 | } 571 | 572 | if (options.appendClassName) { 573 | $dialog.addClass(options.appendClassName); 574 | } 575 | 576 | if (options.width) { 577 | $dialogContent = $dialog[0].querySelector('.ngdialog-content'); 578 | if (angular.isString(options.width)) { 579 | $dialogContent.style.width = options.width; 580 | } else { 581 | $dialogContent.style.width = options.width + 'px'; 582 | } 583 | } 584 | 585 | if (options.height) { 586 | $dialogContent = $dialog[0].querySelector('.ngdialog-content'); 587 | if (angular.isString(options.height)) { 588 | $dialogContent.style.height = options.height; 589 | } else { 590 | $dialogContent.style.height = options.height + 'px'; 591 | } 592 | } 593 | 594 | if (options.disableAnimation) { 595 | $dialog.addClass(disabledAnimationClass); 596 | } 597 | 598 | if (options.appendTo && angular.isString(options.appendTo)) { 599 | $dialogParent = angular.element(document.querySelector(options.appendTo)); 600 | } else { 601 | $dialogParent = $elements.body; 602 | } 603 | 604 | privateMethods.applyAriaAttributes($dialog, options); 605 | 606 | [ 607 | { name: '$ngDialogPreCloseCallback', value: options.preCloseCallback }, 608 | { name: '$ngDialogOnOpenCallback', value: options.onOpenCallback } 609 | ].forEach(function (option) { 610 | if (option.value) { 611 | var callback; 612 | 613 | if (angular.isFunction(option.value)) { 614 | callback = option.value; 615 | } else if (angular.isString(option.value)) { 616 | if (scope) { 617 | if (angular.isFunction(scope[option.value])) { 618 | callback = scope[option.value]; 619 | } else if (scope.$parent && angular.isFunction(scope.$parent[option.value])) { 620 | callback = scope.$parent[option.value]; 621 | } else if ($rootScope && angular.isFunction($rootScope[option.value])) { 622 | callback = $rootScope[option.value]; 623 | } 624 | } 625 | } 626 | 627 | if (callback) { 628 | $dialog.data(option.name, callback); 629 | } 630 | } 631 | }); 632 | 633 | scope.closeThisDialog = function (value) { 634 | privateMethods.closeDialog($dialog, value); 635 | }; 636 | 637 | if (options.controller && (angular.isString(options.controller) || angular.isArray(options.controller) || angular.isFunction(options.controller))) { 638 | 639 | var label; 640 | 641 | if (options.controllerAs && angular.isString(options.controllerAs)) { 642 | label = options.controllerAs; 643 | } 644 | 645 | var controllerInstance = $controller(options.controller, angular.extend( 646 | locals, 647 | { 648 | $scope: scope, 649 | $element: $dialog 650 | }), 651 | true, 652 | label 653 | ); 654 | 655 | if(options.bindToController) { 656 | angular.extend(controllerInstance.instance, {ngDialogId: scope.ngDialogId, ngDialogData: scope.ngDialogData, closeThisDialog: scope.closeThisDialog, confirm: scope.confirm}); 657 | } 658 | 659 | if(typeof controllerInstance === 'function'){ 660 | $dialog.data('$ngDialogControllerController', controllerInstance()); 661 | } else { 662 | $dialog.data('$ngDialogControllerController', controllerInstance); 663 | } 664 | } 665 | 666 | $timeout(function () { 667 | var $activeDialogs = document.querySelectorAll('.ngdialog'); 668 | privateMethods.deactivateAll($activeDialogs); 669 | 670 | $compile($dialog)(scope); 671 | var widthDiffs = $window.innerWidth - $elements.body.prop('clientWidth'); 672 | $elements.html.addClass(options.bodyClassName); 673 | $elements.body.addClass(options.bodyClassName); 674 | activeBodyClasses.push(options.bodyClassName); 675 | var scrollBarWidth = widthDiffs - ($window.innerWidth - $elements.body.prop('clientWidth')); 676 | if (scrollBarWidth > 0) { 677 | privateMethods.setBodyPadding(scrollBarWidth); 678 | } 679 | $dialogParent.append($dialog); 680 | 681 | privateMethods.activate($dialog); 682 | 683 | if (options.trapFocus) { 684 | privateMethods.autoFocus($dialog); 685 | } 686 | 687 | if (options.name) { 688 | $rootScope.$broadcast('ngDialog.opened', {dialog: $dialog, name: options.name}); 689 | } else { 690 | $rootScope.$broadcast('ngDialog.opened', $dialog); 691 | } 692 | var onOpenCallback = $dialog.data('$ngDialogOnOpenCallback'); 693 | if (onOpenCallback && angular.isFunction(onOpenCallback)) { 694 | onOpenCallback.call($dialog); 695 | } 696 | 697 | }); 698 | 699 | if (!keydownIsBound) { 700 | $elements.body.bind('keydown', privateMethods.onDocumentKeydown); 701 | keydownIsBound = true; 702 | } 703 | 704 | if (options.closeByNavigation) { 705 | closeByNavigationDialogStack.push($dialog); 706 | } 707 | 708 | if (options.preserveFocus) { 709 | $dialog.data('$ngDialogPreviousFocus', document.activeElement); 710 | } 711 | 712 | closeByDocumentHandler = function (event) { 713 | var isOverlay = options.closeByDocument ? $el(event.target).hasClass('ngdialog-overlay') : false; 714 | var isCloseBtn = $el(event.target).hasClass('ngdialog-close'); 715 | 716 | if (isOverlay || isCloseBtn) { 717 | publicMethods.close($dialog.attr('id'), isCloseBtn ? '$closeButton' : '$document'); 718 | } 719 | }; 720 | 721 | if (typeof $window.Hammer !== 'undefined') { 722 | var hammerTime = scope.hammerTime = $window.Hammer($dialog[0]); 723 | hammerTime.on('tap', closeByDocumentHandler); 724 | } else { 725 | $dialog.bind('click', closeByDocumentHandler); 726 | } 727 | 728 | dialogsCount += 1; 729 | 730 | return publicMethods; 731 | }); 732 | 733 | return { 734 | id: dialogID, 735 | closePromise: defer.promise, 736 | close: function (value) { 737 | privateMethods.closeDialog($dialog, value); 738 | } 739 | }; 740 | 741 | function loadTemplateUrl (tmpl, config) { 742 | var config = config || {}; 743 | config.headers = config.headers || {}; 744 | 745 | angular.extend(config.headers, {'Accept': 'text/html'}); 746 | 747 | $rootScope.$broadcast('ngDialog.templateLoading', tmpl); 748 | return $http.get(tmpl, config).then(function(res) { 749 | $rootScope.$broadcast('ngDialog.templateLoaded', tmpl); 750 | return res.data || ''; 751 | }); 752 | } 753 | 754 | function loadTemplate (tmpl) { 755 | if (!tmpl) { 756 | return 'Empty template'; 757 | } 758 | 759 | if (angular.isString(tmpl) && options.plain) { 760 | return tmpl; 761 | } 762 | 763 | if (typeof options.cache === 'boolean' && !options.cache) { 764 | return loadTemplateUrl(tmpl, {cache: false}); 765 | } 766 | 767 | return loadTemplateUrl(tmpl, {cache: $templateCache}); 768 | } 769 | }, 770 | 771 | /* 772 | * @param {Object} options: 773 | * - template {String} - id of ng-template, url for partial, plain string (if enabled) 774 | * - plain {Boolean} - enable plain string templates, default false 775 | * - name {String} 776 | * - scope {Object} 777 | * - controller {String} 778 | * - controllerAs {String} 779 | * - className {String} - dialog theme class 780 | * - appendClassName {String} - dialog theme class to be appended to defaults 781 | * - showClose {Boolean} - show close button, default true 782 | * - closeByEscape {Boolean} - default false 783 | * - closeByDocument {Boolean} - default false 784 | * - preCloseCallback {String|Function} - user supplied function name/function called before closing dialog (if set); not called on confirm 785 | * - bodyClassName {String} - class added to body at open dialog 786 | * 787 | * @return {Object} dialog 788 | */ 789 | openConfirm: function (opts) { 790 | var defer = $q.defer(); 791 | var options = angular.copy(defaults); 792 | 793 | opts = opts || {}; 794 | 795 | // Merge opts.data with predefined via setDefaults 796 | if (typeof options.data !== 'undefined') { 797 | if (typeof opts.data === 'undefined') { 798 | opts.data = {}; 799 | } 800 | opts.data = angular.merge(angular.copy(options.data), opts.data); 801 | } 802 | 803 | angular.extend(options, opts); 804 | 805 | options.scope = angular.isObject(options.scope) ? options.scope.$new() : $rootScope.$new(); 806 | options.scope.confirm = function (value) { 807 | defer.resolve(value); 808 | var $dialog = $el(document.getElementById(openResult.id)); 809 | privateMethods.performCloseDialog($dialog, value); 810 | }; 811 | 812 | var openResult = publicMethods.open(options); 813 | if (openResult) { 814 | openResult.closePromise.then(function (data) { 815 | if (data) { 816 | return defer.reject(data.value); 817 | } 818 | return defer.reject(); 819 | }); 820 | return defer.promise; 821 | } 822 | }, 823 | 824 | isOpen: function(id) { 825 | var $dialog = $el(document.getElementById(id)); 826 | return $dialog.length > 0; 827 | }, 828 | 829 | /* 830 | * @param {String} id 831 | * @return {Object} dialog 832 | */ 833 | close: function (id, value) { 834 | var $dialog = $el(document.getElementById(id)); 835 | 836 | if ($dialog.length) { 837 | privateMethods.closeDialog($dialog, value); 838 | } else { 839 | if (id === '$escape') { 840 | var topDialogId = openIdStack[openIdStack.length - 1]; 841 | $dialog = $el(document.getElementById(topDialogId)); 842 | if ($dialog.data('$ngDialogOptions').closeByEscape) { 843 | privateMethods.closeDialog($dialog, '$escape'); 844 | } 845 | } else { 846 | publicMethods.closeAll(value); 847 | } 848 | } 849 | 850 | return publicMethods; 851 | }, 852 | 853 | closeAll: function (value) { 854 | var $all = document.querySelectorAll('.ngdialog'); 855 | 856 | // Reverse order to ensure focus restoration works as expected 857 | for (var i = $all.length - 1; i >= 0; i--) { 858 | var dialog = $all[i]; 859 | privateMethods.closeDialog($el(dialog), value); 860 | } 861 | }, 862 | 863 | getOpenDialogs: function() { 864 | return openIdStack; 865 | }, 866 | 867 | getDefaults: function () { 868 | return defaults; 869 | } 870 | }; 871 | 872 | angular.forEach( 873 | ['html', 'body'], 874 | function(elementName) { 875 | $elements[elementName] = $document.find(elementName); 876 | if (forceElementsReload[elementName]) { 877 | var eventName = privateMethods.getRouterLocationEventName(); 878 | $rootScope.$on(eventName, function () { 879 | $elements[elementName] = $document.find(elementName); 880 | }); 881 | } 882 | } 883 | ); 884 | 885 | // Listen to navigation events to close dialog 886 | var uiRouterVersion = privateMethods.detectUIRouter(); 887 | if (uiRouterVersion === UI_ROUTER_VERSION_ONE_PLUS) { 888 | var $transitions = $injector.get('$transitions'); 889 | $transitions.onStart({}, function (trans) { 890 | while (closeByNavigationDialogStack.length > 0) { 891 | var toCloseDialog = closeByNavigationDialogStack.pop(); 892 | if (privateMethods.closeDialog(toCloseDialog) === false) { 893 | return false; 894 | } 895 | } 896 | }); 897 | } 898 | else { 899 | var eventName = uiRouterVersion === UI_ROUTER_VERSION_LEGACY ? '$stateChangeStart' : '$locationChangeStart'; 900 | $rootScope.$on(eventName, function ($event) { 901 | while (closeByNavigationDialogStack.length > 0) { 902 | var toCloseDialog = closeByNavigationDialogStack.pop(); 903 | if (privateMethods.closeDialog(toCloseDialog) === false) { 904 | $event.preventDefault(); 905 | } 906 | } 907 | }); 908 | } 909 | 910 | return publicMethods; 911 | }]; 912 | }); 913 | 914 | m.directive('ngDialog', ['ngDialog', function (ngDialog) { 915 | return { 916 | restrict: 'A', 917 | scope: { 918 | ngDialogScope: '=' 919 | }, 920 | link: function (scope, elem, attrs) { 921 | elem.on('click', function (e) { 922 | e.preventDefault(); 923 | 924 | var ngDialogScope = angular.isDefined(scope.ngDialogScope) ? scope.ngDialogScope : 'noScope'; 925 | angular.isDefined(attrs.ngDialogClosePrevious) && ngDialog.close(attrs.ngDialogClosePrevious); 926 | 927 | var defaults = ngDialog.getDefaults(); 928 | 929 | ngDialog.open({ 930 | template: attrs.ngDialog, 931 | className: attrs.ngDialogClass || defaults.className, 932 | appendClassName: attrs.ngDialogAppendClass, 933 | controller: attrs.ngDialogController, 934 | controllerAs: attrs.ngDialogControllerAs, 935 | bindToController: attrs.ngDialogBindToController, 936 | disableAnimation: attrs.ngDialogDisableAnimation, 937 | scope: ngDialogScope, 938 | data: attrs.ngDialogData, 939 | showClose: attrs.ngDialogShowClose === 'false' ? false : (attrs.ngDialogShowClose === 'true' ? true : defaults.showClose), 940 | closeByDocument: attrs.ngDialogCloseByDocument === 'false' ? false : (attrs.ngDialogCloseByDocument === 'true' ? true : defaults.closeByDocument), 941 | closeByEscape: attrs.ngDialogCloseByEscape === 'false' ? false : (attrs.ngDialogCloseByEscape === 'true' ? true : defaults.closeByEscape), 942 | overlay: attrs.ngDialogOverlay === 'false' ? false : (attrs.ngDialogOverlay === 'true' ? true : defaults.overlay), 943 | preCloseCallback: attrs.ngDialogPreCloseCallback || defaults.preCloseCallback, 944 | onOpenCallback: attrs.ngDialogOnOpenCallback || defaults.onOpenCallback, 945 | bodyClassName: attrs.ngDialogBodyClass || defaults.bodyClassName 946 | }); 947 | }); 948 | } 949 | }; 950 | }]); 951 | 952 | return m; 953 | })); 954 | -------------------------------------------------------------------------------- /js/ngDialog.min.js: -------------------------------------------------------------------------------- 1 | /*! ng-dialog - v1.2.0 (https://github.com/likeastore/ngDialog) */ 2 | !function(a,b){"undefined"!=typeof module&&module.exports?(b("undefined"==typeof angular?require("angular"):angular),module.exports="ngDialog"):"function"==typeof define&&define.amd?define(["angular"],b):b(a.angular)}(this,function(a){"use strict";var b=a.module("ngDialog",[]),c=a.element,d=a.isDefined,e=(document.body||document.documentElement).style,f=d(e.animation)||d(e.WebkitAnimation)||d(e.MozAnimation)||d(e.MsAnimation)||d(e.OAnimation),g="animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend",h="a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]",i="ngdialog-disabled-animation",j={html:!1,body:!1},k={},l=[],m=[],n=!1,o=!1,p=[],q="legacy",r="1.0.0+";return b.provider("ngDialog",function(){var b=this.defaults={className:"ngdialog-theme-default",appendClassName:"",disableAnimation:!1,plain:!1,showClose:!0,closeByDocument:!0,closeByEscape:!0,closeByNavigation:!1,appendTo:!1,preCloseCallback:!1,onOpenCallback:!1,overlay:!0,cache:!0,trapFocus:!0,preserveFocus:!0,ariaAuto:!0,ariaRole:null,ariaLabelledById:null,ariaLabelledBySelector:null,ariaDescribedById:null,ariaDescribedBySelector:null,bodyClassName:"ngdialog-open",width:null,height:null};this.setForceHtmlReload=function(a){j.html=a||!1},this.setForceBodyReload=function(a){j.body=a||!1},this.setDefaults=function(c){a.extend(b,c)},this.setOpenOnePerName=function(a){o=a||!1};var d,e=0,s=0,t={};this.$get=["$document","$templateCache","$compile","$q","$http","$rootScope","$timeout","$window","$controller","$injector",function(u,v,w,x,y,z,A,B,C,D){var E=[],F={onDocumentKeydown:function(a){27===a.keyCode&&G.close("$escape")},activate:function(a){var b=a.data("$ngDialogOptions");b.trapFocus&&(a.on("keydown",F.onTrapFocusKeydown),E.body.on("keydown",F.onTrapFocusKeydown))},deactivate:function(a){a.off("keydown",F.onTrapFocusKeydown),E.body.off("keydown",F.onTrapFocusKeydown)},deactivateAll:function(b){a.forEach(b,function(b){var c=a.element(b);F.deactivate(c)})},setBodyPadding:function(a){var b=parseInt(E.body.css("padding-right")||0,10);E.body.css("padding-right",b+a+"px"),E.body.data("ng-dialog-original-padding",b),z.$broadcast("ngDialog.setPadding",a)},resetBodyPadding:function(){var a=E.body.data("ng-dialog-original-padding");a?E.body.css("padding-right",a+"px"):E.body.css("padding-right",""),z.$broadcast("ngDialog.setPadding",0)},performCloseDialog:function(a,b){var c=a.data("$ngDialogOptions"),e=a.attr("id"),h=k[e];if(F.deactivate(a),h){if("undefined"!=typeof B.Hammer){var i=h.hammerTime;i.off("tap",d),i.destroy&&i.destroy(),delete h.hammerTime}else a.unbind("click");1===s&&E.body.unbind("keydown",F.onDocumentKeydown),a.hasClass("ngdialog-closing")||(s-=1);var j=a.data("$ngDialogPreviousFocus");j&&j.focus&&j.focus(),z.$broadcast("ngDialog.closing",a,b),s=s<0?0:s,f&&!c.disableAnimation?(h.$destroy(),a.unbind(g).bind(g,function(){F.closeDialogElement(a,b)}).addClass("ngdialog-closing")):(h.$destroy(),F.closeDialogElement(a,b)),t[e]&&(t[e].resolve({id:e,value:b,$dialog:a,remainingDialogs:s}),delete t[e]),k[e]&&delete k[e],l.splice(l.indexOf(e),1),l.length||(E.body.unbind("keydown",F.onDocumentKeydown),n=!1),0==s&&(d=void 0)}},closeDialogElement:function(a,b){var c=a.data("$ngDialogOptions");a.remove(),m.splice(m.indexOf(c.bodyClassName),1),m.indexOf(c.bodyClassName)===-1&&(E.html.removeClass(c.bodyClassName),E.body.removeClass(c.bodyClassName)),0===s&&F.resetBodyPadding(),z.$broadcast("ngDialog.closed",a,b)},closeDialog:function(b,c){var d=b.data("$ngDialogPreCloseCallback");if(d&&a.isFunction(d)){var e=d.call(b,c);if(a.isObject(e))e.closePromise?e.closePromise.then(function(){F.performCloseDialog(b,c)},function(){return!1}):e.then(function(){F.performCloseDialog(b,c)},function(){return!1});else{if(e===!1)return!1;F.performCloseDialog(b,c)}}else F.performCloseDialog(b,c)},onTrapFocusKeydown:function(b){var c,d=a.element(b.currentTarget);if(d.hasClass("ngdialog"))c=d;else if(c=F.getActiveDialog(),null===c)return;var e=9===b.keyCode,f=b.shiftKey===!0;e&&F.handleTab(c,b,f)},handleTab:function(a,b,c){var d=F.getFocusableElements(a);if(0===d.length)return void(document.activeElement&&document.activeElement.blur&&document.activeElement.blur());var e=document.activeElement,f=Array.prototype.indexOf.call(d,e),g=f===-1,h=0===f,i=f===d.length-1,j=!1;c?(g||h)&&(d[d.length-1].focus(),j=!0):(g||i)&&(d[0].focus(),j=!0),j&&(b.preventDefault(),b.stopPropagation())},autoFocus:function(a){var b=a[0],d=b.querySelector("*[autofocus]");if(null===d||(d.focus(),document.activeElement!==d)){var e=F.getFocusableElements(a);if(e.length>0)return void e[0].focus();var f=F.filterVisibleElements(b.querySelectorAll("h1,h2,h3,h4,h5,h6,p,span"));if(f.length>0){var g=f[0];c(g).attr("tabindex","-1").css("outline","0"),g.focus()}}},getFocusableElements:function(a){var b=a[0],c=b.querySelectorAll(h),d=F.filterTabbableElements(c);return F.filterVisibleElements(d)},filterTabbableElements:function(a){for(var b=[],d=0;d0||d.offsetHeight>0)&&b.push(d)}return b},getActiveDialog:function(){var a=document.querySelectorAll(".ngdialog");return 0===a.length?null:c(a[a.length-1])},applyAriaAttributes:function(a,b){if(b.ariaAuto){if(!b.ariaRole){var c=F.getFocusableElements(a).length>0?"dialog":"alertdialog";b.ariaRole=c}b.ariaLabelledBySelector||(b.ariaLabelledBySelector="h1,h2,h3,h4,h5,h6"),b.ariaDescribedBySelector||(b.ariaDescribedBySelector="article,section,p")}b.ariaRole&&a.attr("role",b.ariaRole),F.applyAriaAttribute(a,"aria-labelledby",b.ariaLabelledById,b.ariaLabelledBySelector),F.applyAriaAttribute(a,"aria-describedby",b.ariaDescribedById,b.ariaDescribedBySelector)},applyAriaAttribute:function(a,b,d,e){if(d)return void a.attr(b,d);if(e){var f=a.attr("id"),g=a[0].querySelector(e);if(!g)return;var h=f+"-"+b;return c(g).attr("id",h),a.attr(b,h),h}},detectUIRouter:function(){return D.has("$transitions")?r:!!D.has("$state")&&q},getRouterLocationEventName:function(){return F.detectUIRouter()?"$stateChangeStart":"$locationChangeStart"}},G={__PRIVATE__:F,open:function(f){function g(b,c){var c=c||{};return c.headers=c.headers||{},a.extend(c.headers,{Accept:"text/html"}),z.$broadcast("ngDialog.templateLoading",b),y.get(b,c).then(function(a){return z.$broadcast("ngDialog.templateLoaded",b),a.data||""})}function h(b){return b?a.isString(b)&&q.plain?b:"boolean"!=typeof q.cache||q.cache?g(b,{cache:v}):g(b,{cache:!1}):"Empty template"}var j=null;if(f=f||{},!(o&&f.name&&(j=f.name.toLowerCase().replace(/\s/g,"-")+"-dialog",this.isOpen(j)))){var q=a.copy(b),r=++e;j=j||"ngdialog"+r,l.push(j),"undefined"!=typeof q.data&&("undefined"==typeof f.data&&(f.data={}),f.data=a.merge(a.copy(q.data),f.data)),a.extend(q,f);var u;t[j]=u=x.defer();var H;k[j]=H=a.isObject(q.scope)?q.scope.$new():z.$new();var I,J,K,L=a.extend({},q.resolve);return a.forEach(L,function(b,c){L[c]=a.isString(b)?D.get(b):D.invoke(b,null,null,c)}),x.all({template:h(q.template||q.templateUrl),locals:x.all(L)}).then(function(b){var e=b.template,f=b.locals;q.showClose&&(e+='');var g=q.overlay?"":" ngdialog-no-overlay";if(I=c('
'),I.html(q.overlay?'
'+e+"
":'
'+e+"
"),I.data("$ngDialogOptions",q),H.ngDialogId=j,q.data&&a.isString(q.data)){var h=q.data.replace(/^\s*/,"")[0];H.ngDialogData="{"===h||"["===h?a.fromJson(q.data):new String(q.data),H.ngDialogData.ngDialogId=j}else q.data&&a.isObject(q.data)&&(H.ngDialogData=q.data,H.ngDialogData.ngDialogId=j);if(q.className&&I.addClass(q.className),q.appendClassName&&I.addClass(q.appendClassName),q.width&&(K=I[0].querySelector(".ngdialog-content"),a.isString(q.width)?K.style.width=q.width:K.style.width=q.width+"px"),q.height&&(K=I[0].querySelector(".ngdialog-content"),a.isString(q.height)?K.style.height=q.height:K.style.height=q.height+"px"),q.disableAnimation&&I.addClass(i),J=q.appendTo&&a.isString(q.appendTo)?a.element(document.querySelector(q.appendTo)):E.body,F.applyAriaAttributes(I,q),[{name:"$ngDialogPreCloseCallback",value:q.preCloseCallback},{name:"$ngDialogOnOpenCallback",value:q.onOpenCallback}].forEach(function(b){if(b.value){var c;a.isFunction(b.value)?c=b.value:a.isString(b.value)&&H&&(a.isFunction(H[b.value])?c=H[b.value]:H.$parent&&a.isFunction(H.$parent[b.value])?c=H.$parent[b.value]:z&&a.isFunction(z[b.value])&&(c=z[b.value])),c&&I.data(b.name,c)}}),H.closeThisDialog=function(a){F.closeDialog(I,a)},q.controller&&(a.isString(q.controller)||a.isArray(q.controller)||a.isFunction(q.controller))){var k;q.controllerAs&&a.isString(q.controllerAs)&&(k=q.controllerAs);var l=C(q.controller,a.extend(f,{$scope:H,$element:I}),!0,k);q.bindToController&&a.extend(l.instance,{ngDialogId:H.ngDialogId,ngDialogData:H.ngDialogData,closeThisDialog:H.closeThisDialog,confirm:H.confirm}),"function"==typeof l?I.data("$ngDialogControllerController",l()):I.data("$ngDialogControllerController",l)}if(A(function(){var b=document.querySelectorAll(".ngdialog");F.deactivateAll(b),w(I)(H);var c=B.innerWidth-E.body.prop("clientWidth");E.html.addClass(q.bodyClassName),E.body.addClass(q.bodyClassName),m.push(q.bodyClassName);var d=c-(B.innerWidth-E.body.prop("clientWidth"));d>0&&F.setBodyPadding(d),J.append(I),F.activate(I),q.trapFocus&&F.autoFocus(I),q.name?z.$broadcast("ngDialog.opened",{dialog:I,name:q.name}):z.$broadcast("ngDialog.opened",I);var e=I.data("$ngDialogOnOpenCallback");e&&a.isFunction(e)&&e.call(I)}),n||(E.body.bind("keydown",F.onDocumentKeydown),n=!0),q.closeByNavigation&&p.push(I),q.preserveFocus&&I.data("$ngDialogPreviousFocus",document.activeElement),d=function(a){var b=!!q.closeByDocument&&c(a.target).hasClass("ngdialog-overlay"),d=c(a.target).hasClass("ngdialog-close");(b||d)&&G.close(I.attr("id"),d?"$closeButton":"$document")},"undefined"!=typeof B.Hammer){var o=H.hammerTime=B.Hammer(I[0]);o.on("tap",d)}else I.bind("click",d);return s+=1,G}),{id:j,closePromise:u.promise,close:function(a){F.closeDialog(I,a)}}}},openConfirm:function(d){var e=x.defer(),f=a.copy(b);d=d||{},"undefined"!=typeof f.data&&("undefined"==typeof d.data&&(d.data={}),d.data=a.merge(a.copy(f.data),d.data)),a.extend(f,d),f.scope=a.isObject(f.scope)?f.scope.$new():z.$new(),f.scope.confirm=function(a){e.resolve(a);var b=c(document.getElementById(g.id));F.performCloseDialog(b,a)};var g=G.open(f);if(g)return g.closePromise.then(function(a){return a?e.reject(a.value):e.reject()}),e.promise},isOpen:function(a){var b=c(document.getElementById(a));return b.length>0},close:function(a,b){var d=c(document.getElementById(a));if(d.length)F.closeDialog(d,b);else if("$escape"===a){var e=l[l.length-1];d=c(document.getElementById(e)),d.data("$ngDialogOptions").closeByEscape&&F.closeDialog(d,"$escape")}else G.closeAll(b);return G},closeAll:function(a){for(var b=document.querySelectorAll(".ngdialog"),d=b.length-1;d>=0;d--){var e=b[d];F.closeDialog(c(e),a)}},getOpenDialogs:function(){return l},getDefaults:function(){return b}};a.forEach(["html","body"],function(a){if(E[a]=u.find(a),j[a]){var b=F.getRouterLocationEventName();z.$on(b,function(){E[a]=u.find(a)})}});var H=F.detectUIRouter();if(H===r){var I=D.get("$transitions");I.onStart({},function(a){for(;p.length>0;){var b=p.pop();if(F.closeDialog(b)===!1)return!1}})}else{var J=H===q?"$stateChangeStart":"$locationChangeStart";z.$on(J,function(a){for(;p.length>0;){var b=p.pop();F.closeDialog(b)===!1&&a.preventDefault()}})}return G}]}),b.directive("ngDialog",["ngDialog",function(b){return{restrict:"A",scope:{ngDialogScope:"="},link:function(c,d,e){d.on("click",function(d){d.preventDefault();var f=a.isDefined(c.ngDialogScope)?c.ngDialogScope:"noScope";a.isDefined(e.ngDialogClosePrevious)&&b.close(e.ngDialogClosePrevious);var g=b.getDefaults();b.open({template:e.ngDialog,className:e.ngDialogClass||g.className,appendClassName:e.ngDialogAppendClass,controller:e.ngDialogController,controllerAs:e.ngDialogControllerAs,bindToController:e.ngDialogBindToController,disableAnimation:e.ngDialogDisableAnimation,scope:f,data:e.ngDialogData,showClose:"false"!==e.ngDialogShowClose&&("true"===e.ngDialogShowClose||g.showClose),closeByDocument:"false"!==e.ngDialogCloseByDocument&&("true"===e.ngDialogCloseByDocument||g.closeByDocument),closeByEscape:"false"!==e.ngDialogCloseByEscape&&("true"===e.ngDialogCloseByEscape||g.closeByEscape),overlay:"false"!==e.ngDialogOverlay&&("true"===e.ngDialogOverlay||g.overlay),preCloseCallback:e.ngDialogPreCloseCallback||g.preCloseCallback,onOpenCallback:e.ngDialogOnOpenCallback||g.onOpenCallback,bodyClassName:e.ngDialogBodyClass||g.bodyClassName})})}}}]),b}); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | var testMinified = process.argv.indexOf('--min') > -1, subject; 2 | 3 | if (testMinified) { 4 | subject = 'js/ngDialog.min.js'; 5 | console.log('Testing minifed ngDialog'); 6 | } else { 7 | subject = 'js/ngDialog.js'; 8 | } 9 | 10 | module.exports = function(config) { 11 | config.set({ 12 | basePath: '', 13 | frameworks: ['jasmine'], 14 | files: [ 15 | 'bower_components/angular/angular.js', 16 | 'bower_components/angular-mocks/angular-mocks.js', 17 | 'example/inside-directive/**/*.js', 18 | subject, 19 | 'tests/unit/**/*.js' 20 | ], 21 | port: 9877, 22 | colors: true, 23 | logLevel: config.LOG_INFO, 24 | autoWatch: false, 25 | browsers: ['PhantomJS'], 26 | singleRun: false, 27 | reporters: ['dots', 'coverage'], 28 | preprocessors: { 29 | 'js/ngDialog.js': ['coverage'] 30 | }, 31 | plugins: [ 32 | 'karma-phantomjs-launcher', 33 | 'karma-coverage', 34 | 'karma-jasmine' 35 | ], 36 | coverageReporter: { 37 | reporters: [{ 38 | type: 'html', 39 | subdir: 'report-html' 40 | }, { 41 | type: 'lcov', 42 | subdir: 'report-lcov' 43 | }] 44 | } 45 | }); 46 | }; 47 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ng-dialog", 3 | "version": "1.4.0", 4 | "homepage": "https://github.com/likeastore/ngDialog", 5 | "description": "Modal dialogs and popups provider for Angular.js applications", 6 | "main": "./js/ngDialog.js", 7 | "style": "./css/ngDialog.css", 8 | "scripts": { 9 | "pretest": "npm install && bower install --allow-root", 10 | "test": "./node_modules/karma/bin/karma start --single-run --browsers PhantomJS", 11 | "test-min": "./node_modules/karma/bin/karma start --single-run --browsers PhantomJS --min", 12 | "test-watch": "./node_modules/karma/bin/karma start --auto-watch --browsers PhantomJS", 13 | "serve": "node server", 14 | "webdriver-update": "node_modules/.bin/webdriver-manager update --standalone", 15 | "webdriver": "node_modules/.bin/webdriver-manager start", 16 | "preprotractor": "npm install && bower install --allow-root", 17 | "protractor": "node_modules/.bin/protractor protractor.conf.js", 18 | "protractor-a11y": "node_modules/.bin/protractor protractor.conf.js --a11y", 19 | "protractor-console": "node_modules/.bin/protractor protractor.conf.js --console-error", 20 | "build": "grunt build" 21 | }, 22 | "directories": { 23 | "test": "tests" 24 | }, 25 | "keywords": [ 26 | "angular.js", 27 | "modals", 28 | "popups", 29 | "dialog", 30 | "ng", 31 | "provider", 32 | "factory", 33 | "directive" 34 | ], 35 | "author": { 36 | "name": "Dmitri Voronianski", 37 | "email": "dmitri.voronianski@gmail.com", 38 | "web": "http://pixelhunter.me", 39 | "twitter": "voronianski" 40 | }, 41 | "bugs": "https://github.com/likeastore/ngDialog/issues", 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/likeastore/ngDialog" 45 | }, 46 | "readmeFilename": "README.md", 47 | "license": "MIT", 48 | "devDependencies": { 49 | "express": "^4.13.3", 50 | "grunt": "^0.4.5", 51 | "grunt-cli": "^0.1.13", 52 | "grunt-contrib-cssmin": "^0.14.0", 53 | "grunt-contrib-jshint": "^0.11.3", 54 | "grunt-contrib-uglify": "^0.9.2", 55 | "grunt-myth": "^1.0.1", 56 | "jasmine-core": "^2.3.4", 57 | "karma": "^1.3.0", 58 | "karma-coverage": "^1.1.1", 59 | "karma-jasmine": "^1.1.0", 60 | "karma-phantomjs-launcher": "^1.0.2", 61 | "myth": "^1.5.0", 62 | "phantomjs": "^2.1.7", 63 | "protractor": "^2.2.0" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | var args = process.argv.slice(2); 2 | var plugins = []; 3 | 4 | var useA11y = args.indexOf('--a11y') > -1; 5 | var useConsole = args.indexOf('--console-warning') > -1 || args.indexOf('--console-error') > -1; 6 | 7 | if (useA11y) { 8 | plugins.push({ 9 | path: 'node_modules/protractor/plugins/accessibility', 10 | chromeA11YDevTools: { 11 | treatWarningsAsFailures: true 12 | } 13 | }); 14 | } 15 | 16 | if (useConsole) { 17 | plugins.push({ 18 | path: 'node_modules/protractor/plugins/console', 19 | failOnWarning: args.indexOf('--console-warning') > -1, 20 | failOnError: args.indexOf('--console-error') > -1 21 | }); 22 | } 23 | var multiCapabilities = [{ 24 | browserName: 'firefox' 25 | }]; 26 | 27 | // if (process.env.TRAVIS_PULL_REQUEST === 'false') { 28 | // multiCapabilities.push({ 29 | // browserName: 'chrome' 30 | // }); 31 | 32 | // if (!useA11y) { 33 | // multiCapabilities.push({ 34 | // browserName: 'safari' 35 | // }); 36 | // } 37 | 38 | // if (!useA11y && !useConsole) { 39 | // multiCapabilities.push({ 40 | // browserName: 'internet explorer', 41 | // version: 10 42 | // }); 43 | // multiCapabilities.push({ 44 | // browserName: 'internet explorer', 45 | // version: 11 46 | // }); 47 | // } 48 | 49 | // multiCapabilities.forEach(function(capability) { 50 | // capability['tunnel-identifier'] = process.env.TRAVIS_JOB_NUMBER; 51 | // capability.name = 'ngDialog Protractor ' + process.env.TRAVIS_JOB_NUMBER; 52 | // }); 53 | // } 54 | 55 | var config = { 56 | allScriptsTimeout: 11000, 57 | specs: ['tests/protractor/**/*.js'], 58 | multiCapabilities: multiCapabilities, 59 | framework: 'jasmine2', 60 | jasmineNodeOpts: { 61 | defaultTimeoutInterval: 30000 62 | }, 63 | plugins: plugins 64 | }; 65 | 66 | // if (process.env.TRAVIS_PULL_REQUEST === 'false') { 67 | // config.sauceUser = process.env.SAUCE_USERNAME; 68 | // config.sauceKey = process.env.SAUCE_ACCESS_KEY; 69 | // } 70 | 71 | console.log('TRAVIS_PULL_REQUEST', process.env.TRAVIS_PULL_REQUEST); 72 | console.log('protractor config: ', config); 73 | console.log('multiCapabilities: ', multiCapabilities); 74 | 75 | module.exports.config = config; 76 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var http = require('http'); 3 | var app = express(); 4 | 5 | app.use(express.static( __dirname )); 6 | 7 | var port = process.env.PORT || 3000; 8 | http.createServer(app).listen(port); 9 | console.log('Server running on ' + port); 10 | -------------------------------------------------------------------------------- /tests/build-systems/browserify/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | -------------------------------------------------------------------------------- /tests/build-systems/browserify/README.md: -------------------------------------------------------------------------------- 1 | This is test of ngDialog under Browserify 2 | -------------------------------------------------------------------------------- /tests/build-systems/browserify/app.js: -------------------------------------------------------------------------------- 1 | import angular from 'angular'; 2 | import ngDialog from 'ng-dialog'; 3 | 4 | let app = angular.module('exampleApp', [ 5 | ngDialog 6 | ]); 7 | 8 | app.run((ngDialog) => { 9 | ngDialog.open({ 10 | template: 'dialog', 11 | className: 'ngdialog-theme-default' 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /tests/build-systems/browserify/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var browserify = require('browserify'); 3 | var babelify = require('babelify'); 4 | var source = require('vinyl-source-stream'); 5 | 6 | gulp.task('build', function () { 7 | return browserify({entries: './app.js', debug: true}) 8 | .transform(babelify) 9 | .bundle() 10 | .on('error', function (err) { 11 | console.error(err); 12 | this.emit('end'); 13 | }) 14 | .pipe(source('bundle.js')) 15 | .pipe(gulp.dest('dist')); 16 | }); 17 | 18 | gulp.task('watch', ['build'], function () { 19 | gulp.watch('*.js', ['build']); 20 | }); 21 | 22 | gulp.task('default', ['watch']); 23 | -------------------------------------------------------------------------------- /tests/build-systems/browserify/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Browserify test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | If you don't see the dialog opened, then it might be an issue with this setup (ngDialog + Browserify).
17 | Please submit a new issue to our repository at GitHub. 18 |
19 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tests/build-systems/browserify/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngDialogTest", 3 | "description": "Test of ngDialog setup", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/likeastore/ngDialog" 11 | }, 12 | "license": "MIT", 13 | "devDependencies": { 14 | "babelify": "^6.1.1", 15 | "browserify": "^10.2.1", 16 | "gulp": "^3.8.11", 17 | "vinyl-source-stream": "^1.1.0" 18 | }, 19 | "dependencies": { 20 | "angular": "^1.4.7", 21 | "ng-dialog": "file:../../.." 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/protractor/close.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog open', function() { 2 | beforeEach(function() { 3 | browser.get('http://localhost:3000/example/index.html'); 4 | }); 5 | 6 | it('should open from functions', function() { 7 | element(by.css('#via-service')).click(); 8 | 9 | var EC = protractor.ExpectedConditions; 10 | browser.wait(EC.visibilityOf(element(by.css('.ngdialog'))), 5000); 11 | 12 | var plot0 = element(by.css('.ngdialog-overlay')); 13 | 14 | element(by.css('.close-this-dialog')).click(); 15 | 16 | browser.wait(EC.not(EC.presenceOf(element(by.css('.ngdialog')))), 5000); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /tests/protractor/closeByNavigation.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog closeByNavigation', function () { 2 | 3 | it('should close on state change with legacy ui-router', function () { 4 | // Load page 5 | browser.get('http://localhost:3000/example/browser-back-button/index.html'); 6 | 7 | // Click button to go to 'about' state 8 | element(by.css('[ui-sref=about]')).click(); 9 | 10 | // Expect a visible dialog on the page 11 | var EC = protractor.ExpectedConditions; 12 | browser.wait(EC.visibilityOf(element(by.css('.ngdialog'))), 5000); 13 | 14 | // Go back to 'home' state 15 | browser.navigate().back(); 16 | 17 | // Expect there's no visible dialog on the page 18 | browser.wait(EC.not(EC.presenceOf(element(by.css('.ngdialog')))), 5000); 19 | }); 20 | 21 | it('should close on state change with legacy ui-router', function () { 22 | // Load page 23 | browser.get('http://localhost:3000/example/browser-back-button/ui-router-1.0.0-rc.1.html'); 24 | 25 | // Click button to go to 'about' state 26 | element(by.css('[ui-sref=about]')).click(); 27 | 28 | // Expect a visible dialog on the page 29 | var EC = protractor.ExpectedConditions; 30 | browser.wait(EC.visibilityOf(element(by.css('.ngdialog'))), 5000); 31 | 32 | // Go back to 'home' state 33 | browser.navigate().back(); 34 | 35 | // Expect there's no visible dialog on the page 36 | browser.wait(EC.not(EC.presenceOf(element(by.css('.ngdialog')))), 5000); 37 | }); 38 | 39 | }); 40 | -------------------------------------------------------------------------------- /tests/protractor/open.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog open', function() { 2 | beforeEach(function() { 3 | browser.get('http://localhost:3000/example/index.html'); 4 | }); 5 | 6 | it('should open from functions', function() { 7 | element(by.css('#via-service')).click(); 8 | 9 | var EC = protractor.ExpectedConditions; 10 | browser.wait(EC.visibilityOf(element(by.css('.ngdialog'))), 5000); 11 | 12 | element(by.css('.data-passed-through')).getText() 13 | .then(function(text) { 14 | expect(text).toBe('Data passed through: from a service'); 15 | }); 16 | }); 17 | 18 | it('should define specific width through a property js', function() { 19 | element(by.css('#js-width')).click(); 20 | expect(element(by.css('.ngdialog-content')).getCssValue('width')).toBe('650px'); 21 | }); 22 | 23 | it('should define custom height through a js property', function() { 24 | element(by.css('#js-height')).click(); 25 | expect(element(by.css('.ngdialog-content')).getCssValue('height')).toBe('400px'); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/protractor/test.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog', function() { 2 | beforeEach(function() { 3 | browser.get('http://localhost:3000/example/paddingTest.html'); 4 | }); 5 | 6 | it('should add padding to the body tag when a scrollbar is present', function() { 7 | expect( $('body').getCssValue('padding-right') ).toBe( '0px' ); 8 | $('.openPaddingLink').click(); 9 | browser.sleep( 500 ); 10 | expect(element(by.css('body')).getCssValue('padding-right')).not.toMatch(/[0-9]{,2}px/); 11 | $('.ngdialog-overlay').click(); 12 | browser.sleep( 500 ); 13 | expect(element(by.css('body')).getCssValue('padding-right')).toBe( '0px' ); 14 | }); 15 | 16 | it('should communicate the body padding to the application', function() { 17 | expect(element(by.css('body')).getCssValue('padding-right')).toBe( '0px' ); 18 | expect(element(by.css('body')).getCssValue('padding-right')).toBe( element(by.css('.paddingHeader')).getCssValue('padding-right') ); 19 | $('.openPaddingLink').click(); 20 | browser.sleep( 500 ); 21 | expect(element(by.css('body')).getCssValue('padding-right')).not.toMatch(/[0-9]{,2}px/); 22 | expect(element(by.css('body')).getCssValue('padding-right')).toBe( element(by.css('.paddingHeader')).getCssValue('padding-right') ); 23 | $('.ngdialog-overlay').click(); 24 | browser.sleep( 500 ); 25 | expect(element(by.css('body')).getCssValue('padding-right')).toBe( '0px' ); 26 | expect(element(by.css('body')).getCssValue('padding-right')).toBe( element(by.css('.paddingHeader')).getCssValue('padding-right') ); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /tests/unit/before.js: -------------------------------------------------------------------------------- 1 | if (typeof Function.prototype.bind != 'function') { 2 | Function.prototype.bind = function bind(obj) { 3 | var args = Array.prototype.slice.call(arguments, 1), 4 | self = this, 5 | nop = function() { 6 | }, 7 | bound = function() { 8 | return self.apply( 9 | this instanceof nop ? this : (obj || {}), args.concat( 10 | Array.prototype.slice.call(arguments) 11 | ) 12 | ); 13 | }; 14 | nop.prototype = this.prototype || {}; 15 | bound.prototype = new nop(); 16 | return bound; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /tests/unit/ngDialog.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog', function () { 2 | 'use strict'; 3 | 4 | var any = jasmine.any, 5 | spy = jasmine.createSpy; 6 | 7 | beforeEach(module('ngDialog')); 8 | 9 | afterEach(inject(function (ngDialog, $document) { 10 | ngDialog.closeAll(); 11 | [].slice.call( 12 | $document.find('body').children() 13 | ) 14 | .map(angular.element) 15 | .forEach(function (elm) { 16 | if (elm.hasClass('ngdialog')) { 17 | // yuck 18 | elm.triggerHandler('animationend'); 19 | } 20 | }); 21 | })); 22 | 23 | it('should inject the ngDialog service', inject(function(ngDialog) { 24 | expect(ngDialog).toBeDefined(); 25 | })); 26 | 27 | describe('no options', function () { 28 | var inst, elm; 29 | beforeEach(inject(function (ngDialog, $document, $timeout) { 30 | inst = ngDialog.open(); 31 | $timeout.flush(); 32 | elm = $document[0].getElementById(inst.id); 33 | })); 34 | 35 | it('should have returned a dialog instance object', function() { 36 | expect(inst).toBeDefined(); 37 | }); 38 | 39 | it('should include a document id', function() { 40 | expect(inst.id).toEqual('ngdialog1'); 41 | }); 42 | 43 | it('should have created an element on the DOM', function() { 44 | expect(elm).toBeDefined(); 45 | }); 46 | 47 | it('should have an empty template', function() { 48 | expect(elm.textContent).toEqual('Empty template'); 49 | }); 50 | }); 51 | 52 | describe('with a plain template', function () { 53 | var elm; 54 | beforeEach(inject(function (ngDialog, $timeout, $document) { 55 | var id = ngDialog.open({ 56 | template: '

some text {{1 + 1}}

', 57 | plain: true 58 | }).id; 59 | $timeout.flush(); 60 | elm = $document[0].getElementById(id); 61 | })); 62 | 63 | it('should have compiled the html', inject(function () { 64 | expect(elm.textContent).toEqual('some text 2'); 65 | })); 66 | }); 67 | 68 | describe('with a plain template URL', function () { 69 | var elm; 70 | beforeEach(inject(function (ngDialog, $timeout, $document, $httpBackend) { 71 | $httpBackend.whenGET('test.html').respond('

some text {{1 + 1}}

'); 72 | var id = ngDialog.open({ 73 | templateUrl: 'test.html' 74 | }).id; 75 | $httpBackend.flush(); 76 | $timeout.flush(); 77 | elm = $document[0].getElementById(id); 78 | })); 79 | 80 | it('should have compiled the html', inject(function () { 81 | expect(elm.textContent).toEqual('some text 2'); 82 | })); 83 | }); 84 | 85 | describe('with already cached template URL', function () { 86 | var elm; 87 | beforeEach(inject(function (ngDialog, $timeout, $document, $httpBackend, $compile, $rootScope) { 88 | $httpBackend.whenGET('cached.html').respond('

some text {{1 + 1}}

'); 89 | $compile('
')($rootScope); 90 | 91 | $rootScope.$digest(); 92 | $httpBackend.flush(); 93 | 94 | var id = ngDialog.open({ 95 | templateUrl: 'cached.html' 96 | }).id; 97 | 98 | $timeout.flush(); 99 | 100 | elm = $document[0].getElementById(id); 101 | })); 102 | 103 | it('should have compiled the html', inject(function () { 104 | expect(elm.textContent).toEqual('some text 2'); 105 | })); 106 | }); 107 | 108 | describe('with an appended class', function () { 109 | var elm; 110 | beforeEach(inject(function (ngDialog, $timeout, $document) { 111 | var id = ngDialog.open({ 112 | appendClassName: 'ngdialog-custom' 113 | }).id; 114 | $timeout.flush(); 115 | elm = $document[0].getElementById(id); 116 | })); 117 | 118 | it('should have the additional class', inject(function () { 119 | expect(elm.className.split(' ')).toContain('ngdialog-custom'); 120 | })); 121 | }); 122 | 123 | describe('controller instantiation', function () { 124 | var Ctrl; 125 | beforeEach(inject(function (ngDialog, $timeout, $q) { 126 | Ctrl = spy('DialogCtrl'); 127 | Ctrl.$inject = ['$scope', '$element', '$log', 'myLocal', 'localPromise']; 128 | ngDialog.open({ 129 | controller: Ctrl, 130 | resolve: { 131 | myLocal: function () { 132 | return 'local'; 133 | }, 134 | localPromise: function () { 135 | return $q.when('async local!'); 136 | } 137 | } 138 | }); 139 | $timeout.flush(); 140 | })); 141 | 142 | it('should have instantiated the controller', function() { 143 | expect(Ctrl).toHaveBeenCalled(); 144 | }); 145 | 146 | describe('dependencies', function () { 147 | var injected; 148 | beforeEach(function () { 149 | injected = Ctrl.calls.mostRecent().args; 150 | }); 151 | 152 | it('should inject a scope', function() { 153 | expect(injected[0].$watch).toEqual(any(Function)); 154 | }); 155 | 156 | it('should inject the root dialog html element', function() { 157 | expect(injected[1].prop('id')).toEqual('ngdialog1'); 158 | }); 159 | 160 | it('should inject another angular service', inject(function($log) { 161 | expect(injected[2]).toBe($log); 162 | })); 163 | 164 | it('should inject a local value', function() { 165 | expect(injected[3]).toEqual('local'); 166 | }); 167 | 168 | it('should inject an asynchronous local value', function() { 169 | expect(injected[4]).toEqual('async local!'); 170 | }); 171 | }); 172 | }); 173 | 174 | describe('public functions checking', function () { 175 | var inst; 176 | var elm; 177 | 178 | beforeEach(inject(function (ngDialog, $document, $timeout) { 179 | inst = ngDialog.open(); 180 | $timeout.flush(); 181 | elm = $document[0].getElementById(inst.id); 182 | })); 183 | 184 | it('should be able to check if a dialog is open', inject(function(ngDialog) { 185 | expect(ngDialog.isOpen(inst.id)).toBe(true); 186 | })); 187 | 188 | }); 189 | 190 | describe('bindToController data checking', function () { 191 | var Ctrl; 192 | beforeEach(inject(function (ngDialog, $timeout) { 193 | Ctrl = spy('DialogCtrl'); 194 | ngDialog.open({ 195 | controller: Ctrl, 196 | controllerAs: 'CtrlVM', 197 | bindToController: true, 198 | data: { 199 | testData: 'testData' 200 | } 201 | }); 202 | $timeout.flush(); 203 | })); 204 | 205 | it('should have placed ngDialogId on the controller', function() { 206 | expect(Ctrl.calls.first().object.ngDialogId).toEqual('ngdialog1'); 207 | }); 208 | 209 | it('should have placed ngDialogData on the controller', function() { 210 | expect(Ctrl.calls.first().object.ngDialogData.testData).toEqual('testData'); 211 | }); 212 | 213 | it('should have placed closeThisDialog function on the controller', function() { 214 | expect(Ctrl.calls.first().object.closeThisDialog).toEqual(jasmine.any(Function)); 215 | }); 216 | 217 | it('should not have placed confirm function on the controller', function() { 218 | expect(Ctrl.calls.first().object.confirm).toBeUndefined(); 219 | }); 220 | }); 221 | 222 | describe('bindToController data checking on openConfirm', function () { 223 | var Ctrl; 224 | beforeEach(inject(function (ngDialog, $timeout) { 225 | Ctrl = spy('DialogCtrl'); 226 | ngDialog.openConfirm({ 227 | controller: Ctrl, 228 | controllerAs: 'CtrlVM', 229 | bindToController: true, 230 | data: { 231 | testData: 'testData' 232 | } 233 | }); 234 | $timeout.flush(); 235 | })); 236 | 237 | it('should have placed confirm function on the controller', function () { 238 | expect(Ctrl.calls.first().object.confirm).toEqual(jasmine.any(Function)); 239 | }); 240 | }); 241 | 242 | describe('openOnePerName', function () { 243 | var dialogOptions = { 244 | name: 'Do Something' 245 | }; 246 | 247 | describe('when feature is off - default', function () { 248 | var ngDialog; 249 | var $timeout; 250 | 251 | beforeEach(inject(function (_ngDialog_, _$timeout_) { 252 | ngDialog = _ngDialog_; 253 | $timeout = _$timeout_; 254 | })); 255 | 256 | it('should allow opening 2 dialogs with the same name', function () { 257 | var firstDialog = ngDialog.open(dialogOptions); 258 | expect(firstDialog).toBeDefined(); 259 | expect(firstDialog.id).toBe('ngdialog1'); 260 | 261 | var secondDialog = ngDialog.open(dialogOptions); 262 | expect(secondDialog).toBeDefined(); 263 | expect(secondDialog.id).toBe('ngdialog2'); 264 | $timeout.flush(); 265 | }); 266 | }); 267 | 268 | describe('when feature is on (openOnePerName = true)', function () { 269 | var ngDialog; 270 | var $timeout; 271 | 272 | beforeEach(module(function (ngDialogProvider) { 273 | ngDialogProvider.setOpenOnePerName(true); 274 | })); 275 | 276 | beforeEach(inject(function (_ngDialog_, _$timeout_) { 277 | ngDialog = _ngDialog_; 278 | $timeout = _$timeout_; 279 | })); 280 | 281 | it('should not allow opening 2 dialogs with the same name', function () { 282 | var firstDialog = ngDialog.open(dialogOptions); 283 | expect(firstDialog).toBeDefined(); 284 | expect(firstDialog.id).toBe('do-something-dialog'); 285 | $timeout.flush(); 286 | 287 | var secondDialog = ngDialog.open(dialogOptions); 288 | expect(secondDialog).toBeUndefined(); 289 | }); 290 | }); 291 | }); 292 | 293 | describe('with an width', function () { 294 | var elm, open; 295 | beforeEach(inject(function (ngDialog, $timeout, $document) { 296 | open = function(width) { 297 | var id = ngDialog.open({ 298 | width: width 299 | }).id; 300 | $timeout.flush(); 301 | elm = $document[0].getElementById(id).querySelector('.ngdialog-content'); 302 | } 303 | })); 304 | 305 | it('should transform number to px', function () { 306 | open(400); 307 | expect(elm.style.cssText.trim()).toBe('width: 400px;'); 308 | }); 309 | 310 | it('should set other width metrics', function () { 311 | open('40%'); 312 | expect(elm.style.cssText.trim()).toBe('width: 40%;'); 313 | }); 314 | }); 315 | 316 | describe('with onOpenCallback', function () { 317 | var elm, open; 318 | beforeEach(inject(function (ngDialog, $timeout, $document) { 319 | open = function (onOpenCallback) { 320 | var id = ngDialog.open({ 321 | onOpenCallback: onOpenCallback 322 | }).id; 323 | $timeout.flush(); 324 | } 325 | })); 326 | 327 | it('onOpenCallback method should be called on opening of the dialog', function () { 328 | var callback = spy(); 329 | open(callback); 330 | expect(callback).toHaveBeenCalled(); 331 | }) 332 | }); 333 | 334 | describe('with custom height', function () { 335 | var elm, open; 336 | beforeEach(inject(function (ngDialog, $timeout, $document) { 337 | open = function(height) { 338 | var id = ngDialog.open({ 339 | height: height 340 | }).id; 341 | $timeout.flush(); 342 | elm = $document[0].getElementById(id).querySelector('.ngdialog-content'); 343 | } 344 | })); 345 | 346 | it('should set modal height from number to px', function () { 347 | open(400); 348 | expect(elm.style.cssText.trim()).toBe('height: 400px;'); 349 | }); 350 | 351 | it('should set modal height using other units', function () { 352 | open('40%'); 353 | expect(elm.style.cssText.trim()).toBe('height: 40%;'); 354 | }); 355 | }); 356 | 357 | describe('without custom height', function () { 358 | var elm, id; 359 | beforeEach(inject(function (ngDialog, $timeout, $document) { 360 | id = ngDialog.open().id; 361 | $timeout.flush(); 362 | elm = $document[0].getElementById(id).querySelector('.ngdialog-content'); 363 | })); 364 | 365 | it('should have id', function() { 366 | expect(id).toBeDefined(); 367 | expect(id).toEqual('ngdialog1'); 368 | }); 369 | 370 | it('should have created an element on the DOM', function() { 371 | expect(elm).toBeDefined(); 372 | }); 373 | 374 | it('should have content', function() { 375 | expect(elm.clientHeight).toBeGreaterThan(0); 376 | }); 377 | }); 378 | 379 | describe('body classes should be applied / removed correctly', function () { 380 | var elm, first, second, ngDialog, flush; 381 | 382 | beforeEach(inject(function (_ngDialog_, $timeout, $document) { 383 | ngDialog = _ngDialog_ 384 | 385 | first = ngDialog.open({ 386 | bodyClassName: 'ngdialog-first' 387 | }); 388 | 389 | $timeout.flush(); 390 | 391 | second = ngDialog.open({ 392 | bodyClassName: 'ngdialog-second' 393 | }); 394 | 395 | $timeout.flush(); 396 | 397 | elm = angular.element($document.find('body')); 398 | 399 | flush = function () { 400 | [].slice.call( 401 | $document.find('body').children() 402 | ) 403 | .map(angular.element) 404 | .forEach(function (elm) { 405 | if (elm.hasClass('ngdialog')) { 406 | // yuck 407 | elm.triggerHandler('animationend'); 408 | } 409 | }); 410 | }; 411 | })); 412 | 413 | it('should have two body classes applied', function () { 414 | expect(elm.hasClass('ngdialog-first')).toEqual(true); 415 | expect(elm.hasClass('ngdialog-second')).toEqual(true); 416 | }); 417 | 418 | it('should properly remove one body class', function () { 419 | first.close(); 420 | flush(); 421 | 422 | expect(elm.hasClass('ngdialog-second')).toEqual(true); 423 | expect(elm.hasClass('ngdialog-first')).toEqual(false); 424 | }); 425 | 426 | it('should properly remove all classes on closeAll', function () { 427 | ngDialog.closeAll(); 428 | flush(); 429 | 430 | expect(elm.hasClass('ngdialog-second')).toEqual(false); 431 | expect(elm.hasClass('ngdialog-first')).toEqual(false); 432 | }); 433 | }); 434 | 435 | }); 436 | -------------------------------------------------------------------------------- /tests/unit/ngDialog_close.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog', function () { 2 | 'use strict'; 3 | 4 | beforeEach(module('ngDialog')); 5 | 6 | var animationEndEvent = 'animationend webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend'; 7 | var $timeout; 8 | var $document; 9 | var ngDialog; 10 | beforeEach(inject(function(_$timeout_, _$document_, _ngDialog_) { 11 | $timeout = _$timeout_; 12 | $document = _$document_; 13 | ngDialog = _ngDialog_; 14 | })); 15 | 16 | afterEach(inject(function (ngDialog, $document) { 17 | //ngDialog.closeAll(); 18 | })); 19 | 20 | it('should allow one to close a dialog using just the id, without animation', function() { 21 | spyOn(ngDialog, 'close').and.callThrough(); 22 | spyOn(ngDialog.__PRIVATE__, 'performCloseDialog').and.callThrough(); 23 | spyOn(ngDialog.__PRIVATE__, 'closeDialogElement').and.callThrough(); 24 | var dialog = ngDialog.open({ 25 | disableAnimation: true 26 | }); 27 | $timeout.flush(); 28 | var element = angular.element($document[0].getElementById(dialog.id)); 29 | var id = element.attr('id'); 30 | ngDialog.close(id); 31 | expect(ngDialog.close.calls.count()).toEqual(1); 32 | expect(ngDialog.__PRIVATE__.performCloseDialog.calls.count()).toEqual(1); 33 | expect(ngDialog.__PRIVATE__.closeDialogElement.calls.count()).toEqual(1); 34 | expect(ngDialog.isOpen(id)).toBe(false); 35 | }); 36 | 37 | it('should allow one to close a dialog using just the id, without animation', function() { 38 | spyOn(ngDialog, 'close').and.callThrough(); 39 | spyOn(ngDialog.__PRIVATE__, 'performCloseDialog').and.callThrough(); 40 | spyOn(ngDialog.__PRIVATE__, 'closeDialogElement').and.callThrough(); 41 | var dialog = ngDialog.open({ 42 | disableAnimation: false 43 | }); 44 | $timeout.flush(); 45 | var element = angular.element($document[0].getElementById(dialog.id)); 46 | var id = element.attr('id'); 47 | angular.element(element); 48 | ngDialog.close(id); 49 | 50 | element.triggerHandler('animationend'); 51 | 52 | expect(ngDialog.close.calls.count()).toEqual(1); 53 | expect(ngDialog.__PRIVATE__.performCloseDialog.calls.count()).toEqual(1); 54 | expect(ngDialog.__PRIVATE__.closeDialogElement.calls.count()).toEqual(1); 55 | expect(ngDialog.isOpen(id)).toBe(false); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /tests/unit/ngDialog_closeThisDialog.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog', function () { 2 | 3 | beforeEach(module('ngDialog')); 4 | 5 | var ngDialog; 6 | var $timeout; 7 | var $document; 8 | var $rootScope; 9 | beforeEach(inject(function (_ngDialog_, _$timeout_, _$document_, _$rootScope_) { 10 | ngDialog = _ngDialog_; 11 | $timeout = _$timeout_; 12 | $document = _$document_; 13 | $rootScope = _$rootScope_; 14 | })); 15 | 16 | describe('closeThisDialog on $dialog scope', function() { 17 | it('should expose closeThisDialog on the dialog scope', function() { 18 | var instance = ngDialog.open(); 19 | 20 | $timeout(angular.noop, 100); 21 | $timeout.flush(); 22 | 23 | var element = angular.element($document[0].getElementById(instance.id)); 24 | expect(element.scope().closeThisDialog).toEqual(jasmine.any(Function)); 25 | 26 | $rootScope.$on('ngDialog.closed', function($event, $dialog) { 27 | expect($dialog.attr('class').indexOf('inside-directive')); 28 | }); 29 | 30 | expect(ngDialog.getOpenDialogs().length).toEqual(1); 31 | element.scope().closeThisDialog(); 32 | expect(ngDialog.getOpenDialogs().length).toEqual(0); 33 | }); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /tests/unit/ngDialog_insideDirective.js: -------------------------------------------------------------------------------- 1 | describe('ngDialog inside a directive', function () { 2 | var any = jasmine.any, 3 | spy = jasmine.createSpy; 4 | 5 | beforeEach(module('ngDialog')); 6 | beforeEach(module('inside-directive')); 7 | 8 | var $compile; 9 | var $rootScope; 10 | var $timeout; 11 | var ngDialog; 12 | beforeEach(inject(function(_$compile_, _$rootScope_, _$timeout_, _ngDialog_) { 13 | $compile = _$compile_; 14 | $rootScope = _$rootScope_; 15 | $timeout = _$timeout_; 16 | ngDialog = _ngDialog_; 17 | })); 18 | 19 | describe('with plain template', function() { 20 | 21 | it('should function as normal', function() { 22 | 23 | $rootScope.$on('ngDialog.opened', function($event, $dialog) { 24 | console.log($dialog); 25 | var ExampleController = $dialog.dialog.data('$ngDialogControllerController'); 26 | expect(ExampleController.$scope.closeThisDialog).toEqual(jasmine.any(Function)); 27 | $dialog.dialog.find('button').triggerHandler('click'); 28 | }); 29 | 30 | $rootScope.$on('ngDialog.closed', function($event, $dialog) { 31 | expect($dialog.attr('class').indexOf('inside-directive')); 32 | }); 33 | 34 | var $scope = $rootScope.$new(); 35 | var element = angular.element('
Testing example directive') 36 | $compile(element)($scope); 37 | $rootScope.$digest(); 38 | 39 | element.triggerHandler('click'); 40 | $rootScope.$digest(); 41 | 42 | $timeout(angular.noop, 100); 43 | $timeout.flush(); 44 | }); 45 | }); 46 | }); 47 | --------------------------------------------------------------------------------