├── .gitignore ├── CHANGELOG.md ├── README.md ├── bower.json ├── dist ├── css │ ├── ocModal.animations.css │ ├── ocModal.animations.min.css │ ├── ocModal.full.css │ ├── ocModal.full.min.css │ ├── ocModal.light.css │ └── ocModal.light.min.css ├── ocModal.js ├── ocModal.min.js └── scss │ ├── _animations.scss │ ├── _modal.scss │ ├── _no-bootstrap.scss │ ├── _variables.scss │ ├── ocModal.animations.scss │ ├── ocModal.full.scss │ └── ocModal.light.scss ├── example ├── app.js ├── bootstrap.min.css ├── index.html ├── ocModal.animations.css ├── ocModal.js └── ocModal.light.css ├── gulpfile.js ├── package.json └── src ├── changelog.js ├── ocModal.js ├── scss ├── _animations.scss ├── _modal.scss ├── _no-bootstrap.scss ├── _variables.scss ├── ocModal.animations.scss ├── ocModal.full.scss └── ocModal.light.scss └── validate-commit-msg.js /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ############# 33 | ## Windows detritus 34 | ############# 35 | 36 | # Windows image file caches 37 | Thumbs.db 38 | ehthumbs.db 39 | 40 | # Folder config file 41 | Desktop.ini 42 | 43 | # Recycle Bin used on file shares 44 | $RECYCLE.BIN/ 45 | 46 | # Mac crap 47 | .DS_Store 48 | 49 | 50 | ############# 51 | ## Intellij 52 | ############# 53 | 54 | nbproject 55 | manifest.mf 56 | build.xml 57 | 58 | .project 59 | .settings 60 | .idea/* 61 | *.iml 62 | 63 | 64 | ############# 65 | ## Project 66 | ############# 67 | public 68 | node_modules/* 69 | npm-debug.log 70 | bower_components 71 | 72 | test/test-results.xml 73 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # 0.1.12 (2015-12-23) 3 | 4 | 5 | ## Bug Fixes 6 | 7 | - make it work for npm 8 | ([70d39ecf](https://github.com/ocombe/ocModal/commit/70d39ecfb4b825a1d139aa84ebed352456606a76)) 9 | - vertical center with flexbox in IE10+ 10 | ([b0aa3f95](https://github.com/ocombe/ocModal/commit/b0aa3f9529ae9952498907cb15a1cb265e72083e)) 11 | 12 | 13 | 14 | # 0.1.11 (2015-11-05) 15 | 16 | 17 | ## Bug Fixes 18 | 19 | - don't prevent click events propagation 20 | ([727c6d25](https://github.com/ocombe/ocModal/commit/727c6d25811f4c2e8607b3909259abc2af585e8d)) 21 | 22 | 23 | 24 | # 0.1.10 (2015-01-08) 25 | 26 | 27 | ## Bug Fixes 28 | 29 | - support for the latest versions of bootstrap 30 | ([8e56e21e](https://github.com/ocombe/ocModal/commit/8e56e21e29a9b2dcb58109eff3eb30fc23691866)) 31 | 32 | 33 | 34 | # 0.1.9 (2014-10-09) 35 | 36 | 37 | ## Bug Fixes 38 | 39 | - revert "height 100% for vertical align center on ie10+" 40 | ([b8d1dcc4](https://github.com/ocombe/ocModal/commit/b8d1dcc4a22c7516740080b49838c6317806e71e)) 41 | 42 | 43 | 44 | # 0.1.8 (2014-10-06) 45 | 46 | 47 | ## Bug Fixes 48 | 49 | - height 100% for vertical align center on ie10+ 50 | ([a39b9b40](https://github.com/ocombe/ocModal/commit/a39b9b40cf61e4a852e1987a731953044563cd99)) 51 | - padding for bootstrap modals 52 | ([4fcb0653](https://github.com/ocombe/ocModal/commit/4fcb0653dba0a4113d719bc4c9daef4d13758409)) 53 | 54 | 55 | 56 | # 0.1.7 (2014-09-18) 57 | 58 | 59 | ## Bug Fixes 60 | 61 | - compatibility with angular 1.3.0 62 | ([ff5c4500](https://github.com/ocombe/ocModal/commit/ff5c45009ad0b5b67b3daf826c128831c54f39fe)) 63 | 64 | 65 | 66 | # 0.1.6 (2014-06-23) 67 | 68 | 69 | ## Bug Fixes 70 | 71 | - bug fixed with backdrop overlay on IE 72 | ([e791f698](https://github.com/ocombe/ocModal/commit/e791f698781ed6b58d7a2053a8254dceaccd4714)) 73 | - max-height on flexbox browsers 74 | ([15a531d26f](https://github.com/ocombe/ocModal/commit/15a531d26ffcac51b5367e3a8e920b03791b9ec7)) 75 | 76 | 77 | 78 | # 0.1.5 (2014-06-17) 79 | 80 | 81 | ## Bug Fixes 82 | 83 | - the slit animation now ends with a nice fade 84 | ([5d27b162](https://github.com/ocombe/ocModal/commit/5d27b1623cc770d6dc6b18ba0f7e66c41d646989)) 85 | - no more blurry modal on chrome 86 | ([153d4db3](https://github.com/ocombe/ocModal/commit/153d4db3a35c03ed2237a6d832f251903b6954a5)) 87 | 88 | 89 | 90 | # 0.1.4 (2014-06-12) 91 | 92 | 93 | ## Bug Fixes 94 | 95 | - destroy the scope of the modal before removing it 96 | ([12d34a76](https://github.com/ocombe/ocModal/commit/12d34a76134531a6ec5bbf4b8e04392edb6cf84b)) 97 | 98 | 99 | 100 | # 0.1.3 (2014-06-11) 101 | 102 | 103 | ## Bug Fixes 104 | 105 | - anim name for fade is fade-in not fade 106 | ([2dc9b931](https://github.com/ocombe/ocModal/commit/2dc9b93119356bad0f19b037e7ec9233fd505c5a)) 107 | - let the modal be responsive on small resolutions 108 | ([02cff9f5](https://github.com/ocombe/ocModal/commit/02cff9f54d94aecb165f8a469847bd7e759dc57a)) 109 | 110 | 111 | ## Features 112 | 113 | - added scss files to dist for bower distribution 114 | ([35b8181d](https://github.com/ocombe/ocModal/commit/35b8181d042e1562de9d6ca2568451c4191d83e0)) 115 | 116 | 117 | 118 | # 0.1.2 (2014-06-05) 119 | 120 | 121 | ## Bug Fixes 122 | 123 | - the close function now returns a promise and resolves after animations 124 | ([3dde4592](https://github.com/ocombe/ocModal/commit/3dde4592bace1b836b2aa4dde8e3ee9a201e31f0)) 125 | 126 | 127 | 128 | # 0.1.1 (2014-06-05) 129 | 130 | 131 | ## Bug Fixes 132 | 133 | - style updates to center modal 134 | ([bc3446cd](https://github.com/ocombe/ocModal/commit/bc3446cdac3e9f1bf32705814a189b6755b42da2)) 135 | 136 | 137 | 138 | # 0.1.0 (2014-06-04) 139 | 140 | 141 | ## Features 142 | 143 | - added animations 144 | ([f99f4ba6](https://github.com/ocombe/ocModal/commit/f99f4ba66f808e3760ea67120792a5af6eace63d), 145 | [#4](https://github.com/ocombe/ocModal/issues/4)) 146 | - adding gulp tasks to build & release 147 | ([d153f425](https://github.com/ocombe/ocModal/commit/d153f425f0e375d9cd8a39ffbf93047c326eb2b0)) 148 | - adding an auto changelog generated by a gulp task 149 | ([5978652b](https://github.com/ocombe/ocModal/commit/5978652b883f14255ac63a0c1bda0af32a747bca)) 150 | 151 | 152 | ## Breaking Changes 153 | 154 | - due to [d153f425](https://github.com/ocombe/ocModal/commit/d153f425f0e375d9cd8a39ffbf93047c326eb2b0), 155 | the src files have been moved to the src folder and the dist files to the dist folder. Update your paths accordingly. 156 | 157 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ocModal 2 | ======= 3 | 4 | An angularJS modal directive & service 5 | 6 | ### Key features 7 | - Easy to use modal 8 | - Dependencies free (well except angular off course) 9 | - Load via the service or the directive 10 | - Style yourself or use the bootstrap's theme 11 | 12 | ### [Demo on Plunker](http://embed.plnkr.co/8QBKgw779g6jT6lmhXS5/) 13 | 14 | ### Usage 15 | - Download the lib (you can use `bower install ocModal`) 16 | - Put ocModal.js into you project 17 | - Add the css file to your project: if you don't have bootstrap 3, include dist/css/ocModal.full.min.css. If you already have bootstrap 3, use dist/css/ocModal.light.min.css 18 | - Add the module ```oc.modal``` to your application 19 | - Load on demand using the service or the directive : 20 | 21 | **Service**: 22 | ```javascript 23 | $ocModal.open('partials/modal.html'); 24 | ``` 25 | or 26 | ```javascript 27 | $ocModal.open('
My content
'); 28 | ``` 29 | 30 | **Directive**: 31 | ```html 32 |
33 | ``` 34 | or 35 | ```html 36 |
37 | ``` 38 | 39 | See the example in the 'example' folder to know how to integrate ocLazyLoad with your router. 40 | 41 | ### Parameters 42 | You can also pass parameters when you open a modal via the service or the directive. The previous examples are equivalent to : 43 | 44 | **Service**: 45 | ```javascript 46 | $ocModal.open({ 47 | url: 'partials/modal.html' 48 | }); 49 | ``` 50 | or 51 | ```javascript 52 | $ocModal.open({ 53 | template: '
My content
' 54 | }); 55 | ``` 56 | 57 | **Directive**: 58 | ```html 59 |
60 | ``` 61 | or 62 | ```html 63 |
64 | ``` 65 | 66 | The complete list of parameters is : 67 | - **id**: you can specify an id for your modal, it is usefull if you want to open more than one modal at the same time 68 | ```javascript 69 | $ocModal.open({ 70 | id: 'modal1', 71 | url: 'partials/modal.html' 72 | }); 73 | ``` 74 | By default the id is set to ```'_default'```. 75 | 76 | - **url**: a template url loaded via [ng-include](http://docs.angularjs.org/api/ng.directive:ngInclude), so you can use an ng-script template or the url of an external html file 77 | 78 | - **template**: if you prefer to write the template in line, you can use the ```template``` parameter instead of ```url```. 79 | 80 | - **controller**: you can pass a controller for the new content 81 | ```javascript 82 | $ocModal.open({ 83 | url: 'partials/modal.html', 84 | controller: 'MyController' 85 | }); 86 | ``` 87 | 88 | - **cls**: You can specify one or more (space separated) classes to be added to the modal 89 | ```javascript 90 | $ocModal.open({ 91 | url: 'partials/modal.html', 92 | cls: 'my-class1 my-class2' 93 | }); 94 | ``` 95 | 96 | - **onOpen**: you can add a callback that will be called when the modal is opened 97 | ```javascript 98 | $ocModal.open({ 99 | url: 'partials/modal.html', 100 | onOpen: function() { 101 | console.log('Just opened !'); 102 | } 103 | }); 104 | ``` 105 | 106 | - **onClose**: you can add a callback that will be called when the modal is closed 107 | ```javascript 108 | $ocModal.open({ 109 | url: 'partials/modal.html', 110 | onClose: function() { 111 | console.log('Just closed !'); 112 | } 113 | }); 114 | ``` 115 | 116 | - **init**: use this to populate the modal scope. If you use a controller you will also be able to access this via $init 117 | ```javascript 118 | $ocModal.open({ 119 | template: '
{{param1}}
', 120 | controller: 'MyController', 121 | init: { 122 | param1: 'test' 123 | } 124 | }); 125 | ``` 126 | 127 | And in your controller : 128 | ```javascript 129 | angular.module('app').controller('MyController', ['$scope', '$init', function($scope, $init) { 130 | console.log($scope.param1, $init.param1); 131 | }]); 132 | ``` 133 | 134 | - **$ocModalParams**: Access the modal params in your controller 135 | ```javascript 136 | angular.module('app').controller('MyController', ['$scope', '$ocModalParams', function($scope, $ocModalParams) { 137 | console.log($ocModalParams); 138 | }]); 139 | ``` 140 | 141 | - **isolate**: by default your modal's scope will inherit the variables from the init parameter. If you don't want that and you prefer to access these variables via the $init in your controller, you can use ```isolate=true``` 142 | ```javascript 143 | $ocModal.open({ 144 | url: 'partials/modal.html', 145 | controller: 'MyController', 146 | isolate: true, 147 | init: { 148 | param1: 'test' 149 | } 150 | }); 151 | ``` 152 | 153 | And use $init in your controller : 154 | ```javascript 155 | angular.module('app').controller('MyController', ['$scope', '$init', function($scope, $init) { 156 | console.log($init.param1); 157 | }]); 158 | ``` 159 | 160 | But ```$scope.param1``` will be ```undefined```. 161 | 162 | - **closeOnEsc**: by default you will be able to close the modal with the "ESC" key. If you want to disable this behaviour, use ```closeOnEsc: false``` 163 | ```javascript 164 | $ocModal.open({ 165 | url: 'partials/modal.html', 166 | closeOnEsc: false 167 | }); 168 | ``` 169 | 170 | ### Functions & attributes 171 | - **open(**__url/template/object__**)**: use this to open the modal 172 | ```javascript 173 | $ocModal.open({ 174 | url: 'partials/modal.html' 175 | }); 176 | ``` 177 | 178 | - **close(**__[id][, param1][, param2][, ...]__**)**: use this to close the modal, it will return a promise that resolves at the end of the closing animation (if any) 179 | ```javascript 180 | $ocModal.close(); 181 | ``` 182 | 183 | With no parameter it will close the last opened modal. If you want to close a specific modal, use the id. 184 | ```javascript 185 | $ocModal.close('modal1'); 186 | ``` 187 | 188 | You can also pass what you want to the onClose callback (if you have one) : 189 | ```javascript 190 | $ocModal.open({ 191 | url: 'partials/modal.html', 192 | onClose: function(a, b, c) { 193 | console.log(a); // arg1 194 | b(); // whatever 195 | console.log(c); // {p1: 'test'} 196 | } 197 | }); 198 | 199 | $ocModal.close('arg1', function() { console.log('whatever') }, {p1: 'test'}); 200 | ``` 201 | 202 | - **$scope.closeModal(**__[id][, param1][, param2][, ...]__**)**: this is an alias for ```$ocModal.close()``` that you can also use in your template 203 | ```html 204 | 205 | ``` 206 | 207 | - **getOpenedModals()**: if you need to get the ids of the opened modals 208 | 209 | - **waitingForOpen**: check this property if you need to know if another modal will be opened once this one is closed 210 | ```javascript 211 | $ocModal.open({ 212 | url: "partials/login.html", 213 | controller: 'LoginCtrl', 214 | onClose: function() { 215 | if(!$ocModal.waitingForOpen) { 216 | $state.transitionTo('welcome'); 217 | } 218 | } 219 | }); 220 | ``` 221 | 222 | ### Directives 223 | - **oc-modal-open**: this is an alias for ```$ocModal.open()``` that you can also use in your template. 224 | ```html 225 |
226 | ``` 227 | 228 | - **oc-modal-close**: this is an alias for ```$ocModal.close()``` that you can also use in your template. 229 | ```html 230 | 231 | ``` 232 | 233 | ### Animations 234 | You can use a set of animations by including the file ocModal.animations.css and by adding one of those classes with the cls parameter : 235 | - fade-in 236 | - slide-down 237 | - scale 238 | - fall 239 | - flip-horizontal 240 | - flip-vertical 241 | - super-scaled 242 | - slit 243 | 244 | ```javascript 245 | oc-modal-open="{url: 'partials/modal.html', cls: 'fade-in'}" 246 | ``` 247 | 248 | You can add your own animations by adding new styles to `.modal .modal-dialog .modal-content` and `.modal .modal-dialog .modal-content.opened`. 249 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocModal", 3 | "main": "dist/ocModal.min.js", 4 | "version": "0.1.12", 5 | "homepage": "https://github.com/ocombe/ocModal", 6 | "authors": [ 7 | "Olivier Combe " 8 | ], 9 | "description": "An angularJS modal directive / service", 10 | "keywords": [ 11 | "modal", 12 | "dialog", 13 | "module", 14 | "angular", 15 | "angularJS" 16 | ], 17 | "license": "MIT", 18 | "ignore": [ 19 | "**/.*", 20 | "node_modules", 21 | "bower_components", 22 | "src", 23 | "gulpfile.js", 24 | "package.json" 25 | ] 26 | } -------------------------------------------------------------------------------- /dist/css/ocModal.animations.css: -------------------------------------------------------------------------------- 1 | .modal .modal-dialog .modal-content.fade-in { 2 | -webkit-transition: opacity 0.5s; 3 | -moz-transition: opacity 0.5s; 4 | transition: opacity 0.5s; 5 | opacity: 0; } 6 | .modal .modal-dialog .modal-content.fade-in.opened { 7 | opacity: 1; } 8 | 9 | .modal .modal-dialog .modal-content.slide-down { 10 | -webkit-transition: opacity, -webkit-transform; 11 | -moz-transition: opacity, -moz-transform; 12 | transition: opacity, transform; 13 | -webkit-transform: translateY(-20%); 14 | -moz-transform: translateY(-20%); 15 | -ms-transform: translateY(-20%); 16 | -o-transform: translateY(-20%); 17 | transform: translateY(-20%); 18 | opacity: 0; } 19 | .modal .modal-dialog .modal-content.slide-down.slide-down.opened { 20 | -webkit-transform: translateY(0%); 21 | -moz-transform: translateY(0%); 22 | -ms-transform: translateY(0%); 23 | -o-transform: translateY(0%); 24 | transform: translateY(0%); 25 | opacity: 1; } 26 | 27 | .modal .modal-dialog .modal-content.scale { 28 | -webkit-transform: scale(0.7); 29 | -moz-transform: scale(0.7); 30 | -ms-transform: scale(0.7); 31 | -o-transform: scale(0.7); 32 | transform: scale(0.7); 33 | -webkit-transition: -webkit-transform, opacity; 34 | -moz-transition: -moz-transform, opacity; 35 | transition: transform, opacity; 36 | opacity: 0; } 37 | .modal .modal-dialog .modal-content.scale.opened { 38 | -webkit-transform: scale(1); 39 | -moz-transform: scale(1); 40 | -ms-transform: scale(1); 41 | -o-transform: scale(1); 42 | transform: scale(1); 43 | opacity: 1; } 44 | 45 | .modal .modal-dialog .modal-content.fall { 46 | -webkit-transform-style: preserve-3d; 47 | -moz-transform-style: preserve-3d; 48 | -ms-transform-style: preserve-3d; 49 | -o-transform-style: preserve-3d; 50 | transform-style: preserve-3d; 51 | -webkit-transform: translateZ(600px) rotateX(20deg); 52 | -moz-transform: translateZ(600px) rotateX(20deg); 53 | -ms-transform: translateZ(600px) rotateX(20deg); 54 | -o-transform: translateZ(600px) rotateX(20deg); 55 | transform: translateZ(600px) rotateX(20deg); 56 | -webkit-transition: -webkit-transform, opacity; 57 | -moz-transition: -moz-transform, opacity; 58 | transition: transform, opacity; 59 | opacity: 0; } 60 | .modal .modal-dialog .modal-content.fall.opened { 61 | -webkit-transform: translateZ(0) rotateX(0deg); 62 | -moz-transform: translateZ(0) rotateX(0deg); 63 | -ms-transform: translateZ(0) rotateX(0deg); 64 | -o-transform: translateZ(0) rotateX(0deg); 65 | transform: translateZ(0) rotateX(0deg); 66 | opacity: 1; } 67 | 68 | .modal .modal-dialog .modal-content.flip-horizontal { 69 | -webkit-transform-style: preserve-3d; 70 | -moz-transform-style: preserve-3d; 71 | -ms-transform-style: preserve-3d; 72 | -o-transform-style: preserve-3d; 73 | transform-style: preserve-3d; 74 | -webkit-transform: rotateY(-70deg); 75 | -moz-transform: rotateY(-70deg); 76 | -ms-transform: rotateY(-70deg); 77 | -o-transform: rotateY(-70deg); 78 | transform: rotateY(-70deg); 79 | -webkit-transition: -webkit-transform, opacity; 80 | -moz-transition: -moz-transform, opacity; 81 | transition: transform, opacity; 82 | opacity: 0; } 83 | .modal .modal-dialog .modal-content.flip-horizontal.opened { 84 | -webkit-transform: rotateY(0deg); 85 | -moz-transform: rotateY(0deg); 86 | -ms-transform: rotateY(0deg); 87 | -o-transform: rotateY(0deg); 88 | transform: rotateY(0deg); 89 | opacity: 1; } 90 | 91 | .modal .modal-dialog .modal-content.flip-vertical { 92 | -webkit-transform-style: preserve-3d; 93 | -moz-transform-style: preserve-3d; 94 | -ms-transform-style: preserve-3d; 95 | -o-transform-style: preserve-3d; 96 | transform-style: preserve-3d; 97 | -webkit-transform: rotateX(-70deg); 98 | -moz-transform: rotateX(-70deg); 99 | -ms-transform: rotateX(-70deg); 100 | -o-transform: rotateX(-70deg); 101 | transform: rotateX(-70deg); 102 | -webkit-transition: -webkit-transform, opacity; 103 | -moz-transition: -moz-transform, opacity; 104 | transition: transform, opacity; 105 | opacity: 0; } 106 | .modal .modal-dialog .modal-content.flip-vertical.opened { 107 | -webkit-transform: rotateX(0deg); 108 | -moz-transform: rotateX(0deg); 109 | -ms-transform: rotateX(0deg); 110 | -o-transform: rotateX(0deg); 111 | transform: rotateX(0deg); 112 | opacity: 1; } 113 | 114 | .modal .modal-dialog .modal-content.super-scaled { 115 | -webkit-transform: scale(2); 116 | -moz-transform: scale(2); 117 | -ms-transform: scale(2); 118 | -o-transform: scale(2); 119 | transform: scale(2); 120 | -webkit-transition: -webkit-transform, opacity; 121 | -moz-transition: -moz-transform, opacity; 122 | transition: transform, opacity; 123 | opacity: 0; } 124 | .modal .modal-dialog .modal-content.super-scaled.opened { 125 | -webkit-transform: scale(1); 126 | -moz-transform: scale(1); 127 | -ms-transform: scale(1); 128 | -o-transform: scale(1); 129 | transform: scale(1); 130 | opacity: 1; } 131 | 132 | .modal .modal-dialog .modal-content.slit { 133 | -webkit-transform-style: preserve-3d; 134 | -moz-transform-style: preserve-3d; 135 | -ms-transform-style: preserve-3d; 136 | -o-transform-style: preserve-3d; 137 | transform-style: preserve-3d; 138 | -webkit-transition: opacity 0.5s; 139 | -moz-transition: opacity 0.5s; 140 | transition: opacity 0.5s; 141 | opacity: 0; } 142 | .modal .modal-dialog .modal-content.slit.opened { 143 | opacity: 1; 144 | -webkit-transform: translateZ(-3000px) rotateY(90deg); 145 | -moz-transform: translateZ(-3000px) rotateY(90deg); 146 | -ms-transform: translateZ(-3000px) rotateY(90deg); 147 | -o-transform: translateZ(-3000px) rotateY(90deg); 148 | transform: translateZ(-3000px) rotateY(90deg); 149 | -webkit-animation: slit 0.7s forwards ease-out; 150 | -moz-animation: slit 0.7s forwards ease-out; 151 | animation: slit 0.7s forwards ease-out; } 152 | 153 | @-webkit-keyframes slit { 154 | 50% { 155 | -webkit-transform: translateZ(-250px) rotateY(89deg); 156 | -webkit-animation-timing-function: ease-out; } 157 | 100% { 158 | -webkit-transform: translateZ(0) rotateY(0deg); } } 159 | 160 | @-moz-keyframes slit { 161 | 50% { 162 | -moz-transform: translateZ(-250px) rotateY(89deg); 163 | opacity: .5; 164 | -moz-animation-timing-function: ease-out; } 165 | 100% { 166 | -moz-transform: translateZ(0) rotateY(0deg); } } 167 | 168 | @keyframes slit { 169 | 50% { 170 | transform: translateZ(-250px) rotateY(89deg); 171 | animation-timing-function: ease-in; } 172 | 100% { 173 | transform: translateZ(0) rotateY(0deg); } } 174 | -------------------------------------------------------------------------------- /dist/css/ocModal.animations.min.css: -------------------------------------------------------------------------------- 1 | .modal .modal-dialog .modal-content.fade-in{-webkit-transition:opacity .5s;-moz-transition:opacity .5s;transition:opacity .5s;opacity:0}.modal .modal-dialog .modal-content.fade-in.opened{opacity:1}.modal .modal-dialog .modal-content.slide-down{-webkit-transition:opacity,-webkit-transform;-moz-transition:opacity,-moz-transform;transition:opacity,transform;-webkit-transform:translateY(-20%);-moz-transform:translateY(-20%);-ms-transform:translateY(-20%);-o-transform:translateY(-20%);transform:translateY(-20%);opacity:0}.modal .modal-dialog .modal-content.fall,.modal .modal-dialog .modal-content.scale{-webkit-transition:-webkit-transform,opacity;-moz-transition:-moz-transform,opacity}.modal .modal-dialog .modal-content.slide-down.slide-down.opened{-webkit-transform:translateY(0);-moz-transform:translateY(0);-ms-transform:translateY(0);-o-transform:translateY(0);transform:translateY(0);opacity:1}.modal .modal-dialog .modal-content.scale{-webkit-transform:scale(.7);-moz-transform:scale(.7);-ms-transform:scale(.7);-o-transform:scale(.7);transform:scale(.7);transition:transform,opacity;opacity:0}.modal .modal-dialog .modal-content.scale.opened{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1);opacity:1}.modal .modal-dialog .modal-content.fall{-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;-o-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform:translateZ(600px) rotateX(20deg);-moz-transform:translateZ(600px) rotateX(20deg);-ms-transform:translateZ(600px) rotateX(20deg);-o-transform:translateZ(600px) rotateX(20deg);transform:translateZ(600px) rotateX(20deg);transition:transform,opacity;opacity:0}.modal .modal-dialog .modal-content.fall.opened{-webkit-transform:translateZ(0) rotateX(0);-moz-transform:translateZ(0) rotateX(0);-ms-transform:translateZ(0) rotateX(0);-o-transform:translateZ(0) rotateX(0);transform:translateZ(0) rotateX(0);opacity:1}.modal .modal-dialog .modal-content.flip-horizontal{-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;-o-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform:rotateY(-70deg);-moz-transform:rotateY(-70deg);-ms-transform:rotateY(-70deg);-o-transform:rotateY(-70deg);transform:rotateY(-70deg);-webkit-transition:-webkit-transform,opacity;-moz-transition:-moz-transform,opacity;transition:transform,opacity;opacity:0}.modal .modal-dialog .modal-content.flip-horizontal.opened{-webkit-transform:rotateY(0);-moz-transform:rotateY(0);-ms-transform:rotateY(0);-o-transform:rotateY(0);transform:rotateY(0);opacity:1}.modal .modal-dialog .modal-content.flip-vertical{-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;-o-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transform:rotateX(-70deg);-moz-transform:rotateX(-70deg);-ms-transform:rotateX(-70deg);-o-transform:rotateX(-70deg);transform:rotateX(-70deg);-webkit-transition:-webkit-transform,opacity;-moz-transition:-moz-transform,opacity;transition:transform,opacity;opacity:0}.modal .modal-dialog .modal-content.flip-vertical.opened{-webkit-transform:rotateX(0);-moz-transform:rotateX(0);-ms-transform:rotateX(0);-o-transform:rotateX(0);transform:rotateX(0);opacity:1}.modal .modal-dialog .modal-content.super-scaled{-webkit-transform:scale(2);-moz-transform:scale(2);-ms-transform:scale(2);-o-transform:scale(2);transform:scale(2);-webkit-transition:-webkit-transform,opacity;-moz-transition:-moz-transform,opacity;transition:transform,opacity;opacity:0}.modal .modal-dialog .modal-content.super-scaled.opened{-webkit-transform:scale(1);-moz-transform:scale(1);-ms-transform:scale(1);-o-transform:scale(1);transform:scale(1);opacity:1}.modal .modal-dialog .modal-content.slit{-webkit-transform-style:preserve-3d;-moz-transform-style:preserve-3d;-ms-transform-style:preserve-3d;-o-transform-style:preserve-3d;transform-style:preserve-3d;-webkit-transition:opacity .5s;-moz-transition:opacity .5s;transition:opacity .5s;opacity:0}.modal .modal-dialog .modal-content.slit.opened{opacity:1;-webkit-transform:translateZ(-3000px) rotateY(90deg);-moz-transform:translateZ(-3000px) rotateY(90deg);-ms-transform:translateZ(-3000px) rotateY(90deg);-o-transform:translateZ(-3000px) rotateY(90deg);transform:translateZ(-3000px) rotateY(90deg);-webkit-animation:slit .7s forwards ease-out;-moz-animation:slit .7s forwards ease-out;animation:slit .7s forwards ease-out}@-webkit-keyframes slit{50%{-webkit-transform:translateZ(-250px) rotateY(89deg);-webkit-animation-timing-function:ease-out}100%{-webkit-transform:translateZ(0) rotateY(0)}}@-moz-keyframes slit{50%{-moz-transform:translateZ(-250px) rotateY(89deg);opacity:.5;-moz-animation-timing-function:ease-out}100%{-moz-transform:translateZ(0) rotateY(0)}}@keyframes slit{50%{transform:translateZ(-250px) rotateY(89deg);animation-timing-function:ease-in}100%{transform:translateZ(0) rotateY(0)}} -------------------------------------------------------------------------------- /dist/css/ocModal.full.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | *, 3 | *:before, 4 | *:after { 5 | -webkit-box-sizing: border-box; 6 | -moz-box-sizing: border-box; 7 | box-sizing: border-box; } 8 | 9 | .modal-open { 10 | overflow: hidden; } 11 | 12 | .modal { 13 | display: none; 14 | overflow: auto; 15 | overflow-y: scroll; 16 | position: fixed; 17 | top: 0; 18 | right: 0; 19 | bottom: 0; 20 | left: 0; 21 | z-index: 1040; } 22 | .modal.fade .modal-dialog { 23 | -webkit-transform: translate(0, -25%); 24 | -ms-transform: translate(0, -25%); 25 | transform: translate(0, -25%); 26 | -webkit-transition: -webkit-transform 0.3s ease-out; 27 | -moz-transition: -moz-transform 0.3s ease-out; 28 | -o-transition: -o-transform 0.3s ease-out; 29 | transition: transform 0.3s ease-out; } 30 | .modal.in .modal-dialog { 31 | -webkit-transform: translate(0, 0); 32 | -ms-transform: translate(0, 0); 33 | transform: translate(0, 0); } 34 | 35 | .modal-dialog { 36 | position: relative; 37 | margin-left: auto; 38 | margin-right: auto; 39 | width: auto; 40 | padding: 10px; 41 | z-index: 1050; } 42 | 43 | .modal-content { 44 | position: relative; 45 | background-color: #fff; 46 | border: 1px solid #999; 47 | border: 1px solid rgba(0, 0, 0, 0.2); 48 | border-radius: 6px; 49 | -webkit-box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); 50 | box-shadow: 0 3px 9px rgba(0, 0, 0, 0.5); 51 | background-clip: padding-box; 52 | outline: none; } 53 | 54 | .modal-backdrop { 55 | position: fixed; 56 | top: 0; 57 | right: 0; 58 | bottom: 0; 59 | left: 0; 60 | z-index: 1030; 61 | background-color: #CCCCCC; } 62 | .modal-backdrop.fade { 63 | opacity: 0; 64 | filter: alpha(opacity=0); } 65 | .modal-backdrop.in { 66 | opacity: 0.5; 67 | filter: alpha(opacity=50); } 68 | 69 | .modal-header { 70 | padding: 15px; 71 | border-bottom: 1px solid transparent; 72 | min-height: 16.42857px; } 73 | 74 | .modal-header .close { 75 | margin-top: -2px; } 76 | 77 | .modal-title { 78 | margin: 0; 79 | line-height: 1.42857; } 80 | 81 | .modal-body { 82 | position: relative; 83 | padding: 20px; } 84 | 85 | .modal-footer { 86 | margin-top: 15px; 87 | padding: 19px 20px 20px; 88 | text-align: right; 89 | border-top: 1px solid transparent; } 90 | .modal-footer:before, .modal-footer:after { 91 | content: " "; 92 | /* 1 */ 93 | display: table; 94 | /* 2 */ } 95 | .modal-footer:after { 96 | clear: both; } 97 | .modal-footer .btn + .btn { 98 | margin-left: 5px; 99 | margin-bottom: 0; } 100 | .modal-footer .btn-group .btn + .btn { 101 | margin-left: -1px; } 102 | .modal-footer .btn-block + .btn-block { 103 | margin-left: 0; } 104 | 105 | @media screen and (min-width: 768px) { 106 | .modal-dialog { 107 | width: 600px; 108 | padding-top: 30px; 109 | padding-bottom: 30px; } 110 | .modal-content { 111 | -webkit-box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); 112 | box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); } } 113 | 114 | .noOverflow { 115 | overflow: hidden; } 116 | 117 | .modal-wrapper { 118 | z-index: 1050; 119 | position: fixed; } 120 | .modal-wrapper .modal-backdrop { 121 | width: 100%; 122 | height: 100%; 123 | opacity: 0.8; 124 | filter: alpha(opacity=80); } 125 | 126 | .modal { 127 | display: block; 128 | overflow: auto; 129 | text-align: center; } 130 | .modal .modal-dialog { 131 | z-index: 1060; 132 | width: auto; 133 | text-align: left; 134 | /* on rétablit l'alignement du texte */ 135 | -webkit-perspective: 1300px; 136 | -moz-perspective: 1300px; 137 | perspective: 1300px; 138 | max-width: 100%; } 139 | .modal .modal-dialog.no-backdrop .modal-backdrop { 140 | display: none; } 141 | .modal .modal-dialog .modal-content { 142 | z-index: 1050; 143 | border-radius: 2px; 144 | width: 600px; 145 | padding: 10px; 146 | max-width: 100%; 147 | margin: 0; } 148 | 149 | .flexbox .modal > .modal-backdrop { 150 | display: none; } 151 | 152 | .flexbox .modal .modal-dialog { 153 | display: -webkit-box; 154 | display: -moz-box; 155 | display: box; 156 | display: -webkit-flex; 157 | display: -moz-flex; 158 | display: -ms-flexbox; 159 | display: flex; 160 | -webkit-box-align: center; 161 | -moz-box-align: center; 162 | box-align: center; 163 | -webkit-align-items: center; 164 | -moz-align-items: center; 165 | -ms-align-items: center; 166 | -o-align-items: center; 167 | align-items: center; 168 | -ms-flex-align: center; 169 | -webkit-box-pack: center; 170 | -moz-box-pack: center; 171 | box-pack: center; 172 | -webkit-justify-content: center; 173 | -moz-justify-content: center; 174 | -ms-justify-content: center; 175 | -o-justify-content: center; 176 | justify-content: center; 177 | -ms-flex-pack: center; 178 | position: absolute; 179 | width: 100%; 180 | min-height: 100%; 181 | height: 100%; 182 | margin: 0; 183 | padding: 10px; 184 | max-height: initial; } 185 | 186 | .no-flexbox .modal-dialog { 187 | -webkit-transform: translate(-50%, -50%); 188 | -moz-transform: translate(-50%, -50%); 189 | -ms-transform: translate(-50%, -50%); 190 | -o-transform: translate(-50%, -50%); 191 | transform: translate(-50%, -50%); 192 | position: absolute; 193 | left: 50%; 194 | top: 50%; 195 | margin: 0; 196 | padding: 10px; 197 | max-height: 100%; } 198 | .no-flexbox .modal-dialog .modal-backdrop { 199 | display: none; } 200 | 201 | .no-flexbox.no-csstransforms .modal-dialog { 202 | left: auto; 203 | top: auto; 204 | margin: auto; } 205 | 206 | .lt-ie8 .modal-content { 207 | display: inline; 208 | zoom: 1; } 209 | -------------------------------------------------------------------------------- /dist/css/ocModal.full.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";.modal,.modal-backdrop{top:0;right:0;bottom:0;left:0}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.modal-open{overflow:hidden}.modal{overflow-y:scroll;position:fixed;z-index:1040}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;margin-left:auto;margin-right:auto;width:auto;padding:10px;z-index:1050}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,.2);border-radius:6px;-webkit-box-shadow:0 3px 9px rgba(0,0,0,.5);box-shadow:0 3px 9px rgba(0,0,0,.5);background-clip:padding-box;outline:0}.modal-backdrop{position:fixed;z-index:1030;background-color:#CCC}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{padding:15px;border-bottom:1px solid transparent;min-height:16.43px}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.42857}.modal-body{position:relative;padding:20px}.modal-footer{margin-top:15px;padding:19px 20px 20px;text-align:right;border-top:1px solid transparent}.modal-footer:after,.modal-footer:before{content:" ";display:table}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;padding-top:30px;padding-bottom:30px}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,.5);box-shadow:0 5px 15px rgba(0,0,0,.5)}}.noOverflow{overflow:hidden}.modal-wrapper{z-index:1050;position:fixed}.modal-wrapper .modal-backdrop{width:100%;height:100%;opacity:.8;filter:alpha(opacity=80)}.modal{display:block;overflow:auto;text-align:center}.flexbox .modal>.modal-backdrop,.modal .modal-dialog.no-backdrop .modal-backdrop{display:none}.modal .modal-dialog{z-index:1060;width:auto;text-align:left;-webkit-perspective:1300px;-moz-perspective:1300px;perspective:1300px;max-width:100%}.modal .modal-dialog .modal-content{z-index:1050;border-radius:2px;width:600px;padding:10px;max-width:100%;margin:0}.flexbox .modal .modal-dialog{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-o-justify-content:center;justify-content:center;-ms-flex-pack:center;position:absolute;width:100%;min-height:100%;height:100%;margin:0;padding:10px;max-height:initial}.no-flexbox .modal-dialog{-webkit-transform:translate(-50%,-50%);-moz-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);-o-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;left:50%;top:50%;margin:0;padding:10px;max-height:100%}.no-flexbox .modal-dialog .modal-backdrop{display:none}.no-flexbox.no-csstransforms .modal-dialog{left:auto;top:auto;margin:auto}.lt-ie8 .modal-content{display:inline;zoom:1} -------------------------------------------------------------------------------- /dist/css/ocModal.light.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | .noOverflow { 3 | overflow: hidden; } 4 | 5 | .modal-wrapper { 6 | z-index: 1050; 7 | position: fixed; } 8 | .modal-wrapper .modal-backdrop { 9 | width: 100%; 10 | height: 100%; 11 | opacity: 0.8; 12 | filter: alpha(opacity=80); } 13 | 14 | .modal { 15 | display: block; 16 | overflow: auto; 17 | text-align: center; } 18 | .modal .modal-dialog { 19 | z-index: 1060; 20 | width: auto; 21 | text-align: left; 22 | /* on rétablit l'alignement du texte */ 23 | -webkit-perspective: 1300px; 24 | -moz-perspective: 1300px; 25 | perspective: 1300px; 26 | max-width: 100%; } 27 | .modal .modal-dialog.no-backdrop .modal-backdrop { 28 | display: none; } 29 | .modal .modal-dialog .modal-content { 30 | z-index: 1050; 31 | border-radius: 2px; 32 | width: 600px; 33 | padding: 10px; 34 | max-width: 100%; 35 | margin: 0; } 36 | 37 | .flexbox .modal > .modal-backdrop { 38 | display: none; } 39 | 40 | .flexbox .modal .modal-dialog { 41 | display: -webkit-box; 42 | display: -moz-box; 43 | display: box; 44 | display: -webkit-flex; 45 | display: -moz-flex; 46 | display: -ms-flexbox; 47 | display: flex; 48 | -webkit-box-align: center; 49 | -moz-box-align: center; 50 | box-align: center; 51 | -webkit-align-items: center; 52 | -moz-align-items: center; 53 | -ms-align-items: center; 54 | -o-align-items: center; 55 | align-items: center; 56 | -ms-flex-align: center; 57 | -webkit-box-pack: center; 58 | -moz-box-pack: center; 59 | box-pack: center; 60 | -webkit-justify-content: center; 61 | -moz-justify-content: center; 62 | -ms-justify-content: center; 63 | -o-justify-content: center; 64 | justify-content: center; 65 | -ms-flex-pack: center; 66 | position: absolute; 67 | width: 100%; 68 | min-height: 100%; 69 | height: 100%; 70 | margin: 0; 71 | padding: 10px; 72 | max-height: initial; } 73 | 74 | .no-flexbox .modal-dialog { 75 | -webkit-transform: translate(-50%, -50%); 76 | -moz-transform: translate(-50%, -50%); 77 | -ms-transform: translate(-50%, -50%); 78 | -o-transform: translate(-50%, -50%); 79 | transform: translate(-50%, -50%); 80 | position: absolute; 81 | left: 50%; 82 | top: 50%; 83 | margin: 0; 84 | padding: 10px; 85 | max-height: 100%; } 86 | .no-flexbox .modal-dialog .modal-backdrop { 87 | display: none; } 88 | 89 | .no-flexbox.no-csstransforms .modal-dialog { 90 | left: auto; 91 | top: auto; 92 | margin: auto; } 93 | 94 | .lt-ie8 .modal-content { 95 | display: inline; 96 | zoom: 1; } 97 | -------------------------------------------------------------------------------- /dist/css/ocModal.light.min.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8";.noOverflow{overflow:hidden}.modal-wrapper{z-index:1050;position:fixed}.modal-wrapper .modal-backdrop{width:100%;height:100%;opacity:.8;filter:alpha(opacity=80)}.modal{display:block;overflow:auto;text-align:center}.flexbox .modal>.modal-backdrop,.modal .modal-dialog.no-backdrop .modal-backdrop{display:none}.modal .modal-dialog{z-index:1060;width:auto;text-align:left;-webkit-perspective:1300px;-moz-perspective:1300px;perspective:1300px;max-width:100%}.modal .modal-dialog .modal-content{z-index:1050;border-radius:2px;width:600px;padding:10px;max-width:100%;margin:0}.flexbox .modal .modal-dialog{display:-webkit-box;display:-moz-box;display:box;display:-webkit-flex;display:-moz-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-moz-box-align:center;box-align:center;-webkit-align-items:center;-moz-align-items:center;-ms-align-items:center;-o-align-items:center;align-items:center;-ms-flex-align:center;-webkit-box-pack:center;-moz-box-pack:center;box-pack:center;-webkit-justify-content:center;-moz-justify-content:center;-ms-justify-content:center;-o-justify-content:center;justify-content:center;-ms-flex-pack:center;position:absolute;width:100%;min-height:100%;height:100%;margin:0;padding:10px;max-height:initial}.no-flexbox .modal-dialog{-webkit-transform:translate(-50%,-50%);-moz-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);-o-transform:translate(-50%,-50%);transform:translate(-50%,-50%);position:absolute;left:50%;top:50%;margin:0;padding:10px;max-height:100%}.no-flexbox .modal-dialog .modal-backdrop{display:none}.no-flexbox.no-csstransforms .modal-dialog{left:auto;top:auto;margin:auto}.lt-ie8 .modal-content{display:inline;zoom:1} -------------------------------------------------------------------------------- /dist/ocModal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ocmodal - An angularJS modal directive / service 3 | * @version v0.1.12 4 | * @link https://github.com/ocombe/ocModal 5 | * @license MIT 6 | * @author Olivier Combe 7 | */ 8 | (function() { 9 | 'use strict'; 10 | 11 | var ocModal = angular.module('oc.modal', []); 12 | 13 | ocModal.factory('$ocModal', ['$rootScope', '$controller', '$location', '$timeout', '$compile', '$sniffer', '$q', function($rootScope, $controller, $location, $timeout, $compile, $sniffer, $q) { 14 | var $body = angular.element(document.body), 15 | $dialogsWrapper = angular.element(''), 16 | $modalWrapper = angular.element( 17 | '' 18 | ), 19 | modals = {}, 20 | openedModals = [], 21 | baseOverflow; 22 | 23 | // include the modal in DOM at start for animations 24 | $modalWrapper.css('display', 'none'); 25 | $modalWrapper.append($dialogsWrapper); 26 | $body.append($modalWrapper); 27 | $dialogsWrapper.on('click', function(e) { 28 | if(angular.element(e.target).hasClass('modal-backdrop')) { // only if clicked on backdrop 29 | $rootScope.$apply(function() { 30 | self.closeOnEsc(); 31 | }); 32 | } 33 | }); 34 | 35 | var parseMaxTime = function parseMaxTime(str) { 36 | var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : []; 37 | angular.forEach(values, function(value) { 38 | total = Math.max(parseFloat(value) || 0, total); 39 | }); 40 | return total; 41 | }; 42 | 43 | var getAnimDuration = function getDuration($element) { 44 | var duration = 0; 45 | if(($sniffer.transitions || $sniffer.animations)) { 46 | //one day all browsers will have these properties 47 | var w3cAnimationProp = 'animation'; 48 | var w3cTransitionProp = 'transition'; 49 | 50 | //but some still use vendor-prefixed styles 51 | var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation'; 52 | var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; 53 | 54 | var durationKey = 'Duration', 55 | delayKey = 'Delay', 56 | animationIterationCountKey = 'IterationCount'; 57 | 58 | //we want all the styles defined before and after 59 | var ELEMENT_NODE = 1; 60 | angular.forEach($element, function(element) { 61 | if(element.nodeType == ELEMENT_NODE) { 62 | var elementStyles = window.getComputedStyle(element) || {}; 63 | 64 | var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]), 65 | parseMaxTime(elementStyles[vendorTransitionProp + delayKey])); 66 | 67 | var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]), 68 | parseMaxTime(elementStyles[vendorAnimationProp + delayKey])); 69 | 70 | var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]), 71 | parseMaxTime(elementStyles[vendorTransitionProp + durationKey])); 72 | 73 | var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]), 74 | parseMaxTime(elementStyles[vendorAnimationProp + durationKey])); 75 | 76 | if(animationDuration > 0) { 77 | animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0, 78 | parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0, 1); 79 | } 80 | 81 | duration = Math.max(animationDelay + animationDuration, transitionDelay + transitionDuration, duration); 82 | } 83 | }); 84 | } 85 | 86 | return duration * 1000; 87 | }; 88 | 89 | angular.element(document).on('keyup', function(e) { 90 | if (e.keyCode == 27 && openedModals.length > 0) { 91 | e.stopPropagation(); 92 | $rootScope.$apply(function() { 93 | self.closeOnEsc(openedModals[openedModals.length - 1]); 94 | }); 95 | } 96 | }); 97 | 98 | var self = { 99 | waitingForOpen: false, 100 | 101 | getOpenedModals: function() { 102 | return openedModals; 103 | }, 104 | 105 | register: function(params) { 106 | modals[params.id || '_default'] = params; 107 | }, 108 | 109 | remove: function(id) { 110 | delete modals[id || '_default']; 111 | }, 112 | 113 | open: function(opt) { 114 | if(typeof opt === 'string') { 115 | if(opt.match('<')) { // if html code 116 | opt = { 117 | template: opt 118 | } 119 | } else { 120 | opt = { 121 | url: opt 122 | } 123 | } 124 | } 125 | var modal = modals[opt.id || '_default']; 126 | if(!modal) { 127 | $dialogsWrapper.append($compile('
')($rootScope)); 128 | $timeout(function() { // let the ng-include detect that it's now empty 129 | self.open(opt); 130 | }); 131 | return; 132 | } else if(modal && openedModals.indexOf(opt.id || '_default') !== -1) { // if modal already opened 133 | if(self.waitingForOpen) { 134 | return; 135 | } 136 | self.waitingForOpen = true; 137 | self.close(opt.id).then(function() { 138 | self.open(opt); 139 | }); 140 | return; 141 | } 142 | // ok let's open the modal 143 | if(!self.waitingForOpen) { 144 | if(openedModals.length === 0) { // if no modal opened 145 | baseOverflow = document.body.style.overflow; 146 | document.body.style.overflow = 'hidden'; 147 | $modalWrapper.css('display', 'block'); 148 | } else { 149 | for(var i = 0, len = openedModals.length; i < len; i++) { 150 | var $e = modals[openedModals[i]].$element; 151 | modals[openedModals[i]].baseZIndex = $e.css('z-index'); 152 | $e.css('z-index', '-1'); 153 | $e.addClass('no-backdrop'); 154 | } 155 | } 156 | } 157 | self.waitingForOpen = false; 158 | openedModals.push(opt.id || '_default'); 159 | modal.params = opt; 160 | modal.$scope.customClass = modal.params.cls; 161 | 162 | // timeout for animations (if any) 163 | $rootScope.$digest(); 164 | $body[0].offsetWidth; // force paint to be sure the element is in the page 165 | $timeout(function() { 166 | modal.$scope.modalShow = true; 167 | }, 100); 168 | 169 | if(typeof modal.params.onOpen === 'function') { 170 | modal.params.onOpen(); 171 | } 172 | 173 | var off = modal.$scope.$on('$includeContentLoaded', function(event) { // on view load 174 | if(modal.params.init && !modal.params.isolate) { 175 | angular.extend(event.targetScope, modal.params.init); 176 | } 177 | if(typeof modal.params.controller === 'string') { 178 | $controller(modal.params.controller, {$scope: event.targetScope, $init: modal.params.init, $ocModalParams: modal.params}); // inject controller 179 | } 180 | off(); 181 | }); 182 | 183 | if(modal.params.template) { 184 | modal.$scope.modalTemplate = modal.params.template; // load the view 185 | } else if(modal.params.url) { 186 | modal.$scope.modalUrl = modal.params.url; // load the view 187 | } else { 188 | throw "You need to define a template or an url"; 189 | return; 190 | } 191 | 192 | if(typeof callback === 'function') { 193 | modal.$scope.callbacksList.push(callback); 194 | } 195 | }, 196 | 197 | closeOnEsc: function(id) { 198 | if(modals[id || openedModals[openedModals.length -1]].params.closeOnEsc !== false) { 199 | return self.close(id); 200 | } 201 | }, 202 | 203 | close: function(id) { 204 | var args, 205 | deferred = $q.defer(); 206 | if(typeof id === 'string' && openedModals.indexOf(id) !== -1) { 207 | args = Array.prototype.slice.call(arguments, 1); 208 | } else { 209 | args = arguments; 210 | } 211 | if(typeof id === 'undefined' || openedModals.indexOf(id) === -1) { 212 | id = openedModals[openedModals.length -1]; 213 | } 214 | var modal = modals[id || openedModals[openedModals.length -1]]; 215 | if(modal && modal.$scope.modalShow === true) { // if the modal is opened 216 | var animDuration = getAnimDuration(angular.element(modal.$element[0].querySelector('.modal-content'))); 217 | $timeout(function() { 218 | modal.$scope.modalShow = false; 219 | 220 | $timeout(function() { 221 | modal.$scope.$destroy(); 222 | modal.$element.remove(); // destroy the modal 223 | 224 | modal.callbacksList = []; // forget all callbacks 225 | openedModals.splice(openedModals.indexOf(id || openedModals[openedModals.length -1]), 1); 226 | if(openedModals.length === 0) { // if no modal left opened 227 | if(!self.waitingForOpen) { // in case the current modal is closed because another opened with the same id (avoid backdrop flickering in firefox) 228 | document.body.style.overflow = baseOverflow; // restore the body overflow 229 | $modalWrapper.css('display', 'none'); 230 | } 231 | } else { 232 | var topModal = modals[openedModals[openedModals.length - 1]]; 233 | topModal.$element.css('z-index', topModal.baseZIndex); 234 | topModal.$element.removeClass('no-backdrop'); 235 | } 236 | if(typeof modal.params.onClose === 'function') { 237 | modal.params.onClose.apply(undefined, args); 238 | } 239 | 240 | deferred.resolve(); 241 | }, animDuration); 242 | }); 243 | } else { 244 | deferred.resolve(); 245 | } 246 | return deferred.promise; 247 | } 248 | }; 249 | 250 | return self; 251 | }]); 252 | 253 | ocModal.directive('ocModal', ['$ocModal', '$compile', '$timeout', function($ocModal, $compile, $timeout) { 254 | return { 255 | restrict: 'AE', 256 | replace: true, 257 | scope: true, 258 | template: 259 | '', 264 | 265 | link: function link($scope, $element, $attrs) { 266 | var id = $attrs.ocModal, 267 | $templateWrapper; 268 | 269 | $scope.closeModal = function() { 270 | var args = Array.prototype.slice.call(arguments); 271 | args.unshift(id); 272 | $ocModal.close.apply(undefined, args); 273 | }; 274 | 275 | $ocModal.register({ 276 | id: id, 277 | $scope: $scope, 278 | $element: $element 279 | }); 280 | 281 | $element.on('$destroy', function() { 282 | $ocModal.remove(id); 283 | }); 284 | 285 | $scope.$watch('modalTemplate', function(newVal, oldVal) { 286 | if(typeof newVal !== 'undefined') { 287 | if(!$templateWrapper) { 288 | $templateWrapper = angular.element($element.children()[1]); 289 | } 290 | $templateWrapper.append($compile(newVal)($scope)); 291 | $scope.$emit('$includeContentLoaded'); 292 | } 293 | }); 294 | } 295 | } 296 | }]); 297 | 298 | ocModal.directive('ocModalOpen', ['$ocModal', function($ocModal) { 299 | return { 300 | restrict: 'A', 301 | require: '?modal', 302 | link: function($scope, $element, $attrs) { 303 | $element.on('click touchstart', function(e) { 304 | e.preventDefault(); 305 | e.stopPropagation(); 306 | var newScope = $scope.$new(); 307 | var params = newScope.$eval($attrs.ocModalOpen); 308 | if(params) { 309 | if(typeof params === "number") { 310 | params = { url: $attrs.ocModalOpen }; 311 | } else if(typeof params === "string") { 312 | params = { url: params }; 313 | } 314 | if(!params.url) { 315 | throw "You need to set the modal url"; 316 | } 317 | $scope.$apply(function() { 318 | $ocModal.open(params); 319 | }); 320 | } 321 | }); 322 | } 323 | }; 324 | }]); 325 | 326 | ocModal.directive('ocModalClose', ['$ocModal', function($ocModal) { 327 | return { 328 | restrict: 'A', 329 | require: '?modal', 330 | link: function($scope, $element, $attrs) { 331 | $element.on('click touchstart', function(e) { 332 | e.preventDefault(); 333 | e.stopPropagation(); 334 | $scope.$apply(function() { 335 | if($attrs.ocModalClose) { 336 | var params = $scope.$new().$eval($attrs.ocModalClose); 337 | } 338 | $ocModal.close(params); 339 | }); 340 | }); 341 | } 342 | }; 343 | }]); 344 | 345 | 346 | 347 | })(); 348 | 349 | /* Modernizr 2.8.2 (Custom Build) | MIT & BSD 350 | * Build: http://modernizr.com/download/#-flexbox-flexboxlegacy-cssclasses-testprop-testallprops-domprefixes 351 | */ 352 | (function(e,t,n){function x(e){f.cssText=e}function T(e,t){return x(prefixes.join(e+";")+(t||""))}function N(e,t){return typeof e===t}function C(e,t){return!!~(""+e).indexOf(t)}function k(e,t){for(var r in e){var i=e[r];if(!C(i,"-")&&f[i]!==n){return t=="pfx"?i:true}}return false}function L(e,t,r){for(var i in e){var s=t[e[i]];if(s!==n){if(r===false)return e[i];if(N(s,"function")){return s.bind(r||t)}return s}}return false}function A(e,t,n){var r=e.charAt(0).toUpperCase()+e.slice(1),i=(e+" "+p.join(r+" ")+r).split(" ");if(N(t,"string")||N(t,"undefined")){return k(i,t)}else{i=(e+" "+d.join(r+" ")+r).split(" ");return L(i,t,n)}}var r="2.8.2",i={},s=true,o=t.documentElement,u="modernizr",a=t.createElement(u),f=a.style,l,c={}.toString,h="Webkit Moz O ms",p=h.split(" "),d=h.toLowerCase().split(" "),v={},m={},g={},y=[],b=y.slice,w,E={}.hasOwnProperty,S;if(!N(E,"undefined")&&!N(E.call,"undefined")){S=function(e,t){return E.call(e,t)}}else{S=function(e,t){return t in e&&N(e.constructor.prototype[t],"undefined")}}if(!Function.prototype.bind){Function.prototype.bind=function(t){var n=this;if(typeof n!="function"){throw new TypeError}var r=b.call(arguments,1),i=function(){if(this instanceof i){var e=function(){};e.prototype=n.prototype;var s=new e;var o=n.apply(s,r.concat(b.call(arguments)));if(Object(o)===o){return o}return s}else{return n.apply(t,r.concat(b.call(arguments)))}};return i}}v["flexbox"]=function(){return A("flexWrap")};v["csstransforms"]=function(){return!!A("transform")};for(var O in v){if(S(v,O)){w=O.toLowerCase();i[w]=v[O]();y.push((i[w]?"":"no-")+w)}}i.addTest=function(e,t){if(typeof e=="object"){for(var r in e){if(S(e,r)){i.addTest(r,e[r])}}}else{e=e.toLowerCase();if(i[e]!==n){return i}t=typeof t=="function"?t():t;if(typeof s!=="undefined"&&s){o.className+=" "+(t?"":"no-")+e}i[e]=t}return i};x("");a=l=null;(function(e,t){function c(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;n.innerHTML="x";return r.insertBefore(n.lastChild,r.firstChild)}function h(){var e=y.elements;return typeof e=="string"?e.split(" "):e}function p(e){var t=f[e[u]];if(!t){t={};a++;e[u]=a;f[a]=t}return t}function d(e,n,r){if(!n){n=t}if(l){return n.createElement(e)}if(!r){r=p(n)}var o;if(r.cache[e]){o=r.cache[e].cloneNode()}else if(s.test(e)){o=(r.cache[e]=r.createElem(e)).cloneNode()}else{o=r.createElem(e)}return o.canHaveChildren&&!i.test(e)&&!o.tagUrn?r.frag.appendChild(o):o}function v(e,n){if(!e){e=t}if(l){return e.createDocumentFragment()}n=n||p(e);var r=n.frag.cloneNode(),i=0,s=h(),o=s.length;for(;i";o="hidden"in e;l=e.childNodes.length==1||function(){t.createElement("a");var e=t.createDocumentFragment();return typeof e.cloneNode=="undefined"||typeof e.createDocumentFragment=="undefined"||typeof e.createElement=="undefined"}()}catch(n){o=true;l=true}})();var y={elements:r.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:n,shivCSS:r.shivCSS!==false,supportsUnknownElements:l,shivMethods:r.shivMethods!==false,type:"default",shivDocument:g,createElement:d,createDocumentFragment:v};e.html5=y;g(t)})(this,t);i._version=r;i._domPrefixes=d;i._cssomPrefixes=p;i.testProp=function(e){return k([e])};i.testAllProps=A;o.className=o.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(s?" js "+y.join(" "):"");return i})(this,this.document) -------------------------------------------------------------------------------- /dist/ocModal.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ocmodal - An angularJS modal directive / service 3 | * @version v0.1.12 4 | * @link https://github.com/ocombe/ocModal 5 | * @license MIT 6 | * @author Olivier Combe 7 | */ 8 | !function(){"use strict";var e=angular.module("oc.modal",[]);e.factory("$ocModal",["$rootScope","$controller","$location","$timeout","$compile","$sniffer","$q",function(e,n,t,o,a,r,i){var l,c=angular.element(document.body),s=angular.element(''),u=angular.element(''),d={},p=[];u.css("display","none"),u.append(s),c.append(u),s.on("click",function(n){angular.element(n.target).hasClass("modal-backdrop")&&e.$apply(function(){v.closeOnEsc()})});var f=function(e){var n=0,t=angular.isString(e)?e.split(/\s*,\s*/):[];return angular.forEach(t,function(e){n=Math.max(parseFloat(e)||0,n)}),n},m=function(e){var n=0;if(r.transitions||r.animations){var t="animation",o="transition",a=r.vendorPrefix+"Animation",i=r.vendorPrefix+"Transition",l="Duration",c="Delay",s="IterationCount",u=1;angular.forEach(e,function(e){if(e.nodeType==u){var r=window.getComputedStyle(e)||{},d=Math.max(f(r[o+c]),f(r[i+c])),p=Math.max(f(r[t+c]),f(r[a+c])),m=Math.max(f(r[o+l]),f(r[i+l])),v=Math.max(f(r[t+l]),f(r[a+l]));v>0&&(v*=Math.max(parseInt(r[t+s])||0,parseInt(r[a+s])||0,1)),n=Math.max(p+v,d+m,n)}})}return 1e3*n};angular.element(document).on("keyup",function(n){27==n.keyCode&&p.length>0&&(n.stopPropagation(),e.$apply(function(){v.closeOnEsc(p[p.length-1])}))});var v={waitingForOpen:!1,getOpenedModals:function(){return p},register:function(e){d[e.id||"_default"]=e},remove:function(e){delete d[e||"_default"]},open:function(t){"string"==typeof t&&(t=t.match("<")?{template:t}:{url:t});var r=d[t.id||"_default"];if(!r)return s.append(a('
')(e)),void o(function(){v.open(t)});if(r&&-1!==p.indexOf(t.id||"_default")){if(v.waitingForOpen)return;return v.waitingForOpen=!0,void v.close(t.id).then(function(){v.open(t)})}if(!v.waitingForOpen)if(0===p.length)l=document.body.style.overflow,document.body.style.overflow="hidden",u.css("display","block");else for(var i=0,f=p.length;f>i;i++){var m=d[p[i]].$element;d[p[i]].baseZIndex=m.css("z-index"),m.css("z-index","-1"),m.addClass("no-backdrop")}v.waitingForOpen=!1,p.push(t.id||"_default"),r.params=t,r.$scope.customClass=r.params.cls,e.$digest(),c[0].offsetWidth,o(function(){r.$scope.modalShow=!0},100),"function"==typeof r.params.onOpen&&r.params.onOpen();var h=r.$scope.$on("$includeContentLoaded",function(e){r.params.init&&!r.params.isolate&&angular.extend(e.targetScope,r.params.init),"string"==typeof r.params.controller&&n(r.params.controller,{$scope:e.targetScope,$init:r.params.init,$ocModalParams:r.params}),h()});if(r.params.template)r.$scope.modalTemplate=r.params.template;else{if(!r.params.url)throw"You need to define a template or an url";r.$scope.modalUrl=r.params.url}"function"==typeof callback&&r.$scope.callbacksList.push(callback)},closeOnEsc:function(e){return d[e||p[p.length-1]].params.closeOnEsc!==!1?v.close(e):void 0},close:function(e){var n,t=i.defer();n="string"==typeof e&&-1!==p.indexOf(e)?Array.prototype.slice.call(arguments,1):arguments,("undefined"==typeof e||-1===p.indexOf(e))&&(e=p[p.length-1]);var a=d[e||p[p.length-1]];if(a&&a.$scope.modalShow===!0){var r=m(angular.element(a.$element[0].querySelector(".modal-content")));o(function(){a.$scope.modalShow=!1,o(function(){if(a.$scope.$destroy(),a.$element.remove(),a.callbacksList=[],p.splice(p.indexOf(e||p[p.length-1]),1),0===p.length)v.waitingForOpen||(document.body.style.overflow=l,u.css("display","none"));else{var o=d[p[p.length-1]];o.$element.css("z-index",o.baseZIndex),o.$element.removeClass("no-backdrop")}"function"==typeof a.params.onClose&&a.params.onClose.apply(void 0,n),t.resolve()},r)})}else t.resolve();return t.promise}};return v}]),e.directive("ocModal",["$ocModal","$compile","$timeout",function(e,n,t){return{restrict:"AE",replace:!0,scope:!0,template:'',link:function(t,o,a){var r,i=a.ocModal;t.closeModal=function(){var n=Array.prototype.slice.call(arguments);n.unshift(i),e.close.apply(void 0,n)},e.register({id:i,$scope:t,$element:o}),o.on("$destroy",function(){e.remove(i)}),t.$watch("modalTemplate",function(e,a){"undefined"!=typeof e&&(r||(r=angular.element(o.children()[1])),r.append(n(e)(t)),t.$emit("$includeContentLoaded"))})}}}]),e.directive("ocModalOpen",["$ocModal",function(e){return{restrict:"A",require:"?modal",link:function(n,t,o){t.on("click touchstart",function(t){t.preventDefault(),t.stopPropagation();var a=n.$new(),r=a.$eval(o.ocModalOpen);if(r){if("number"==typeof r?r={url:o.ocModalOpen}:"string"==typeof r&&(r={url:r}),!r.url)throw"You need to set the modal url";n.$apply(function(){e.open(r)})}})}}}]),e.directive("ocModalClose",["$ocModal",function(e){return{restrict:"A",require:"?modal",link:function(n,t,o){t.on("click touchstart",function(t){t.preventDefault(),t.stopPropagation(),n.$apply(function(){if(o.ocModalClose)var t=n.$new().$eval(o.ocModalClose);e.close(t)})})}}}])}(),function(e,n,t){function o(e){y.cssText=e}function a(e,n){return typeof e===n}function r(e,n){return!!~(""+e).indexOf(n)}function i(e,n){for(var o in e){var a=e[o];if(!r(a,"-")&&y[a]!==t)return"pfx"==n?a:!0}return!1}function l(e,n,o){for(var r in e){var i=n[e[r]];if(i!==t)return o===!1?e[r]:a(i,"function")?i.bind(o||n):i}return!1}function c(e,n,t){var o=e.charAt(0).toUpperCase()+e.slice(1),r=(e+" "+b.join(o+" ")+o).split(" ");return a(n,"string")||a(n,"undefined")?i(r,n):(r=(e+" "+x.join(o+" ")+o).split(" "),l(r,n,t))}var s,u,d,p="2.8.2",f={},m=!0,v=n.documentElement,h="modernizr",g=n.createElement(h),y=g.style,$=({}.toString,"Webkit Moz O ms"),b=$.split(" "),x=$.toLowerCase().split(" "),w={},C=[],E=C.slice,M={}.hasOwnProperty;d=a(M,"undefined")||a(M.call,"undefined")?function(e,n){return n in e&&a(e.constructor.prototype[n],"undefined")}:function(e,n){return M.call(e,n)},Function.prototype.bind||(Function.prototype.bind=function(e){var n=this;if("function"!=typeof n)throw new TypeError;var t=E.call(arguments,1),o=function(){if(this instanceof o){var a=function(){};a.prototype=n.prototype;var r=new a,i=n.apply(r,t.concat(E.call(arguments)));return Object(i)===i?i:r}return n.apply(e,t.concat(E.call(arguments)))};return o}),w.flexbox=function(){return c("flexWrap")},w.csstransforms=function(){return!!c("transform")};for(var k in w)d(w,k)&&(u=k.toLowerCase(),f[u]=w[k](),C.push((f[u]?"":"no-")+u));return f.addTest=function(e,n){if("object"==typeof e)for(var o in e)d(e,o)&&f.addTest(o,e[o]);else{if(e=e.toLowerCase(),f[e]!==t)return f;n="function"==typeof n?n():n,"undefined"!=typeof m&&m&&(v.className+=" "+(n?"":"no-")+e),f[e]=n}return f},o(""),g=s=null,function(e,n){function t(e,n){var t=e.createElement("p"),o=e.getElementsByTagName("head")[0]||e.documentElement;return t.innerHTML="x",o.insertBefore(t.lastChild,o.firstChild)}function o(){var e=y.elements;return"string"==typeof e?e.split(" "):e}function a(e){var n=g[e[v]];return n||(n={},h++,e[v]=h,g[h]=n),n}function r(e,t,o){if(t||(t=n),u)return t.createElement(e);o||(o=a(t));var r;return r=o.cache[e]?o.cache[e].cloneNode():m.test(e)?(o.cache[e]=o.createElem(e)).cloneNode():o.createElem(e),!r.canHaveChildren||f.test(e)||r.tagUrn?r:o.frag.appendChild(r)}function i(e,t){if(e||(e=n),u)return e.createDocumentFragment();t=t||a(e);for(var r=t.frag.cloneNode(),i=0,l=o(),c=l.length;c>i;i++)r.createElement(l[i]);return r}function l(e,n){n.cache||(n.cache={},n.createElem=e.createElement,n.createFrag=e.createDocumentFragment,n.frag=n.createFrag()),e.createElement=function(t){return y.shivMethods?r(t,e,n):n.createElem(t)},e.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+o().join().replace(/[\w\-]+/g,function(e){return n.createElem(e),n.frag.createElement(e),'c("'+e+'")'})+");return n}")(y,n.frag)}function c(e){e||(e=n);var o=a(e);return!y.shivCSS||s||o.hasCSS||(o.hasCSS=!!t(e,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),u||l(e,o),e}var s,u,d="3.7.0",p=e.html5||{},f=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,m=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",h=0,g={};!function(){try{var e=n.createElement("a");e.innerHTML="",s="hidden"in e,u=1==e.childNodes.length||function(){n.createElement("a");var e=n.createDocumentFragment();return"undefined"==typeof e.cloneNode||"undefined"==typeof e.createDocumentFragment||"undefined"==typeof e.createElement}()}catch(t){s=!0,u=!0}}();var y={elements:p.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:d,shivCSS:p.shivCSS!==!1,supportsUnknownElements:u,shivMethods:p.shivMethods!==!1,type:"default",shivDocument:c,createElement:r,createDocumentFragment:i};e.html5=y,c(n)}(this,n),f._version=p,f._domPrefixes=x,f._cssomPrefixes=b,f.testProp=function(e){return i([e])},f.testAllProps=c,v.className=v.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(m?" js "+C.join(" "):""),f}(this,this.document); -------------------------------------------------------------------------------- /dist/scss/_animations.scss: -------------------------------------------------------------------------------- 1 | .modal .modal-dialog .modal-content { 2 | &.fade-in { 3 | @include transition(opacity 0.5s); 4 | opacity: 0; 5 | 6 | &.opened { 7 | opacity: 1; 8 | } 9 | } 10 | &.slide-down { 11 | @include transition(opacity 0.5s, transform 0.5s); 12 | @include transform(translateY(-20%)); 13 | opacity: 0; 14 | 15 | &.slide-down.opened { 16 | @include transform(translateY(0%)); 17 | opacity: 1; 18 | } 19 | } 20 | 21 | &.scale { 22 | @include transform(scale(0.7)); 23 | @include transition(transform 0.5s, opacity 0.5s); 24 | opacity: 0; 25 | 26 | &.opened { 27 | @include transform(scale(1)); 28 | opacity: 1; 29 | } 30 | } 31 | 32 | &.fall { 33 | @include transform-style(preserve-3d); 34 | @include transform(translateZ(600px) rotateX(20deg)); 35 | @include transition(transform 0.3s ease-in, opacity 0.3s ease-in); 36 | opacity: 0; 37 | 38 | &.opened { 39 | @include transform(translateZ(0) rotateX(0deg)); 40 | opacity: 1; 41 | } 42 | } 43 | 44 | &.flip-horizontal { 45 | @include transform-style(preserve-3d); 46 | @include transform(rotateY(-70deg)); 47 | @include transition(transform 0.3s ease-in, opacity 0.3s ease-in); 48 | opacity: 0; 49 | 50 | &.opened { 51 | @include transform(rotateY(0deg)); 52 | opacity: 1; 53 | } 54 | } 55 | 56 | &.flip-vertical { 57 | @include transform-style(preserve-3d); 58 | @include transform(rotateX(-70deg)); 59 | @include transition(transform 0.3s, opacity 0.3s); 60 | opacity: 0; 61 | 62 | &.opened { 63 | @include transform(rotateX(0deg)); 64 | opacity: 1; 65 | } 66 | } 67 | 68 | &.super-scaled { 69 | @include transform(scale(2)); 70 | @include transition(transform 0.5s, opacity 0.5s); 71 | opacity: 0; 72 | 73 | &.opened { 74 | @include transform(scale(1)); 75 | opacity: 1; 76 | } 77 | } 78 | 79 | &.slit { 80 | @include transform-style(preserve-3d); 81 | @include transition(opacity 0.5s); 82 | opacity: 0; 83 | 84 | &.opened { 85 | opacity: 1; 86 | @include transform(translateZ(-3000px) rotateY(90deg)); 87 | @include animation(slit .7s forwards ease-out); 88 | } 89 | } 90 | } 91 | 92 | @-webkit-keyframes slit { 93 | 50% { -webkit-transform: translateZ(-250px) rotateY(89deg); -webkit-animation-timing-function: ease-out;} 94 | 100% { -webkit-transform: translateZ(0) rotateY(0deg); } 95 | } 96 | 97 | @-moz-keyframes slit { 98 | 50% { -moz-transform: translateZ(-250px) rotateY(89deg); opacity: .5; -moz-animation-timing-function: ease-out;} 99 | 100% { -moz-transform: translateZ(0) rotateY(0deg); } 100 | } 101 | 102 | @keyframes slit { 103 | 50% { transform: translateZ(-250px) rotateY(89deg); animation-timing-function: ease-in;} 104 | 100% { transform: translateZ(0) rotateY(0deg); } 105 | } -------------------------------------------------------------------------------- /dist/scss/_modal.scss: -------------------------------------------------------------------------------- 1 | @mixin opacity($opacity) { 2 | opacity: $opacity; 3 | // IE8 filter 4 | $opacity-ie: ($opacity * 100); 5 | filter: #{alpha(opacity=$opacity-ie)}; 6 | } 7 | 8 | .noOverflow { 9 | overflow: hidden; 10 | } 11 | 12 | .modal-wrapper { 13 | z-index: $zindex-modal; 14 | position: fixed; 15 | 16 | .modal-backdrop { 17 | width: 100%; 18 | height: 100%; 19 | @include opacity($modal-backdrop-opacity); 20 | } 21 | } 22 | 23 | .modal { 24 | display: block; 25 | overflow: auto; 26 | text-align: center; 27 | 28 | .modal-dialog { 29 | z-index: $zindex-modal + 10; 30 | width: auto; 31 | text-align: left; /* on rétablit l'alignement du texte */ 32 | @include perspective(1300px); 33 | max-width: 100%; 34 | 35 | &.no-backdrop .modal-backdrop { 36 | display: none; 37 | } 38 | 39 | .modal-content { 40 | z-index: $zindex-modal; 41 | border-radius: $modal-border-radius; 42 | width: 600px; 43 | padding: 10px; 44 | max-width: 100%; 45 | margin: 0; 46 | } 47 | } 48 | } 49 | 50 | .flexbox { 51 | .modal { 52 | & > .modal-backdrop { 53 | display: none; 54 | } 55 | .modal-dialog { 56 | @include display(flex); 57 | @include align-items(center); 58 | @include justify-content(center); 59 | position: absolute; 60 | width: 100%; 61 | min-height: 100%; 62 | height: 100%; // required by IE10+ to center vertically 63 | margin: 0; 64 | padding: 10px; 65 | max-height: initial; 66 | } 67 | } 68 | } 69 | 70 | .no-flexbox { 71 | .modal-dialog { 72 | @include transform(translate(-50%, -50%)); 73 | position: absolute; 74 | left: 50%; 75 | top: 50%; 76 | margin: 0; 77 | padding: 10px; 78 | max-height: 100%; 79 | 80 | .modal-backdrop { 81 | display: none; 82 | } 83 | } 84 | &.no-csstransforms { 85 | .modal-dialog { 86 | left: auto; 87 | top: auto; 88 | margin: auto; 89 | } 90 | } 91 | } 92 | 93 | // IE7 support 94 | // Styles that make popup look nicer in old IE 95 | .lt-ie8 { 96 | .modal-content { 97 | display: inline; 98 | zoom: 1; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /dist/scss/_no-bootstrap.scss: -------------------------------------------------------------------------------- 1 | // Bootstrap variables & mixins 2 | @mixin transition-transform($transition...) { 3 | -webkit-transition: -webkit-transform $transition; 4 | -moz-transition: -moz-transform $transition; 5 | -o-transition: -o-transform $transition; 6 | transition: transform $transition; 7 | } 8 | 9 | // Box sizing 10 | @mixin box-sizing($boxmodel) { 11 | -webkit-box-sizing: $boxmodel; 12 | -moz-box-sizing: $boxmodel; 13 | box-sizing: $boxmodel; 14 | } 15 | 16 | // Translate 17 | @mixin translate($x, $y) { 18 | -webkit-transform: translate($x, $y); 19 | -ms-transform: translate($x, $y); // IE9+ 20 | transform: translate($x, $y); 21 | } 22 | 23 | // Box shadow 24 | @mixin box-shadow($shadow...) { 25 | -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 26 | box-shadow: $shadow; 27 | } 28 | 29 | // Opacity 30 | @mixin opacity($opacity) { 31 | opacity: $opacity; 32 | // IE8 filter 33 | $opacity-ie: ($opacity * 100); 34 | filter: #{alpha(opacity=$opacity-ie)}; 35 | } 36 | 37 | // Clearfix 38 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 39 | // 40 | // For modern browsers 41 | // 1. The space content is one way to avoid an Opera bug when the 42 | // contenteditable attribute is included anywhere else in the document. 43 | // Otherwise it causes space to appear at the top and bottom of elements 44 | // that are clearfixed. 45 | // 2. The use of `table` rather than `block` is only necessary if using 46 | // `:before` to contain the top-margins of child elements. 47 | @mixin clearfix() { 48 | &:before, 49 | &:after { 50 | content: " "; /* 1 */ 51 | display: table; /* 2 */ 52 | } 53 | &:after { 54 | clear: both; 55 | } 56 | } 57 | 58 | $screen-sm: 768px !default; 59 | $screen-sm-min: $screen-sm !default; 60 | $border-radius-base: 4px !default; 61 | $border-radius-large: 6px !default; 62 | $border-radius-small: 3px !default; 63 | $line-height-base: 1.428571429 !default; // 20/14 64 | $modal-title-line-height: $line-height-base !default; 65 | 66 | // Others 67 | *, 68 | *:before, 69 | *:after { 70 | @include box-sizing(border-box); 71 | } 72 | 73 | // 74 | // Modals 75 | // -------------------------------------------------- 76 | 77 | // .modal-open - body class for killing the scroll 78 | // .modal - container to scroll within 79 | // .modal-dialog - positioning shell for the actual modal 80 | // .modal-content - actual modal w/ bg and corners and shit 81 | 82 | // Kill the scroll on the body 83 | .modal-open { 84 | overflow: hidden; 85 | } 86 | 87 | // Container that the modal scrolls within 88 | .modal { 89 | display: none; 90 | overflow: auto; 91 | overflow-y: scroll; 92 | position: fixed; 93 | top: 0; 94 | right: 0; 95 | bottom: 0; 96 | left: 0; 97 | z-index: $zindex-modal-background; 98 | 99 | // When fading in the modal, animate it to slide down 100 | &.fade .modal-dialog { 101 | @include translate(0, -25%); 102 | @include transition-transform(0.3s ease-out); 103 | } 104 | &.in .modal-dialog { @include translate(0, 0)} 105 | } 106 | 107 | // Shell div to position the modal with bottom padding 108 | .modal-dialog { 109 | position: relative; 110 | margin-left: auto; 111 | margin-right: auto; 112 | width: auto; 113 | padding: 10px; 114 | z-index: ($zindex-modal-background + 10); 115 | } 116 | 117 | // Actual modal 118 | .modal-content { 119 | position: relative; 120 | background-color: $modal-content-bg; 121 | border: 1px solid $modal-content-fallback-border-color; //old browsers fallback (ie8 etc) 122 | border: 1px solid $modal-content-border-color; 123 | border-radius: $border-radius-large; 124 | @include box-shadow(0 3px 9px rgba(0,0,0,.5)); 125 | background-clip: padding-box; 126 | // Remove focus outline from opened modal 127 | outline: none; 128 | } 129 | 130 | // Modal background 131 | .modal-backdrop { 132 | position: fixed; 133 | top: 0; 134 | right: 0; 135 | bottom: 0; 136 | left: 0; 137 | z-index: ($zindex-modal-background - 10); 138 | background-color: $modal-backdrop-bg; 139 | // Fade for backdrop 140 | &.fade { @include opacity(0); } 141 | &.in { @include opacity(.5); } 142 | } 143 | 144 | // Modal header 145 | // Top section of the modal w/ title and dismiss 146 | .modal-header { 147 | padding: $modal-title-padding; 148 | border-bottom: 1px solid $modal-header-border-color; 149 | min-height: ($modal-title-padding + $modal-title-line-height); 150 | } 151 | // Close icon 152 | .modal-header .close { 153 | margin-top: -2px; 154 | } 155 | 156 | // Title text within header 157 | .modal-title { 158 | margin: 0; 159 | line-height: $modal-title-line-height; 160 | } 161 | 162 | // Modal body 163 | // Where all modal content resides (sibling of .modal-header and .modal-footer) 164 | .modal-body { 165 | position: relative; 166 | padding: $modal-inner-padding; 167 | } 168 | 169 | // Footer (for actions) 170 | .modal-footer { 171 | margin-top: 15px; 172 | padding: ($modal-inner-padding - 1) $modal-inner-padding $modal-inner-padding; 173 | text-align: right; // right align buttons 174 | border-top: 1px solid $modal-footer-border-color; 175 | @include clearfix(); // clear it in case folks use .pull-* classes on buttons 176 | 177 | // Properly space out buttons 178 | .btn + .btn { 179 | margin-left: 5px; 180 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs 181 | } 182 | // but override that for button groups 183 | .btn-group .btn + .btn { 184 | margin-left: -1px; 185 | } 186 | // and override it for block buttons as well 187 | .btn-block + .btn-block { 188 | margin-left: 0; 189 | } 190 | } 191 | 192 | // Scale up the modal 193 | @media screen and (min-width: $screen-sm-min) { 194 | .modal-dialog { 195 | width: 600px; 196 | padding-top: 30px; 197 | padding-bottom: 30px; 198 | } 199 | .modal-content { 200 | @include box-shadow(0 5px 15px rgba(0,0,0,.5)); 201 | } 202 | } -------------------------------------------------------------------------------- /dist/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $modal-backdrop-bg: #CCCCCC !default; // Color of overlay 2 | $modal-backdrop-opacity: 0.8 !default; // opacity of overlay 3 | $modal-border-radius: 2px; 4 | $modal-header-border-color: transparent !default; 5 | $close-button-color: #000; 6 | $zindex-modal-background: 1040 !default; 7 | $zindex-modal: 1050 !default; 8 | $modal-inner-padding: 20px !default; 9 | $modal-title-padding: 15px !default; 10 | $modal-content-bg: #fff !default; 11 | $modal-content-border-color: rgba(0, 0, 0, .2) !default; 12 | $modal-content-fallback-border-color: #999 !default; 13 | $modal-backdrop-bg: #000 !default; 14 | $modal-header-border-color: #e5e5e5 !default; 15 | $modal-footer-border-color: $modal-header-border-color !default; -------------------------------------------------------------------------------- /dist/scss/ocModal.animations.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bourbon/app/assets/stylesheets/_bourbon.scss"; 2 | 3 | @import "animations"; -------------------------------------------------------------------------------- /dist/scss/ocModal.full.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bourbon/app/assets/stylesheets/_bourbon.scss"; 2 | 3 | @import "variables"; 4 | @import "no-bootstrap"; 5 | @import "modal"; -------------------------------------------------------------------------------- /dist/scss/ocModal.light.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bourbon/app/assets/stylesheets/_bourbon.scss"; 2 | 3 | @import "variables"; 4 | @import "modal"; -------------------------------------------------------------------------------- /example/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var App = angular.module('app', ['oc.modal']); 4 | 5 | App.controller('AppCtrl', ['$scope', '$ocModal', function($scope, $ocModal) { 6 | $ocModal.open({ 7 | url: 'partials/modal.html', 8 | cls: 'test fade-in', 9 | onOpen: function() { 10 | console.log('modal1 opened from url'); 11 | } 12 | }) 13 | 14 | 15 | $ocModal.open({ 16 | id: 'tempModal', 17 | template: '', 18 | controller: 'TestCtrl', 19 | cls: 'slide-down', 20 | onClose: function(a, b) { 21 | console.log('on close callback:', a, b); 22 | }, 23 | init: { 24 | testVar: 'Close this or wait 5s' 25 | } 26 | }) 27 | }]); 28 | 29 | App.controller('TestCtrl', ['$scope', '$ocModal', '$timeout', function($scope, $ocModal, $timeout) { 30 | $timeout(function() { 31 | if($ocModal.getOpenedModals().indexOf('tempModal') !== -1) { 32 | $ocModal.close('tempModal', 'var a', 'var b'); 33 | } 34 | }, 5000); 35 | }]); -------------------------------------------------------------------------------- /example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |

Default

11 |

12 | 13 |

Transitions :

14 |

15 |

16 |

17 |

18 |

19 |

20 |

21 |

22 | 23 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /example/ocModal.animations.css: -------------------------------------------------------------------------------- 1 | .modal .modal-dialog .modal-content.fade-in { 2 | -webkit-transition: opacity 0.5s; 3 | -moz-transition: opacity 0.5s; 4 | transition: opacity 0.5s; 5 | opacity: 0; } 6 | .modal .modal-dialog .modal-content.fade-in.opened { 7 | opacity: 1; } 8 | 9 | .modal .modal-dialog .modal-content.slide-down { 10 | -webkit-transition: opacity, -webkit-transform; 11 | -moz-transition: opacity, -moz-transform; 12 | transition: opacity, transform; 13 | -webkit-transform: translateY(-20%); 14 | -moz-transform: translateY(-20%); 15 | -ms-transform: translateY(-20%); 16 | -o-transform: translateY(-20%); 17 | transform: translateY(-20%); 18 | opacity: 0; } 19 | .modal .modal-dialog .modal-content.slide-down.slide-down.opened { 20 | -webkit-transform: translateY(0%); 21 | -moz-transform: translateY(0%); 22 | -ms-transform: translateY(0%); 23 | -o-transform: translateY(0%); 24 | transform: translateY(0%); 25 | opacity: 1; } 26 | 27 | .modal .modal-dialog .modal-content.scale { 28 | -webkit-transform: scale(0.7); 29 | -moz-transform: scale(0.7); 30 | -ms-transform: scale(0.7); 31 | -o-transform: scale(0.7); 32 | transform: scale(0.7); 33 | -webkit-transition: -webkit-transform, opacity; 34 | -moz-transition: -moz-transform, opacity; 35 | transition: transform, opacity; 36 | opacity: 0; } 37 | .modal .modal-dialog .modal-content.scale.opened { 38 | -webkit-transform: scale(1); 39 | -moz-transform: scale(1); 40 | -ms-transform: scale(1); 41 | -o-transform: scale(1); 42 | transform: scale(1); 43 | opacity: 1; } 44 | 45 | .modal .modal-dialog .modal-content.fall { 46 | -webkit-transform-style: preserve-3d; 47 | -moz-transform-style: preserve-3d; 48 | -ms-transform-style: preserve-3d; 49 | -o-transform-style: preserve-3d; 50 | transform-style: preserve-3d; 51 | -webkit-transform: translateZ(600px) rotateX(20deg); 52 | -moz-transform: translateZ(600px) rotateX(20deg); 53 | -ms-transform: translateZ(600px) rotateX(20deg); 54 | -o-transform: translateZ(600px) rotateX(20deg); 55 | transform: translateZ(600px) rotateX(20deg); 56 | -webkit-transition: -webkit-transform, opacity; 57 | -moz-transition: -moz-transform, opacity; 58 | transition: transform, opacity; 59 | opacity: 0; } 60 | .modal .modal-dialog .modal-content.fall.opened { 61 | -webkit-transform: translateZ(0) rotateX(0deg); 62 | -moz-transform: translateZ(0) rotateX(0deg); 63 | -ms-transform: translateZ(0) rotateX(0deg); 64 | -o-transform: translateZ(0) rotateX(0deg); 65 | transform: translateZ(0) rotateX(0deg); 66 | opacity: 1; } 67 | 68 | .modal .modal-dialog .modal-content.flip-horizontal { 69 | -webkit-transform-style: preserve-3d; 70 | -moz-transform-style: preserve-3d; 71 | -ms-transform-style: preserve-3d; 72 | -o-transform-style: preserve-3d; 73 | transform-style: preserve-3d; 74 | -webkit-transform: rotateY(-70deg); 75 | -moz-transform: rotateY(-70deg); 76 | -ms-transform: rotateY(-70deg); 77 | -o-transform: rotateY(-70deg); 78 | transform: rotateY(-70deg); 79 | -webkit-transition: -webkit-transform, opacity; 80 | -moz-transition: -moz-transform, opacity; 81 | transition: transform, opacity; 82 | opacity: 0; } 83 | .modal .modal-dialog .modal-content.flip-horizontal.opened { 84 | -webkit-transform: rotateY(0deg); 85 | -moz-transform: rotateY(0deg); 86 | -ms-transform: rotateY(0deg); 87 | -o-transform: rotateY(0deg); 88 | transform: rotateY(0deg); 89 | opacity: 1; } 90 | 91 | .modal .modal-dialog .modal-content.flip-vertical { 92 | -webkit-transform-style: preserve-3d; 93 | -moz-transform-style: preserve-3d; 94 | -ms-transform-style: preserve-3d; 95 | -o-transform-style: preserve-3d; 96 | transform-style: preserve-3d; 97 | -webkit-transform: rotateX(-70deg); 98 | -moz-transform: rotateX(-70deg); 99 | -ms-transform: rotateX(-70deg); 100 | -o-transform: rotateX(-70deg); 101 | transform: rotateX(-70deg); 102 | -webkit-transition: -webkit-transform, opacity; 103 | -moz-transition: -moz-transform, opacity; 104 | transition: transform, opacity; 105 | opacity: 0; } 106 | .modal .modal-dialog .modal-content.flip-vertical.opened { 107 | -webkit-transform: rotateX(0deg); 108 | -moz-transform: rotateX(0deg); 109 | -ms-transform: rotateX(0deg); 110 | -o-transform: rotateX(0deg); 111 | transform: rotateX(0deg); 112 | opacity: 1; } 113 | 114 | .modal .modal-dialog .modal-content.super-scaled { 115 | -webkit-transform: scale(2); 116 | -moz-transform: scale(2); 117 | -ms-transform: scale(2); 118 | -o-transform: scale(2); 119 | transform: scale(2); 120 | -webkit-transition: -webkit-transform, opacity; 121 | -moz-transition: -moz-transform, opacity; 122 | transition: transform, opacity; 123 | opacity: 0; } 124 | .modal .modal-dialog .modal-content.super-scaled.opened { 125 | -webkit-transform: scale(1); 126 | -moz-transform: scale(1); 127 | -ms-transform: scale(1); 128 | -o-transform: scale(1); 129 | transform: scale(1); 130 | opacity: 1; } 131 | 132 | .modal .modal-dialog .modal-content.slit { 133 | -webkit-transform-style: preserve-3d; 134 | -moz-transform-style: preserve-3d; 135 | -ms-transform-style: preserve-3d; 136 | -o-transform-style: preserve-3d; 137 | transform-style: preserve-3d; 138 | -webkit-transition: opacity 0.5s; 139 | -moz-transition: opacity 0.5s; 140 | transition: opacity 0.5s; 141 | opacity: 0; } 142 | .modal .modal-dialog .modal-content.slit.opened { 143 | opacity: 1; 144 | -webkit-transform: translateZ(-3000px) rotateY(90deg); 145 | -moz-transform: translateZ(-3000px) rotateY(90deg); 146 | -ms-transform: translateZ(-3000px) rotateY(90deg); 147 | -o-transform: translateZ(-3000px) rotateY(90deg); 148 | transform: translateZ(-3000px) rotateY(90deg); 149 | -webkit-animation: slit 0.7s forwards ease-out; 150 | -moz-animation: slit 0.7s forwards ease-out; 151 | animation: slit 0.7s forwards ease-out; } 152 | 153 | @-webkit-keyframes slit { 154 | 50% { 155 | -webkit-transform: translateZ(-250px) rotateY(89deg); 156 | -webkit-animation-timing-function: ease-out; } 157 | 100% { 158 | -webkit-transform: translateZ(0) rotateY(0deg); } } 159 | 160 | @-moz-keyframes slit { 161 | 50% { 162 | -moz-transform: translateZ(-250px) rotateY(89deg); 163 | opacity: .5; 164 | -moz-animation-timing-function: ease-out; } 165 | 100% { 166 | -moz-transform: translateZ(0) rotateY(0deg); } } 167 | 168 | @keyframes slit { 169 | 50% { 170 | transform: translateZ(-250px) rotateY(89deg); 171 | animation-timing-function: ease-in; } 172 | 100% { 173 | transform: translateZ(0) rotateY(0deg); } } 174 | -------------------------------------------------------------------------------- /example/ocModal.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ocmodal - An angularJS modal directive / service 3 | * @version v0.1.12 4 | * @link https://github.com/ocombe/ocModal 5 | * @license MIT 6 | * @author Olivier Combe 7 | */ 8 | (function() { 9 | 'use strict'; 10 | 11 | var ocModal = angular.module('oc.modal', []); 12 | 13 | ocModal.factory('$ocModal', ['$rootScope', '$controller', '$location', '$timeout', '$compile', '$sniffer', '$q', function($rootScope, $controller, $location, $timeout, $compile, $sniffer, $q) { 14 | var $body = angular.element(document.body), 15 | $dialogsWrapper = angular.element(''), 16 | $modalWrapper = angular.element( 17 | '' 18 | ), 19 | modals = {}, 20 | openedModals = [], 21 | baseOverflow; 22 | 23 | // include the modal in DOM at start for animations 24 | $modalWrapper.css('display', 'none'); 25 | $modalWrapper.append($dialogsWrapper); 26 | $body.append($modalWrapper); 27 | $dialogsWrapper.on('click', function(e) { 28 | if(angular.element(e.target).hasClass('modal-backdrop')) { // only if clicked on backdrop 29 | $rootScope.$apply(function() { 30 | self.closeOnEsc(); 31 | }); 32 | } 33 | }); 34 | 35 | var parseMaxTime = function parseMaxTime(str) { 36 | var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : []; 37 | angular.forEach(values, function(value) { 38 | total = Math.max(parseFloat(value) || 0, total); 39 | }); 40 | return total; 41 | }; 42 | 43 | var getAnimDuration = function getDuration($element) { 44 | var duration = 0; 45 | if(($sniffer.transitions || $sniffer.animations)) { 46 | //one day all browsers will have these properties 47 | var w3cAnimationProp = 'animation'; 48 | var w3cTransitionProp = 'transition'; 49 | 50 | //but some still use vendor-prefixed styles 51 | var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation'; 52 | var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; 53 | 54 | var durationKey = 'Duration', 55 | delayKey = 'Delay', 56 | animationIterationCountKey = 'IterationCount'; 57 | 58 | //we want all the styles defined before and after 59 | var ELEMENT_NODE = 1; 60 | angular.forEach($element, function(element) { 61 | if(element.nodeType == ELEMENT_NODE) { 62 | var elementStyles = window.getComputedStyle(element) || {}; 63 | 64 | var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]), 65 | parseMaxTime(elementStyles[vendorTransitionProp + delayKey])); 66 | 67 | var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]), 68 | parseMaxTime(elementStyles[vendorAnimationProp + delayKey])); 69 | 70 | var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]), 71 | parseMaxTime(elementStyles[vendorTransitionProp + durationKey])); 72 | 73 | var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]), 74 | parseMaxTime(elementStyles[vendorAnimationProp + durationKey])); 75 | 76 | if(animationDuration > 0) { 77 | animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0, 78 | parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0, 1); 79 | } 80 | 81 | duration = Math.max(animationDelay + animationDuration, transitionDelay + transitionDuration, duration); 82 | } 83 | }); 84 | } 85 | 86 | return duration * 1000; 87 | }; 88 | 89 | angular.element(document).on('keyup', function(e) { 90 | if (e.keyCode == 27 && openedModals.length > 0) { 91 | e.stopPropagation(); 92 | $rootScope.$apply(function() { 93 | self.closeOnEsc(openedModals[openedModals.length - 1]); 94 | }); 95 | } 96 | }); 97 | 98 | var self = { 99 | waitingForOpen: false, 100 | 101 | getOpenedModals: function() { 102 | return openedModals; 103 | }, 104 | 105 | register: function(params) { 106 | modals[params.id || '_default'] = params; 107 | }, 108 | 109 | remove: function(id) { 110 | delete modals[id || '_default']; 111 | }, 112 | 113 | open: function(opt) { 114 | if(typeof opt === 'string') { 115 | if(opt.match('<')) { // if html code 116 | opt = { 117 | template: opt 118 | } 119 | } else { 120 | opt = { 121 | url: opt 122 | } 123 | } 124 | } 125 | var modal = modals[opt.id || '_default']; 126 | if(!modal) { 127 | $dialogsWrapper.append($compile('
')($rootScope)); 128 | $timeout(function() { // let the ng-include detect that it's now empty 129 | self.open(opt); 130 | }); 131 | return; 132 | } else if(modal && openedModals.indexOf(opt.id || '_default') !== -1) { // if modal already opened 133 | if(self.waitingForOpen) { 134 | return; 135 | } 136 | self.waitingForOpen = true; 137 | self.close(opt.id).then(function() { 138 | self.open(opt); 139 | }); 140 | return; 141 | } 142 | // ok let's open the modal 143 | if(!self.waitingForOpen) { 144 | if(openedModals.length === 0) { // if no modal opened 145 | baseOverflow = document.body.style.overflow; 146 | document.body.style.overflow = 'hidden'; 147 | $modalWrapper.css('display', 'block'); 148 | } else { 149 | for(var i = 0, len = openedModals.length; i < len; i++) { 150 | var $e = modals[openedModals[i]].$element; 151 | modals[openedModals[i]].baseZIndex = $e.css('z-index'); 152 | $e.css('z-index', '-1'); 153 | $e.addClass('no-backdrop'); 154 | } 155 | } 156 | } 157 | self.waitingForOpen = false; 158 | openedModals.push(opt.id || '_default'); 159 | modal.params = opt; 160 | modal.$scope.customClass = modal.params.cls; 161 | 162 | // timeout for animations (if any) 163 | $rootScope.$digest(); 164 | $body[0].offsetWidth; // force paint to be sure the element is in the page 165 | $timeout(function() { 166 | modal.$scope.modalShow = true; 167 | }, 100); 168 | 169 | if(typeof modal.params.onOpen === 'function') { 170 | modal.params.onOpen(); 171 | } 172 | 173 | var off = modal.$scope.$on('$includeContentLoaded', function(event) { // on view load 174 | if(modal.params.init && !modal.params.isolate) { 175 | angular.extend(event.targetScope, modal.params.init); 176 | } 177 | if(typeof modal.params.controller === 'string') { 178 | $controller(modal.params.controller, {$scope: event.targetScope, $init: modal.params.init, $ocModalParams: modal.params}); // inject controller 179 | } 180 | off(); 181 | }); 182 | 183 | if(modal.params.template) { 184 | modal.$scope.modalTemplate = modal.params.template; // load the view 185 | } else if(modal.params.url) { 186 | modal.$scope.modalUrl = modal.params.url; // load the view 187 | } else { 188 | throw "You need to define a template or an url"; 189 | return; 190 | } 191 | 192 | if(typeof callback === 'function') { 193 | modal.$scope.callbacksList.push(callback); 194 | } 195 | }, 196 | 197 | closeOnEsc: function(id) { 198 | if(modals[id || openedModals[openedModals.length -1]].params.closeOnEsc !== false) { 199 | return self.close(id); 200 | } 201 | }, 202 | 203 | close: function(id) { 204 | var args, 205 | deferred = $q.defer(); 206 | if(typeof id === 'string' && openedModals.indexOf(id) !== -1) { 207 | args = Array.prototype.slice.call(arguments, 1); 208 | } else { 209 | args = arguments; 210 | } 211 | if(typeof id === 'undefined' || openedModals.indexOf(id) === -1) { 212 | id = openedModals[openedModals.length -1]; 213 | } 214 | var modal = modals[id || openedModals[openedModals.length -1]]; 215 | if(modal && modal.$scope.modalShow === true) { // if the modal is opened 216 | var animDuration = getAnimDuration(angular.element(modal.$element[0].querySelector('.modal-content'))); 217 | $timeout(function() { 218 | modal.$scope.modalShow = false; 219 | 220 | $timeout(function() { 221 | modal.$scope.$destroy(); 222 | modal.$element.remove(); // destroy the modal 223 | 224 | modal.callbacksList = []; // forget all callbacks 225 | openedModals.splice(openedModals.indexOf(id || openedModals[openedModals.length -1]), 1); 226 | if(openedModals.length === 0) { // if no modal left opened 227 | if(!self.waitingForOpen) { // in case the current modal is closed because another opened with the same id (avoid backdrop flickering in firefox) 228 | document.body.style.overflow = baseOverflow; // restore the body overflow 229 | $modalWrapper.css('display', 'none'); 230 | } 231 | } else { 232 | var topModal = modals[openedModals[openedModals.length - 1]]; 233 | topModal.$element.css('z-index', topModal.baseZIndex); 234 | topModal.$element.removeClass('no-backdrop'); 235 | } 236 | if(typeof modal.params.onClose === 'function') { 237 | modal.params.onClose.apply(undefined, args); 238 | } 239 | 240 | deferred.resolve(); 241 | }, animDuration); 242 | }); 243 | } else { 244 | deferred.resolve(); 245 | } 246 | return deferred.promise; 247 | } 248 | }; 249 | 250 | return self; 251 | }]); 252 | 253 | ocModal.directive('ocModal', ['$ocModal', '$compile', '$timeout', function($ocModal, $compile, $timeout) { 254 | return { 255 | restrict: 'AE', 256 | replace: true, 257 | scope: true, 258 | template: 259 | '', 264 | 265 | link: function link($scope, $element, $attrs) { 266 | var id = $attrs.ocModal, 267 | $templateWrapper; 268 | 269 | $scope.closeModal = function() { 270 | var args = Array.prototype.slice.call(arguments); 271 | args.unshift(id); 272 | $ocModal.close.apply(undefined, args); 273 | }; 274 | 275 | $ocModal.register({ 276 | id: id, 277 | $scope: $scope, 278 | $element: $element 279 | }); 280 | 281 | $element.on('$destroy', function() { 282 | $ocModal.remove(id); 283 | }); 284 | 285 | $scope.$watch('modalTemplate', function(newVal, oldVal) { 286 | if(typeof newVal !== 'undefined') { 287 | if(!$templateWrapper) { 288 | $templateWrapper = angular.element($element.children()[1]); 289 | } 290 | $templateWrapper.append($compile(newVal)($scope)); 291 | $scope.$emit('$includeContentLoaded'); 292 | } 293 | }); 294 | } 295 | } 296 | }]); 297 | 298 | ocModal.directive('ocModalOpen', ['$ocModal', function($ocModal) { 299 | return { 300 | restrict: 'A', 301 | require: '?modal', 302 | link: function($scope, $element, $attrs) { 303 | $element.on('click touchstart', function(e) { 304 | e.preventDefault(); 305 | e.stopPropagation(); 306 | var newScope = $scope.$new(); 307 | var params = newScope.$eval($attrs.ocModalOpen); 308 | if(params) { 309 | if(typeof params === "number") { 310 | params = { url: $attrs.ocModalOpen }; 311 | } else if(typeof params === "string") { 312 | params = { url: params }; 313 | } 314 | if(!params.url) { 315 | throw "You need to set the modal url"; 316 | } 317 | $scope.$apply(function() { 318 | $ocModal.open(params); 319 | }); 320 | } 321 | }); 322 | } 323 | }; 324 | }]); 325 | 326 | ocModal.directive('ocModalClose', ['$ocModal', function($ocModal) { 327 | return { 328 | restrict: 'A', 329 | require: '?modal', 330 | link: function($scope, $element, $attrs) { 331 | $element.on('click touchstart', function(e) { 332 | e.preventDefault(); 333 | e.stopPropagation(); 334 | $scope.$apply(function() { 335 | if($attrs.ocModalClose) { 336 | var params = $scope.$new().$eval($attrs.ocModalClose); 337 | } 338 | $ocModal.close(params); 339 | }); 340 | }); 341 | } 342 | }; 343 | }]); 344 | 345 | 346 | 347 | })(); 348 | 349 | /* Modernizr 2.8.2 (Custom Build) | MIT & BSD 350 | * Build: http://modernizr.com/download/#-flexbox-flexboxlegacy-cssclasses-testprop-testallprops-domprefixes 351 | */ 352 | (function(e,t,n){function x(e){f.cssText=e}function T(e,t){return x(prefixes.join(e+";")+(t||""))}function N(e,t){return typeof e===t}function C(e,t){return!!~(""+e).indexOf(t)}function k(e,t){for(var r in e){var i=e[r];if(!C(i,"-")&&f[i]!==n){return t=="pfx"?i:true}}return false}function L(e,t,r){for(var i in e){var s=t[e[i]];if(s!==n){if(r===false)return e[i];if(N(s,"function")){return s.bind(r||t)}return s}}return false}function A(e,t,n){var r=e.charAt(0).toUpperCase()+e.slice(1),i=(e+" "+p.join(r+" ")+r).split(" ");if(N(t,"string")||N(t,"undefined")){return k(i,t)}else{i=(e+" "+d.join(r+" ")+r).split(" ");return L(i,t,n)}}var r="2.8.2",i={},s=true,o=t.documentElement,u="modernizr",a=t.createElement(u),f=a.style,l,c={}.toString,h="Webkit Moz O ms",p=h.split(" "),d=h.toLowerCase().split(" "),v={},m={},g={},y=[],b=y.slice,w,E={}.hasOwnProperty,S;if(!N(E,"undefined")&&!N(E.call,"undefined")){S=function(e,t){return E.call(e,t)}}else{S=function(e,t){return t in e&&N(e.constructor.prototype[t],"undefined")}}if(!Function.prototype.bind){Function.prototype.bind=function(t){var n=this;if(typeof n!="function"){throw new TypeError}var r=b.call(arguments,1),i=function(){if(this instanceof i){var e=function(){};e.prototype=n.prototype;var s=new e;var o=n.apply(s,r.concat(b.call(arguments)));if(Object(o)===o){return o}return s}else{return n.apply(t,r.concat(b.call(arguments)))}};return i}}v["flexbox"]=function(){return A("flexWrap")};v["csstransforms"]=function(){return!!A("transform")};for(var O in v){if(S(v,O)){w=O.toLowerCase();i[w]=v[O]();y.push((i[w]?"":"no-")+w)}}i.addTest=function(e,t){if(typeof e=="object"){for(var r in e){if(S(e,r)){i.addTest(r,e[r])}}}else{e=e.toLowerCase();if(i[e]!==n){return i}t=typeof t=="function"?t():t;if(typeof s!=="undefined"&&s){o.className+=" "+(t?"":"no-")+e}i[e]=t}return i};x("");a=l=null;(function(e,t){function c(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;n.innerHTML="x";return r.insertBefore(n.lastChild,r.firstChild)}function h(){var e=y.elements;return typeof e=="string"?e.split(" "):e}function p(e){var t=f[e[u]];if(!t){t={};a++;e[u]=a;f[a]=t}return t}function d(e,n,r){if(!n){n=t}if(l){return n.createElement(e)}if(!r){r=p(n)}var o;if(r.cache[e]){o=r.cache[e].cloneNode()}else if(s.test(e)){o=(r.cache[e]=r.createElem(e)).cloneNode()}else{o=r.createElem(e)}return o.canHaveChildren&&!i.test(e)&&!o.tagUrn?r.frag.appendChild(o):o}function v(e,n){if(!e){e=t}if(l){return e.createDocumentFragment()}n=n||p(e);var r=n.frag.cloneNode(),i=0,s=h(),o=s.length;for(;i";o="hidden"in e;l=e.childNodes.length==1||function(){t.createElement("a");var e=t.createDocumentFragment();return typeof e.cloneNode=="undefined"||typeof e.createDocumentFragment=="undefined"||typeof e.createElement=="undefined"}()}catch(n){o=true;l=true}})();var y={elements:r.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:n,shivCSS:r.shivCSS!==false,supportsUnknownElements:l,shivMethods:r.shivMethods!==false,type:"default",shivDocument:g,createElement:d,createDocumentFragment:v};e.html5=y;g(t)})(this,t);i._version=r;i._domPrefixes=d;i._cssomPrefixes=p;i.testProp=function(e){return k([e])};i.testAllProps=A;o.className=o.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(s?" js "+y.join(" "):"");return i})(this,this.document) -------------------------------------------------------------------------------- /example/ocModal.light.css: -------------------------------------------------------------------------------- 1 | @charset "UTF-8"; 2 | .noOverflow { 3 | overflow: hidden; } 4 | 5 | .modal-wrapper { 6 | z-index: 1050; 7 | position: fixed; } 8 | .modal-wrapper .modal-backdrop { 9 | width: 100%; 10 | height: 100%; 11 | opacity: 0.8; 12 | filter: alpha(opacity=80); } 13 | 14 | .modal { 15 | display: block; 16 | overflow: auto; 17 | text-align: center; } 18 | .modal .modal-dialog { 19 | z-index: 1060; 20 | width: auto; 21 | text-align: left; 22 | /* on rétablit l'alignement du texte */ 23 | -webkit-perspective: 1300px; 24 | -moz-perspective: 1300px; 25 | perspective: 1300px; 26 | max-width: 100%; } 27 | .modal .modal-dialog.no-backdrop .modal-backdrop { 28 | display: none; } 29 | .modal .modal-dialog .modal-content { 30 | z-index: 1050; 31 | border-radius: 2px; 32 | width: 600px; 33 | padding: 10px; 34 | max-width: 100%; 35 | margin: 0; } 36 | 37 | .flexbox .modal > .modal-backdrop { 38 | display: none; } 39 | 40 | .flexbox .modal .modal-dialog { 41 | display: -webkit-box; 42 | display: -moz-box; 43 | display: box; 44 | display: -webkit-flex; 45 | display: -moz-flex; 46 | display: -ms-flexbox; 47 | display: flex; 48 | -webkit-box-align: center; 49 | -moz-box-align: center; 50 | box-align: center; 51 | -webkit-align-items: center; 52 | -moz-align-items: center; 53 | -ms-align-items: center; 54 | -o-align-items: center; 55 | align-items: center; 56 | -ms-flex-align: center; 57 | -webkit-box-pack: center; 58 | -moz-box-pack: center; 59 | box-pack: center; 60 | -webkit-justify-content: center; 61 | -moz-justify-content: center; 62 | -ms-justify-content: center; 63 | -o-justify-content: center; 64 | justify-content: center; 65 | -ms-flex-pack: center; 66 | position: absolute; 67 | width: 100%; 68 | min-height: 100%; 69 | height: 100%; 70 | margin: 0; 71 | padding: 10px; 72 | max-height: initial; } 73 | 74 | .no-flexbox .modal-dialog { 75 | -webkit-transform: translate(-50%, -50%); 76 | -moz-transform: translate(-50%, -50%); 77 | -ms-transform: translate(-50%, -50%); 78 | -o-transform: translate(-50%, -50%); 79 | transform: translate(-50%, -50%); 80 | position: absolute; 81 | left: 50%; 82 | top: 50%; 83 | margin: 0; 84 | padding: 10px; 85 | max-height: 100%; } 86 | .no-flexbox .modal-dialog .modal-backdrop { 87 | display: none; } 88 | 89 | .no-flexbox.no-csstransforms .modal-dialog { 90 | left: auto; 91 | top: auto; 92 | margin: auto; } 93 | 94 | .lt-ie8 .modal-content { 95 | display: inline; 96 | zoom: 1; } 97 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | 3 | gulp.task('sass', function() { 4 | var sass = require('gulp-sass'), 5 | minifyCSS = require('gulp-minify-css'), 6 | rename = require('gulp-rename'); 7 | 8 | gulp.src('./src/scss/*.scss') 9 | .pipe(gulp.dest('./dist/scss')); 10 | 11 | // light 12 | gulp.src('./src/scss/ocModal.light.scss') 13 | .pipe(sass({ 14 | includePaths: [ 15 | 'node_modules/bourbon/app/assets/stylesheets/' 16 | ] 17 | })) 18 | .pipe(gulp.dest('./dist/css')) 19 | .pipe(gulp.dest('./example')) 20 | .pipe(minifyCSS()) 21 | .pipe(rename({suffix: '.min'})) 22 | .pipe(gulp.dest('./dist/css')); 23 | 24 | // full (bootstrap included) 25 | gulp.src('./src/scss/ocModal.full.scss') 26 | .pipe(sass()) 27 | .pipe(gulp.dest('./dist/css')) 28 | .pipe(minifyCSS()) 29 | .pipe(rename({suffix: '.min'})) 30 | .pipe(gulp.dest('./dist/css')); 31 | 32 | // full (bootstrap included) 33 | gulp.src('./src/scss/ocModal.animations.scss') 34 | .pipe(sass()) 35 | .pipe(gulp.dest('./dist/css')) 36 | .pipe(gulp.dest('./example')) 37 | .pipe(minifyCSS()) 38 | .pipe(rename({suffix: '.min'})) 39 | .pipe(gulp.dest('./dist/css')); 40 | }); 41 | 42 | var build = function(newVer) { 43 | var rename = require('gulp-rename'), 44 | uglify = require('gulp-uglify'), 45 | header = require('gulp-header'), 46 | pkg = require('./package.json'), 47 | banner = ['/**', 48 | ' * <%= pkg.name %> - <%= pkg.description %>', 49 | ' * @version v<%= version %>', 50 | ' * @link <%= pkg.homepage %>', 51 | ' * @license <%= pkg.license %>', 52 | ' * @author <%= pkg.author %>', 53 | ' */', 54 | ''].join('\n'); 55 | 56 | return gulp.src('src/ocModal.js') 57 | .pipe(header(banner, {pkg: pkg, version: newVer || pkg.version})) 58 | .pipe(gulp.dest('dist')) 59 | .pipe(gulp.dest('example')) 60 | .pipe(uglify()) 61 | .pipe(header(banner, {pkg: pkg, version: newVer || pkg.version})) 62 | .pipe(rename({suffix: '.min'})) 63 | .pipe(gulp.dest('dist')); 64 | }; 65 | 66 | gulp.task('build', ['sass'], function() { 67 | return build(); 68 | }); 69 | 70 | var promptBump = function(callback) { 71 | var prompt = require('gulp-prompt'), 72 | semver = require('semver'), 73 | pkg = require('./package.json'); 74 | 75 | return gulp.src('') 76 | .pipe(prompt.prompt({ 77 | type: 'list', 78 | name: 'bump', 79 | message: 'What type of version bump would you like to do ? (current version is ' + pkg.version + ')', 80 | choices: [ 81 | 'patch (' + pkg.version + ' --> ' + semver.inc(pkg.version, 'patch') + ')', 82 | 'minor (' + pkg.version + ' --> ' + semver.inc(pkg.version, 'minor') + ')', 83 | 'major (' + pkg.version + ' --> ' + semver.inc(pkg.version, 'major') + ')', 84 | 'none (exit)' 85 | ] 86 | }, function(res) { 87 | var newVer; 88 | if(res.bump.match(/^patch/)) { 89 | newVer = semver.inc(pkg.version, 'patch'); 90 | } else if(res.bump.match(/^minor/)) { 91 | newVer = semver.inc(pkg.version, 'minor'); 92 | } else if(res.bump.match(/^major/)) { 93 | newVer = semver.inc(pkg.version, 'major'); 94 | } 95 | if(newVer && typeof callback === 'function') { 96 | return callback(newVer); 97 | } else { 98 | return; 99 | } 100 | })); 101 | }; 102 | 103 | var makeChangelog = function(newVer) { 104 | var streamqueue = require('streamqueue'), 105 | stream = streamqueue({objectMode: true}), 106 | exec = require('gulp-exec'), 107 | concat = require('gulp-concat'), 108 | clean = require('gulp-clean'); 109 | 110 | stream.queue(gulp.src('').pipe(exec('node ./src/changelog.js ' + newVer, {pipeStdout: true}))); 111 | stream.queue(gulp.src('CHANGELOG.md').pipe(clean())); 112 | 113 | return stream.done() 114 | .pipe(concat('CHANGELOG.md')) 115 | .pipe(gulp.dest('./')); 116 | }; 117 | 118 | // Make changelog 119 | gulp.task('changelog', function(event) { 120 | var prompt = require('gulp-prompt'); 121 | var semver = require('semver'); 122 | 123 | return promptBump(makeChangelog); 124 | }); 125 | 126 | gulp.task('release', ['sass'], function() { 127 | var jeditor = require("gulp-json-editor"); 128 | 129 | return promptBump(function(newVer) { 130 | var streamqueue = require('streamqueue'); 131 | var stream = streamqueue({objectMode: true}); 132 | 133 | // make the changelog 134 | stream.queue(makeChangelog(newVer)); 135 | 136 | // update the main project version number 137 | stream.queue( 138 | gulp.src('package.json') 139 | .pipe(jeditor({ 140 | 'version': newVer 141 | })) 142 | .pipe(gulp.dest("./")) 143 | ); 144 | 145 | stream.queue( 146 | gulp.src('bower.json') 147 | .pipe(jeditor({ 148 | 'version': newVer 149 | })) 150 | .pipe(gulp.dest("./")) 151 | ); 152 | 153 | stream.queue(build(newVer)); 154 | 155 | return stream.done(); 156 | }); 157 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ocmodal", 3 | "version": "0.1.12", 4 | "description": "An angularJS modal directive / service", 5 | "author": "Olivier Combe ", 6 | "license": "MIT", 7 | "main": "dist/ocModal.js", 8 | "homepage": "https://github.com/ocombe/ocModal", 9 | "bugs": { 10 | "url": "https://github.com/ocombe/ocModal/issues" 11 | }, 12 | "scripts": { 13 | "start": "static ./example/ -p 3000", 14 | "build": "gulp build" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/ocombe/ocModal.git" 19 | }, 20 | "keywords": [ 21 | "modal", 22 | "dialog", 23 | "module", 24 | "angular", 25 | "angularJS" 26 | ], 27 | "devDependencies": { 28 | "bourbon": "^4.2.6", 29 | "bower": "~1.6.5", 30 | "gulp": "~3.9.0", 31 | "gulp-clean": "^0.3.0", 32 | "gulp-concat": "~2.6.0", 33 | "gulp-exec": "~2.1.2", 34 | "gulp-header": "~1.7.1", 35 | "gulp-json-editor": "~2.2.1", 36 | "gulp-minify-css": "^1.2.1", 37 | "gulp-prompt": "~0.1.1", 38 | "gulp-rename": "^1.2.0", 39 | "gulp-sass": "^2.1.0", 40 | "gulp-uglify": "~1.4.2", 41 | "node-static": "^0.7.3", 42 | "qq": "~0.3.5", 43 | "semver": "~5.0.3", 44 | "streamqueue": "~1.1.1" 45 | } 46 | } -------------------------------------------------------------------------------- /src/changelog.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var child = require('child_process'); 4 | var fs = require('fs'); 5 | var util = require('util'); 6 | var q = require('qq'); 7 | 8 | var GIT_LOG_CMD = 'git log --grep="%s" -E --format=%s %s..HEAD'; 9 | var GIT_TAG_CMD = 'git describe --tags --abbrev=0'; 10 | 11 | var HEADER_TPL = '\n# %s (%s)\n\n'; 12 | var LINK_ISSUE = '[#%s](https://github.com/ocombe/ocModal/issues/%s)'; 13 | var LINK_COMMIT = '[%s](https://github.com/ocombe/ocModal/commit/%s)'; 14 | 15 | var EMPTY_COMPONENT = '$$'; 16 | 17 | 18 | var warn = function() { 19 | console.error('WARNING:', util.format.apply(null, arguments)); 20 | }; 21 | 22 | 23 | var parseRawCommit = function(raw) { 24 | if (!raw) return null; 25 | 26 | var lines = raw.split('\n'); 27 | var msg = {}, match; 28 | 29 | msg.hash = lines.shift(); 30 | msg.subject = lines.shift(); 31 | msg.closes = []; 32 | msg.breaks = []; 33 | 34 | lines.forEach(function(line) { 35 | match = line.match(/(?:Closes|Fixes)\s#(\d+)/); 36 | if (match) msg.closes.push(parseInt(match[1])); 37 | }); 38 | 39 | match = raw.match(/BREAKING CHANGE:([\s\S]*)/); 40 | if (match) { 41 | msg.breaking = match[1]; 42 | } 43 | 44 | msg.body = lines.join('\n'); 45 | match = msg.subject.match(/^(\w*)\s?\:\s?(.*)$/); 46 | 47 | if (!match || !match[1] || !match[2]) { 48 | warn('Incorrect message: %s %s', msg.hash, msg.subject); 49 | return null; 50 | } 51 | 52 | msg.type = match[1]; 53 | // msg.component = match[2]; 54 | msg.subject = match[2]; 55 | 56 | return msg; 57 | }; 58 | 59 | 60 | var linkToIssue = function(issue) { 61 | return util.format(LINK_ISSUE, issue, issue); 62 | }; 63 | 64 | 65 | var linkToCommit = function(hash) { 66 | return util.format(LINK_COMMIT, hash.substr(0, 8), hash); 67 | }; 68 | 69 | 70 | var currentDate = function() { 71 | var now = new Date(); 72 | var pad = function(i) { 73 | return ('0' + i).substr(-2); 74 | }; 75 | 76 | return util.format('%d-%s-%s', now.getFullYear(), pad(now.getMonth() + 1), pad(now.getDate())); 77 | }; 78 | 79 | 80 | var printSection = function(stream, title, section, printCommitLinks) { 81 | printCommitLinks = printCommitLinks === undefined ? true : printCommitLinks; 82 | var components = Object.getOwnPropertyNames(section).sort(); 83 | 84 | if (!components.length || section['$$'].length <= 0) return; 85 | 86 | stream.write(util.format('\n## %s\n\n', title)); 87 | 88 | components.forEach(function(name) { 89 | var prefix = '-'; 90 | var nested = section[name].length > 1; 91 | 92 | if (name !== EMPTY_COMPONENT) { 93 | if (nested) { 94 | stream.write(util.format('- **%s:**\n', name)); 95 | prefix = ' -'; 96 | } else { 97 | prefix = util.format('- **%s:**', name); 98 | } 99 | } 100 | 101 | section[name].forEach(function(commit) { 102 | if (printCommitLinks) { 103 | stream.write(util.format('%s %s\n (%s', prefix, commit.subject, linkToCommit(commit.hash))); 104 | if (commit.closes.length) { 105 | stream.write(',\n ' + commit.closes.map(linkToIssue).join(', ')); 106 | } 107 | stream.write(')\n'); 108 | } else { 109 | stream.write(util.format('%s %s', prefix, commit.subject)); 110 | } 111 | }); 112 | }); 113 | 114 | stream.write('\n'); 115 | }; 116 | 117 | 118 | var readGitLog = function(grep, from) { 119 | var deferred = q.defer(); 120 | 121 | // TODO(vojta): if it's slow, use spawn and stream it instead 122 | child.exec(util.format(GIT_LOG_CMD, grep, '%H%n%s%n%b%n==END==', from), function(code, stdout, stderr) { 123 | var commits = []; 124 | 125 | stdout.split('\n==END==\n').forEach(function(rawCommit) { 126 | var commit = parseRawCommit(rawCommit); 127 | if (commit) commits.push(commit); 128 | }); 129 | 130 | deferred.resolve(commits); 131 | }); 132 | 133 | return deferred.promise; 134 | }; 135 | 136 | 137 | var writeChangelog = function(stream, commits, version) { 138 | var sections = { 139 | fix: {}, 140 | feat: {}, 141 | perf: {}, 142 | docs: {}, 143 | breaks: {} 144 | }; 145 | 146 | sections.breaks[EMPTY_COMPONENT] = []; 147 | 148 | commits.forEach(function(commit) { 149 | var section = sections[commit.type]; 150 | var component = commit.component || EMPTY_COMPONENT; 151 | 152 | if (section) { 153 | section[component] = section[component] || []; 154 | section[component].push(commit); 155 | } 156 | 157 | if (commit.breaking) { 158 | sections.breaks[component] = sections.breaks[component] || []; 159 | sections.breaks[component].push({ 160 | subject: util.format("due to %s,\n %s", linkToCommit(commit.hash), commit.breaking), 161 | hash: commit.hash, 162 | closes: [] 163 | }); 164 | }; 165 | }); 166 | 167 | stream.write(util.format(HEADER_TPL, version, version, currentDate())); 168 | printSection(stream, 'Bug Fixes', sections.fix); 169 | printSection(stream, 'Features', sections.feat); 170 | printSection(stream, 'Performance Improvements', sections.perf); 171 | printSection(stream, 'Documentation', sections.docs); 172 | printSection(stream, 'Breaking Changes', sections.breaks, false); 173 | } 174 | 175 | 176 | var getPreviousTag = function() { 177 | var deferred = q.defer(); 178 | child.exec(GIT_TAG_CMD, function(code, stdout, stderr) { 179 | if (code) deferred.reject('Cannot get the previous tag.'); 180 | else deferred.resolve(stdout.replace('\n', '')); 181 | }); 182 | return deferred.promise; 183 | }; 184 | 185 | 186 | var generate = function(version, file) { 187 | getPreviousTag().then(function(tag) { 188 | // console.log('Reading git log since', tag); 189 | readGitLog('^fix|^feat|^perf|^docs|BREAKING', tag).then(function(commits) { 190 | // console.log('Parsed', commits.length, 'commits'); 191 | // console.log('Generating changelog to', file || 'stdout', '(', version, ')'); 192 | writeChangelog(file ? fs.createWriteStream(file) : process.stdout, commits, version); 193 | }); 194 | }); 195 | }; 196 | 197 | 198 | // publish for testing 199 | exports.parseRawCommit = parseRawCommit; 200 | 201 | // hacky start if not run by jasmine :-D 202 | if (process.argv.join('').indexOf('jasmine-node') === -1) { 203 | generate(process.argv[2], process.argv[3]); 204 | } -------------------------------------------------------------------------------- /src/ocModal.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | var ocModal = angular.module('oc.modal', []); 5 | 6 | ocModal.factory('$ocModal', ['$rootScope', '$controller', '$location', '$timeout', '$compile', '$sniffer', '$q', function($rootScope, $controller, $location, $timeout, $compile, $sniffer, $q) { 7 | var $body = angular.element(document.body), 8 | $dialogsWrapper = angular.element(''), 9 | $modalWrapper = angular.element( 10 | '' 11 | ), 12 | modals = {}, 13 | openedModals = [], 14 | baseOverflow; 15 | 16 | // include the modal in DOM at start for animations 17 | $modalWrapper.css('display', 'none'); 18 | $modalWrapper.append($dialogsWrapper); 19 | $body.append($modalWrapper); 20 | $dialogsWrapper.on('click', function(e) { 21 | if(angular.element(e.target).hasClass('modal-backdrop')) { // only if clicked on backdrop 22 | $rootScope.$apply(function() { 23 | self.closeOnEsc(); 24 | }); 25 | } 26 | }); 27 | 28 | var parseMaxTime = function parseMaxTime(str) { 29 | var total = 0, values = angular.isString(str) ? str.split(/\s*,\s*/) : []; 30 | angular.forEach(values, function(value) { 31 | total = Math.max(parseFloat(value) || 0, total); 32 | }); 33 | return total; 34 | }; 35 | 36 | var getAnimDuration = function getDuration($element) { 37 | var duration = 0; 38 | if(($sniffer.transitions || $sniffer.animations)) { 39 | //one day all browsers will have these properties 40 | var w3cAnimationProp = 'animation'; 41 | var w3cTransitionProp = 'transition'; 42 | 43 | //but some still use vendor-prefixed styles 44 | var vendorAnimationProp = $sniffer.vendorPrefix + 'Animation'; 45 | var vendorTransitionProp = $sniffer.vendorPrefix + 'Transition'; 46 | 47 | var durationKey = 'Duration', 48 | delayKey = 'Delay', 49 | animationIterationCountKey = 'IterationCount'; 50 | 51 | //we want all the styles defined before and after 52 | var ELEMENT_NODE = 1; 53 | angular.forEach($element, function(element) { 54 | if(element.nodeType == ELEMENT_NODE) { 55 | var elementStyles = window.getComputedStyle(element) || {}; 56 | 57 | var transitionDelay = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + delayKey]), 58 | parseMaxTime(elementStyles[vendorTransitionProp + delayKey])); 59 | 60 | var animationDelay = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + delayKey]), 61 | parseMaxTime(elementStyles[vendorAnimationProp + delayKey])); 62 | 63 | var transitionDuration = Math.max(parseMaxTime(elementStyles[w3cTransitionProp + durationKey]), 64 | parseMaxTime(elementStyles[vendorTransitionProp + durationKey])); 65 | 66 | var animationDuration = Math.max(parseMaxTime(elementStyles[w3cAnimationProp + durationKey]), 67 | parseMaxTime(elementStyles[vendorAnimationProp + durationKey])); 68 | 69 | if(animationDuration > 0) { 70 | animationDuration *= Math.max(parseInt(elementStyles[w3cAnimationProp + animationIterationCountKey]) || 0, 71 | parseInt(elementStyles[vendorAnimationProp + animationIterationCountKey]) || 0, 1); 72 | } 73 | 74 | duration = Math.max(animationDelay + animationDuration, transitionDelay + transitionDuration, duration); 75 | } 76 | }); 77 | } 78 | 79 | return duration * 1000; 80 | }; 81 | 82 | angular.element(document).on('keyup', function(e) { 83 | if (e.keyCode == 27 && openedModals.length > 0) { 84 | e.stopPropagation(); 85 | $rootScope.$apply(function() { 86 | self.closeOnEsc(openedModals[openedModals.length - 1]); 87 | }); 88 | } 89 | }); 90 | 91 | var self = { 92 | waitingForOpen: false, 93 | 94 | getOpenedModals: function() { 95 | return openedModals; 96 | }, 97 | 98 | register: function(params) { 99 | modals[params.id || '_default'] = params; 100 | }, 101 | 102 | remove: function(id) { 103 | delete modals[id || '_default']; 104 | }, 105 | 106 | open: function(opt) { 107 | if(typeof opt === 'string') { 108 | if(opt.match('<')) { // if html code 109 | opt = { 110 | template: opt 111 | } 112 | } else { 113 | opt = { 114 | url: opt 115 | } 116 | } 117 | } 118 | var modal = modals[opt.id || '_default']; 119 | if(!modal) { 120 | $dialogsWrapper.append($compile('
')($rootScope)); 121 | $timeout(function() { // let the ng-include detect that it's now empty 122 | self.open(opt); 123 | }); 124 | return; 125 | } else if(modal && openedModals.indexOf(opt.id || '_default') !== -1) { // if modal already opened 126 | if(self.waitingForOpen) { 127 | return; 128 | } 129 | self.waitingForOpen = true; 130 | self.close(opt.id).then(function() { 131 | self.open(opt); 132 | }); 133 | return; 134 | } 135 | // ok let's open the modal 136 | if(!self.waitingForOpen) { 137 | if(openedModals.length === 0) { // if no modal opened 138 | baseOverflow = document.body.style.overflow; 139 | document.body.style.overflow = 'hidden'; 140 | $modalWrapper.css('display', 'block'); 141 | } else { 142 | for(var i = 0, len = openedModals.length; i < len; i++) { 143 | var $e = modals[openedModals[i]].$element; 144 | modals[openedModals[i]].baseZIndex = $e.css('z-index'); 145 | $e.css('z-index', '-1'); 146 | $e.addClass('no-backdrop'); 147 | } 148 | } 149 | } 150 | self.waitingForOpen = false; 151 | openedModals.push(opt.id || '_default'); 152 | modal.params = opt; 153 | modal.$scope.customClass = modal.params.cls; 154 | 155 | // timeout for animations (if any) 156 | $rootScope.$digest(); 157 | $body[0].offsetWidth; // force paint to be sure the element is in the page 158 | $timeout(function() { 159 | modal.$scope.modalShow = true; 160 | }, 100); 161 | 162 | if(typeof modal.params.onOpen === 'function') { 163 | modal.params.onOpen(); 164 | } 165 | 166 | var off = modal.$scope.$on('$includeContentLoaded', function(event) { // on view load 167 | if(modal.params.init && !modal.params.isolate) { 168 | angular.extend(event.targetScope, modal.params.init); 169 | } 170 | if(typeof modal.params.controller === 'string') { 171 | $controller(modal.params.controller, {$scope: event.targetScope, $init: modal.params.init, $ocModalParams: modal.params}); // inject controller 172 | } 173 | off(); 174 | }); 175 | 176 | if(modal.params.template) { 177 | modal.$scope.modalTemplate = modal.params.template; // load the view 178 | } else if(modal.params.url) { 179 | modal.$scope.modalUrl = modal.params.url; // load the view 180 | } else { 181 | throw "You need to define a template or an url"; 182 | return; 183 | } 184 | 185 | if(typeof callback === 'function') { 186 | modal.$scope.callbacksList.push(callback); 187 | } 188 | }, 189 | 190 | closeOnEsc: function(id) { 191 | if(modals[id || openedModals[openedModals.length -1]].params.closeOnEsc !== false) { 192 | return self.close(id); 193 | } 194 | }, 195 | 196 | close: function(id) { 197 | var args, 198 | deferred = $q.defer(); 199 | if(typeof id === 'string' && openedModals.indexOf(id) !== -1) { 200 | args = Array.prototype.slice.call(arguments, 1); 201 | } else { 202 | args = arguments; 203 | } 204 | if(typeof id === 'undefined' || openedModals.indexOf(id) === -1) { 205 | id = openedModals[openedModals.length -1]; 206 | } 207 | var modal = modals[id || openedModals[openedModals.length -1]]; 208 | if(modal && modal.$scope.modalShow === true) { // if the modal is opened 209 | var animDuration = getAnimDuration(angular.element(modal.$element[0].querySelector('.modal-content'))); 210 | $timeout(function() { 211 | modal.$scope.modalShow = false; 212 | 213 | $timeout(function() { 214 | modal.$scope.$destroy(); 215 | modal.$element.remove(); // destroy the modal 216 | 217 | modal.callbacksList = []; // forget all callbacks 218 | openedModals.splice(openedModals.indexOf(id || openedModals[openedModals.length -1]), 1); 219 | if(openedModals.length === 0) { // if no modal left opened 220 | if(!self.waitingForOpen) { // in case the current modal is closed because another opened with the same id (avoid backdrop flickering in firefox) 221 | document.body.style.overflow = baseOverflow; // restore the body overflow 222 | $modalWrapper.css('display', 'none'); 223 | } 224 | } else { 225 | var topModal = modals[openedModals[openedModals.length - 1]]; 226 | topModal.$element.css('z-index', topModal.baseZIndex); 227 | topModal.$element.removeClass('no-backdrop'); 228 | } 229 | if(typeof modal.params.onClose === 'function') { 230 | modal.params.onClose.apply(undefined, args); 231 | } 232 | 233 | deferred.resolve(); 234 | }, animDuration); 235 | }); 236 | } else { 237 | deferred.resolve(); 238 | } 239 | return deferred.promise; 240 | } 241 | }; 242 | 243 | return self; 244 | }]); 245 | 246 | ocModal.directive('ocModal', ['$ocModal', '$compile', '$timeout', function($ocModal, $compile, $timeout) { 247 | return { 248 | restrict: 'AE', 249 | replace: true, 250 | scope: true, 251 | template: 252 | '', 257 | 258 | link: function link($scope, $element, $attrs) { 259 | var id = $attrs.ocModal, 260 | $templateWrapper; 261 | 262 | $scope.closeModal = function() { 263 | var args = Array.prototype.slice.call(arguments); 264 | args.unshift(id); 265 | $ocModal.close.apply(undefined, args); 266 | }; 267 | 268 | $ocModal.register({ 269 | id: id, 270 | $scope: $scope, 271 | $element: $element 272 | }); 273 | 274 | $element.on('$destroy', function() { 275 | $ocModal.remove(id); 276 | }); 277 | 278 | $scope.$watch('modalTemplate', function(newVal, oldVal) { 279 | if(typeof newVal !== 'undefined') { 280 | if(!$templateWrapper) { 281 | $templateWrapper = angular.element($element.children()[1]); 282 | } 283 | $templateWrapper.append($compile(newVal)($scope)); 284 | $scope.$emit('$includeContentLoaded'); 285 | } 286 | }); 287 | } 288 | } 289 | }]); 290 | 291 | ocModal.directive('ocModalOpen', ['$ocModal', function($ocModal) { 292 | return { 293 | restrict: 'A', 294 | require: '?modal', 295 | link: function($scope, $element, $attrs) { 296 | $element.on('click touchstart', function(e) { 297 | e.preventDefault(); 298 | e.stopPropagation(); 299 | var newScope = $scope.$new(); 300 | var params = newScope.$eval($attrs.ocModalOpen); 301 | if(params) { 302 | if(typeof params === "number") { 303 | params = { url: $attrs.ocModalOpen }; 304 | } else if(typeof params === "string") { 305 | params = { url: params }; 306 | } 307 | if(!params.url) { 308 | throw "You need to set the modal url"; 309 | } 310 | $scope.$apply(function() { 311 | $ocModal.open(params); 312 | }); 313 | } 314 | }); 315 | } 316 | }; 317 | }]); 318 | 319 | ocModal.directive('ocModalClose', ['$ocModal', function($ocModal) { 320 | return { 321 | restrict: 'A', 322 | require: '?modal', 323 | link: function($scope, $element, $attrs) { 324 | $element.on('click touchstart', function(e) { 325 | e.preventDefault(); 326 | e.stopPropagation(); 327 | $scope.$apply(function() { 328 | if($attrs.ocModalClose) { 329 | var params = $scope.$new().$eval($attrs.ocModalClose); 330 | } 331 | $ocModal.close(params); 332 | }); 333 | }); 334 | } 335 | }; 336 | }]); 337 | 338 | 339 | 340 | })(); 341 | 342 | /* Modernizr 2.8.2 (Custom Build) | MIT & BSD 343 | * Build: http://modernizr.com/download/#-flexbox-flexboxlegacy-cssclasses-testprop-testallprops-domprefixes 344 | */ 345 | (function(e,t,n){function x(e){f.cssText=e}function T(e,t){return x(prefixes.join(e+";")+(t||""))}function N(e,t){return typeof e===t}function C(e,t){return!!~(""+e).indexOf(t)}function k(e,t){for(var r in e){var i=e[r];if(!C(i,"-")&&f[i]!==n){return t=="pfx"?i:true}}return false}function L(e,t,r){for(var i in e){var s=t[e[i]];if(s!==n){if(r===false)return e[i];if(N(s,"function")){return s.bind(r||t)}return s}}return false}function A(e,t,n){var r=e.charAt(0).toUpperCase()+e.slice(1),i=(e+" "+p.join(r+" ")+r).split(" ");if(N(t,"string")||N(t,"undefined")){return k(i,t)}else{i=(e+" "+d.join(r+" ")+r).split(" ");return L(i,t,n)}}var r="2.8.2",i={},s=true,o=t.documentElement,u="modernizr",a=t.createElement(u),f=a.style,l,c={}.toString,h="Webkit Moz O ms",p=h.split(" "),d=h.toLowerCase().split(" "),v={},m={},g={},y=[],b=y.slice,w,E={}.hasOwnProperty,S;if(!N(E,"undefined")&&!N(E.call,"undefined")){S=function(e,t){return E.call(e,t)}}else{S=function(e,t){return t in e&&N(e.constructor.prototype[t],"undefined")}}if(!Function.prototype.bind){Function.prototype.bind=function(t){var n=this;if(typeof n!="function"){throw new TypeError}var r=b.call(arguments,1),i=function(){if(this instanceof i){var e=function(){};e.prototype=n.prototype;var s=new e;var o=n.apply(s,r.concat(b.call(arguments)));if(Object(o)===o){return o}return s}else{return n.apply(t,r.concat(b.call(arguments)))}};return i}}v["flexbox"]=function(){return A("flexWrap")};v["csstransforms"]=function(){return!!A("transform")};for(var O in v){if(S(v,O)){w=O.toLowerCase();i[w]=v[O]();y.push((i[w]?"":"no-")+w)}}i.addTest=function(e,t){if(typeof e=="object"){for(var r in e){if(S(e,r)){i.addTest(r,e[r])}}}else{e=e.toLowerCase();if(i[e]!==n){return i}t=typeof t=="function"?t():t;if(typeof s!=="undefined"&&s){o.className+=" "+(t?"":"no-")+e}i[e]=t}return i};x("");a=l=null;(function(e,t){function c(e,t){var n=e.createElement("p"),r=e.getElementsByTagName("head")[0]||e.documentElement;n.innerHTML="x";return r.insertBefore(n.lastChild,r.firstChild)}function h(){var e=y.elements;return typeof e=="string"?e.split(" "):e}function p(e){var t=f[e[u]];if(!t){t={};a++;e[u]=a;f[a]=t}return t}function d(e,n,r){if(!n){n=t}if(l){return n.createElement(e)}if(!r){r=p(n)}var o;if(r.cache[e]){o=r.cache[e].cloneNode()}else if(s.test(e)){o=(r.cache[e]=r.createElem(e)).cloneNode()}else{o=r.createElem(e)}return o.canHaveChildren&&!i.test(e)&&!o.tagUrn?r.frag.appendChild(o):o}function v(e,n){if(!e){e=t}if(l){return e.createDocumentFragment()}n=n||p(e);var r=n.frag.cloneNode(),i=0,s=h(),o=s.length;for(;i";o="hidden"in e;l=e.childNodes.length==1||function(){t.createElement("a");var e=t.createDocumentFragment();return typeof e.cloneNode=="undefined"||typeof e.createDocumentFragment=="undefined"||typeof e.createElement=="undefined"}()}catch(n){o=true;l=true}})();var y={elements:r.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:n,shivCSS:r.shivCSS!==false,supportsUnknownElements:l,shivMethods:r.shivMethods!==false,type:"default",shivDocument:g,createElement:d,createDocumentFragment:v};e.html5=y;g(t)})(this,t);i._version=r;i._domPrefixes=d;i._cssomPrefixes=p;i.testProp=function(e){return k([e])};i.testAllProps=A;o.className=o.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(s?" js "+y.join(" "):"");return i})(this,this.document) -------------------------------------------------------------------------------- /src/scss/_animations.scss: -------------------------------------------------------------------------------- 1 | .modal .modal-dialog .modal-content { 2 | &.fade-in { 3 | @include transition(opacity 0.5s); 4 | opacity: 0; 5 | 6 | &.opened { 7 | opacity: 1; 8 | } 9 | } 10 | &.slide-down { 11 | @include transition(opacity 0.5s, transform 0.5s); 12 | @include transform(translateY(-20%)); 13 | opacity: 0; 14 | 15 | &.slide-down.opened { 16 | @include transform(translateY(0%)); 17 | opacity: 1; 18 | } 19 | } 20 | 21 | &.scale { 22 | @include transform(scale(0.7)); 23 | @include transition(transform 0.5s, opacity 0.5s); 24 | opacity: 0; 25 | 26 | &.opened { 27 | @include transform(scale(1)); 28 | opacity: 1; 29 | } 30 | } 31 | 32 | &.fall { 33 | @include transform-style(preserve-3d); 34 | @include transform(translateZ(600px) rotateX(20deg)); 35 | @include transition(transform 0.3s ease-in, opacity 0.3s ease-in); 36 | opacity: 0; 37 | 38 | &.opened { 39 | @include transform(translateZ(0) rotateX(0deg)); 40 | opacity: 1; 41 | } 42 | } 43 | 44 | &.flip-horizontal { 45 | @include transform-style(preserve-3d); 46 | @include transform(rotateY(-70deg)); 47 | @include transition(transform 0.3s ease-in, opacity 0.3s ease-in); 48 | opacity: 0; 49 | 50 | &.opened { 51 | @include transform(rotateY(0deg)); 52 | opacity: 1; 53 | } 54 | } 55 | 56 | &.flip-vertical { 57 | @include transform-style(preserve-3d); 58 | @include transform(rotateX(-70deg)); 59 | @include transition(transform 0.3s, opacity 0.3s); 60 | opacity: 0; 61 | 62 | &.opened { 63 | @include transform(rotateX(0deg)); 64 | opacity: 1; 65 | } 66 | } 67 | 68 | &.super-scaled { 69 | @include transform(scale(2)); 70 | @include transition(transform 0.5s, opacity 0.5s); 71 | opacity: 0; 72 | 73 | &.opened { 74 | @include transform(scale(1)); 75 | opacity: 1; 76 | } 77 | } 78 | 79 | &.slit { 80 | @include transform-style(preserve-3d); 81 | @include transition(opacity 0.5s); 82 | opacity: 0; 83 | 84 | &.opened { 85 | opacity: 1; 86 | @include transform(translateZ(-3000px) rotateY(90deg)); 87 | @include animation(slit .7s forwards ease-out); 88 | } 89 | } 90 | } 91 | 92 | @-webkit-keyframes slit { 93 | 50% { -webkit-transform: translateZ(-250px) rotateY(89deg); -webkit-animation-timing-function: ease-out;} 94 | 100% { -webkit-transform: translateZ(0) rotateY(0deg); } 95 | } 96 | 97 | @-moz-keyframes slit { 98 | 50% { -moz-transform: translateZ(-250px) rotateY(89deg); opacity: .5; -moz-animation-timing-function: ease-out;} 99 | 100% { -moz-transform: translateZ(0) rotateY(0deg); } 100 | } 101 | 102 | @keyframes slit { 103 | 50% { transform: translateZ(-250px) rotateY(89deg); animation-timing-function: ease-in;} 104 | 100% { transform: translateZ(0) rotateY(0deg); } 105 | } -------------------------------------------------------------------------------- /src/scss/_modal.scss: -------------------------------------------------------------------------------- 1 | @mixin opacity($opacity) { 2 | opacity: $opacity; 3 | // IE8 filter 4 | $opacity-ie: ($opacity * 100); 5 | filter: #{alpha(opacity=$opacity-ie)}; 6 | } 7 | 8 | .noOverflow { 9 | overflow: hidden; 10 | } 11 | 12 | .modal-wrapper { 13 | z-index: $zindex-modal; 14 | position: fixed; 15 | 16 | .modal-backdrop { 17 | width: 100%; 18 | height: 100%; 19 | @include opacity($modal-backdrop-opacity); 20 | } 21 | } 22 | 23 | .modal { 24 | display: block; 25 | overflow: auto; 26 | text-align: center; 27 | 28 | .modal-dialog { 29 | z-index: $zindex-modal + 10; 30 | width: auto; 31 | text-align: left; /* on rétablit l'alignement du texte */ 32 | @include perspective(1300px); 33 | max-width: 100%; 34 | 35 | &.no-backdrop .modal-backdrop { 36 | display: none; 37 | } 38 | 39 | .modal-content { 40 | z-index: $zindex-modal; 41 | border-radius: $modal-border-radius; 42 | width: 600px; 43 | padding: 10px; 44 | max-width: 100%; 45 | margin: 0; 46 | } 47 | } 48 | } 49 | 50 | .flexbox { 51 | .modal { 52 | & > .modal-backdrop { 53 | display: none; 54 | } 55 | .modal-dialog { 56 | @include display(flex); 57 | @include align-items(center); 58 | @include justify-content(center); 59 | position: absolute; 60 | width: 100%; 61 | min-height: 100%; 62 | height: 100%; // required by IE10+ to center vertically 63 | margin: 0; 64 | padding: 10px; 65 | max-height: initial; 66 | } 67 | } 68 | } 69 | 70 | .no-flexbox { 71 | .modal-dialog { 72 | @include transform(translate(-50%, -50%)); 73 | position: absolute; 74 | left: 50%; 75 | top: 50%; 76 | margin: 0; 77 | padding: 10px; 78 | max-height: 100%; 79 | 80 | .modal-backdrop { 81 | display: none; 82 | } 83 | } 84 | &.no-csstransforms { 85 | .modal-dialog { 86 | left: auto; 87 | top: auto; 88 | margin: auto; 89 | } 90 | } 91 | } 92 | 93 | // IE7 support 94 | // Styles that make popup look nicer in old IE 95 | .lt-ie8 { 96 | .modal-content { 97 | display: inline; 98 | zoom: 1; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/scss/_no-bootstrap.scss: -------------------------------------------------------------------------------- 1 | // Bootstrap variables & mixins 2 | @mixin transition-transform($transition...) { 3 | -webkit-transition: -webkit-transform $transition; 4 | -moz-transition: -moz-transform $transition; 5 | -o-transition: -o-transform $transition; 6 | transition: transform $transition; 7 | } 8 | 9 | // Box sizing 10 | @mixin box-sizing($boxmodel) { 11 | -webkit-box-sizing: $boxmodel; 12 | -moz-box-sizing: $boxmodel; 13 | box-sizing: $boxmodel; 14 | } 15 | 16 | // Translate 17 | @mixin translate($x, $y) { 18 | -webkit-transform: translate($x, $y); 19 | -ms-transform: translate($x, $y); // IE9+ 20 | transform: translate($x, $y); 21 | } 22 | 23 | // Box shadow 24 | @mixin box-shadow($shadow...) { 25 | -webkit-box-shadow: $shadow; // iOS <4.3 & Android <4.1 26 | box-shadow: $shadow; 27 | } 28 | 29 | // Opacity 30 | @mixin opacity($opacity) { 31 | opacity: $opacity; 32 | // IE8 filter 33 | $opacity-ie: ($opacity * 100); 34 | filter: #{alpha(opacity=$opacity-ie)}; 35 | } 36 | 37 | // Clearfix 38 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 39 | // 40 | // For modern browsers 41 | // 1. The space content is one way to avoid an Opera bug when the 42 | // contenteditable attribute is included anywhere else in the document. 43 | // Otherwise it causes space to appear at the top and bottom of elements 44 | // that are clearfixed. 45 | // 2. The use of `table` rather than `block` is only necessary if using 46 | // `:before` to contain the top-margins of child elements. 47 | @mixin clearfix() { 48 | &:before, 49 | &:after { 50 | content: " "; /* 1 */ 51 | display: table; /* 2 */ 52 | } 53 | &:after { 54 | clear: both; 55 | } 56 | } 57 | 58 | $screen-sm: 768px !default; 59 | $screen-sm-min: $screen-sm !default; 60 | $border-radius-base: 4px !default; 61 | $border-radius-large: 6px !default; 62 | $border-radius-small: 3px !default; 63 | $line-height-base: 1.428571429 !default; // 20/14 64 | $modal-title-line-height: $line-height-base !default; 65 | 66 | // Others 67 | *, 68 | *:before, 69 | *:after { 70 | @include box-sizing(border-box); 71 | } 72 | 73 | // 74 | // Modals 75 | // -------------------------------------------------- 76 | 77 | // .modal-open - body class for killing the scroll 78 | // .modal - container to scroll within 79 | // .modal-dialog - positioning shell for the actual modal 80 | // .modal-content - actual modal w/ bg and corners and shit 81 | 82 | // Kill the scroll on the body 83 | .modal-open { 84 | overflow: hidden; 85 | } 86 | 87 | // Container that the modal scrolls within 88 | .modal { 89 | display: none; 90 | overflow: auto; 91 | overflow-y: scroll; 92 | position: fixed; 93 | top: 0; 94 | right: 0; 95 | bottom: 0; 96 | left: 0; 97 | z-index: $zindex-modal-background; 98 | 99 | // When fading in the modal, animate it to slide down 100 | &.fade .modal-dialog { 101 | @include translate(0, -25%); 102 | @include transition-transform(0.3s ease-out); 103 | } 104 | &.in .modal-dialog { @include translate(0, 0)} 105 | } 106 | 107 | // Shell div to position the modal with bottom padding 108 | .modal-dialog { 109 | position: relative; 110 | margin-left: auto; 111 | margin-right: auto; 112 | width: auto; 113 | padding: 10px; 114 | z-index: ($zindex-modal-background + 10); 115 | } 116 | 117 | // Actual modal 118 | .modal-content { 119 | position: relative; 120 | background-color: $modal-content-bg; 121 | border: 1px solid $modal-content-fallback-border-color; //old browsers fallback (ie8 etc) 122 | border: 1px solid $modal-content-border-color; 123 | border-radius: $border-radius-large; 124 | @include box-shadow(0 3px 9px rgba(0,0,0,.5)); 125 | background-clip: padding-box; 126 | // Remove focus outline from opened modal 127 | outline: none; 128 | } 129 | 130 | // Modal background 131 | .modal-backdrop { 132 | position: fixed; 133 | top: 0; 134 | right: 0; 135 | bottom: 0; 136 | left: 0; 137 | z-index: ($zindex-modal-background - 10); 138 | background-color: $modal-backdrop-bg; 139 | // Fade for backdrop 140 | &.fade { @include opacity(0); } 141 | &.in { @include opacity(.5); } 142 | } 143 | 144 | // Modal header 145 | // Top section of the modal w/ title and dismiss 146 | .modal-header { 147 | padding: $modal-title-padding; 148 | border-bottom: 1px solid $modal-header-border-color; 149 | min-height: ($modal-title-padding + $modal-title-line-height); 150 | } 151 | // Close icon 152 | .modal-header .close { 153 | margin-top: -2px; 154 | } 155 | 156 | // Title text within header 157 | .modal-title { 158 | margin: 0; 159 | line-height: $modal-title-line-height; 160 | } 161 | 162 | // Modal body 163 | // Where all modal content resides (sibling of .modal-header and .modal-footer) 164 | .modal-body { 165 | position: relative; 166 | padding: $modal-inner-padding; 167 | } 168 | 169 | // Footer (for actions) 170 | .modal-footer { 171 | margin-top: 15px; 172 | padding: ($modal-inner-padding - 1) $modal-inner-padding $modal-inner-padding; 173 | text-align: right; // right align buttons 174 | border-top: 1px solid $modal-footer-border-color; 175 | @include clearfix(); // clear it in case folks use .pull-* classes on buttons 176 | 177 | // Properly space out buttons 178 | .btn + .btn { 179 | margin-left: 5px; 180 | margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs 181 | } 182 | // but override that for button groups 183 | .btn-group .btn + .btn { 184 | margin-left: -1px; 185 | } 186 | // and override it for block buttons as well 187 | .btn-block + .btn-block { 188 | margin-left: 0; 189 | } 190 | } 191 | 192 | // Scale up the modal 193 | @media screen and (min-width: $screen-sm-min) { 194 | .modal-dialog { 195 | width: 600px; 196 | padding-top: 30px; 197 | padding-bottom: 30px; 198 | } 199 | .modal-content { 200 | @include box-shadow(0 5px 15px rgba(0,0,0,.5)); 201 | } 202 | } -------------------------------------------------------------------------------- /src/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $modal-backdrop-bg: #CCCCCC !default; // Color of overlay 2 | $modal-backdrop-opacity: 0.8 !default; // opacity of overlay 3 | $modal-border-radius: 2px; 4 | $modal-header-border-color: transparent !default; 5 | $close-button-color: #000; 6 | $zindex-modal-background: 1040 !default; 7 | $zindex-modal: 1050 !default; 8 | $modal-inner-padding: 20px !default; 9 | $modal-title-padding: 15px !default; 10 | $modal-content-bg: #fff !default; 11 | $modal-content-border-color: rgba(0, 0, 0, .2) !default; 12 | $modal-content-fallback-border-color: #999 !default; 13 | $modal-backdrop-bg: #000 !default; 14 | $modal-header-border-color: #e5e5e5 !default; 15 | $modal-footer-border-color: $modal-header-border-color !default; -------------------------------------------------------------------------------- /src/scss/ocModal.animations.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bourbon/app/assets/stylesheets/_bourbon.scss"; 2 | 3 | @import "animations"; -------------------------------------------------------------------------------- /src/scss/ocModal.full.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bourbon/app/assets/stylesheets/_bourbon.scss"; 2 | 3 | @import "variables"; 4 | @import "no-bootstrap"; 5 | @import "modal"; -------------------------------------------------------------------------------- /src/scss/ocModal.light.scss: -------------------------------------------------------------------------------- 1 | @import "../../node_modules/bourbon/app/assets/stylesheets/_bourbon.scss"; 2 | 3 | @import "variables"; 4 | @import "modal"; -------------------------------------------------------------------------------- /src/validate-commit-msg.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Git COMMIT-MSG hook for validating commit message 5 | * See https://docs.google.com/document/d/1rk04jEuGfk9kYzfqCuOlPTSJw3hEDZJTBN5E5f1SALo/edit 6 | * 7 | * Installation: 8 | * >> cd 9 | * >> ln -s ../../src/validate-commit-msg.js .git/hooks/commit-msg 10 | */ 11 | var fs = require('fs'); 12 | var util = require('util'); 13 | 14 | 15 | var MAX_LENGTH = 100; 16 | var PATTERN = /^(?:fixup!\s*)?(\w*)(\(([\w\$\.\-\*/]*)\))?\: (.*)$/; 17 | var IGNORED = /^WIP\:/; 18 | var TYPES = { 19 | feat: true, 20 | fix: true, 21 | docs: true, 22 | style: true, 23 | refactor: true, 24 | perf: true, 25 | test: true, 26 | chore: true, 27 | revert: true 28 | }; 29 | 30 | 31 | var error = function() { 32 | // gitx does not display it 33 | // http://gitx.lighthouseapp.com/projects/17830/tickets/294-feature-display-hook-error-message-when-hook-fails 34 | // https://groups.google.com/group/gitx/browse_thread/thread/a03bcab60844b812 35 | console.error('INVALID COMMIT MSG: ' + util.format.apply(null, arguments)); 36 | }; 37 | 38 | 39 | var validateMessage = function(message) { 40 | var isValid = true; 41 | 42 | if (IGNORED.test(message)) { 43 | console.log('Commit message validation ignored.'); 44 | return true; 45 | } 46 | 47 | if (message.length > MAX_LENGTH) { 48 | error('is longer than %d characters !', MAX_LENGTH); 49 | isValid = false; 50 | } 51 | 52 | var match = PATTERN.exec(message); 53 | 54 | if (!match) { 55 | error('does not match "(): " ! was: ' + message); 56 | return false; 57 | } 58 | 59 | var type = match[1]; 60 | var scope = match[3]; 61 | var subject = match[4]; 62 | 63 | if (!TYPES.hasOwnProperty(type)) { 64 | error('"%s" is not allowed type !', type); 65 | return false; 66 | } 67 | 68 | // Some more ideas, do want anything like this ? 69 | // - allow only specific scopes (eg. fix(docs) should not be allowed ? 70 | // - auto correct the type to lower case ? 71 | // - auto correct first letter of the subject to lower case ? 72 | // - auto add empty line after subject ? 73 | // - auto remove empty () ? 74 | // - auto correct typos in type ? 75 | // - store incorrect messages, so that we can learn 76 | 77 | return isValid; 78 | }; 79 | 80 | 81 | var firstLineFromBuffer = function(buffer) { 82 | return buffer.toString().split('\n').shift(); 83 | }; 84 | 85 | 86 | 87 | // publish for testing 88 | exports.validateMessage = validateMessage; 89 | 90 | // hacky start if not run by jasmine :-D 91 | if (process.argv.join('').indexOf('jasmine-node') === -1) { 92 | var commitMsgFile = process.argv[2]; 93 | var incorrectLogFile = commitMsgFile.replace('COMMIT_EDITMSG', 'logs/incorrect-commit-msgs'); 94 | 95 | fs.readFile(commitMsgFile, function(err, buffer) { 96 | var msg = firstLineFromBuffer(buffer); 97 | 98 | if (!validateMessage(msg)) { 99 | fs.appendFile(incorrectLogFile, msg + '\n', function() { 100 | process.exit(1); 101 | }); 102 | } else { 103 | process.exit(0); 104 | } 105 | }); 106 | } --------------------------------------------------------------------------------