<!DOCTYPE html>
<html ng-app="app">
<head>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet" />
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<script src="//code.angularjs.org/1.4.8/angular-sanitize.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular-animate.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-1.3.3.js"></script>
<!--<link href="spinner.css" rel="stylesheet" />-->
<script src="app.js"></script>
<script src="popup.service.min.js"></script>
</head>
<body>
<div ng-controller="appCtrl as vm" class="fluid panel-body">
<h2>Dialoge Box using UI Bootstrap</h2>
<h5>Inspired by <a href="http://ionicframework.com/docs/v1/api/service/$ionicPopup/" target="_blank">Ionic Popup</a></h5>
<div style=" padding-bottom: 10px;">
<strong class="text-danger mark">Launch in full window(or extend size of this window) to see the modal size effect.</strong>
</div>
<div>
<button class="btn btn-info" ng-click="vm.showConfirmWithOptions()">
Complex Confirm
</button>
<button class="btn btn-primary" ng-click="vm.showConfirm()">
Simple Confirm
</button>
<button class="btn btn-success" ng-click="vm.showAlert()">
Alert
</button>
<button class="btn btn-success" ng-click="vm.showAndClose()">
Alert (Close after 2 Sec)
</button>
<button class="btn btn-warning" ng-click="vm.showAndCloseSpinner()">
Spinner started with Generic Method (Close after 2 Sec)
</button>
<button class="btn btn-warning" ng-click="vm.showAndCloseSpinnerGlobal()">
Simple Spinner (Close after 2 Sec)
</button>
</div>
<!--<button class="button button-dark" ng-click="vm.showPopup()">-->
<!-- show-->
<!-- </button>-->
<form>
<div class="form-group">
<label for="text1">Message Body </label>
<input type="text" class="form-control" id="text1" ng-model="vm.body">
</div>
<div class="form-group">
<label for="text2">Title </label>
<input type="text" class="form-control" id="text2" ng-model="vm.title">
</div>
<div class="form-group">
<label for="text3">Sub Title </label>
<input type="text" class="form-control" id="text3" ng-model="vm.subTitle">
</div>
<div class="alert alert-success">
All input supports html snippet as well!!
</div>
</form>
<hr>
</div>
</body>
</html>
angular.module('app', ['ngAnimate', 'ui.bootstrap', 'ngSanitize', 'popup'])
.controller('appCtrl', ['$scope', '$injector', appCtrl])
.config(['PopupSvcProvider', function(PopupSvcProvider) { //optionally configure popup svc
PopupSvcProvider.setDefaults({
//okText: 'Dismiss'
});
}]);
function appCtrl($scope, $injector) {
var vm = this;
vm.body = "<span class='text-success'>Hey!!</span>Modal width automatically adjust as per Message body length when you simply pass the string";
vm.title = "Attention!";
vm.subTitle = "You bet";
var PopupSvc = $injector.get('PopupSvc');
vm.showAlert = function() {
var modal = PopupSvc.alert(vm.body);
modal.then(function(response) {
vm.response = response;
});
};
vm.showAndClose = function() {
var modal = PopupSvc.alert(vm.body);
window.setTimeout(modal.close, 2000);
};
vm.showAndCloseSpinner = function() {
var modal = PopupSvc.spin('Saving...');
window.setTimeout(modal.close, 2000);
};
vm.showAndCloseSpinnerGlobal = function() {
PopupSvc.spin('');
window.setTimeout(PopupSvc.stopSpin, 2000);
};
vm.showConfirm = function() {
PopupSvc.confirm(vm.body).then(function(response) {
vm.response = response;
});
};
vm.showConfirmWithOptions = function() {
PopupSvc.confirm({
title: vm.title,
subTitle: vm.subTitle,
body: vm.body,
okText: 'Agree',
cancelClass: 'btn-danger'
}).then(function(response) {
vm.response = response;
});
};
}
(function() {
/* popup.service.js v1.1 by Amitesh Kumar*/
angular.module('popup', [])
.provider('PopupSvc', PopupProviderFunction);
function PopupProviderFunction() {
var DEFAULTS = {
//title, subTitle and body are not a part of configuration
// title: '', // String (optional). The title of the popup.
// subTitle: '', // String (optional). The sub-title of the popup. only applicable when title provided
// body: '', //String or html template to place in the popup body.
okText: 'OK', //text for OK button
okClass: 'btn-info', //class(es) to be added to OK button; e.g 'btn-info btn-small'
cancelText: 'Cancel', //not applicable for alert
cancelClass: 'btn-secondary',
headerClass: 'text-center', //class to be added to bootstrap modal-header
bodyClass: '', //class for bootstrap modal-body
footerClass: '', //class for bootstrap modal-footer
//Below are the three uibModal related properties, see uibModal Bootstrap documentation for details
backdrop: 'static', //Controls presence of a backdrop. Allowed values: true (default), false (no backdrop), 'static' (disables modal closing by click on the backdrop).
keyboard: false, //Indicates whether the dialog should be closable by hitting the ESC key.
size: 'sm', //modal or popup size, default is small
/*NOTE: Below are the app level configuration applicable when input parameter is string. It can be set during angular config phase.
*/
showStringAs: 'body', //it will display the text as modal body(left aligned smaller font text). Other value is 'title' (center aligned h5 element)
enableDynamicSize: true, //show medium size popup when input string extends the below character limit
extendSizeCharLength: 300
};
this.setDefaults = function(userDefaults) {
angular.extend(DEFAULTS, userDefaults);
};
this.$get = ["$uibModal", function($uibModal) {
return new PopupSvc(DEFAULTS, $uibModal);
}];
}
function PopupSvc(DEFAULTS, $uibModal) {
/* jshint -W043 */
var POPUP_TEMPLATE = '\
<div>\
<div class="modal-header" ng-class="vm.headerClass" ng-if="vm.title" style="border:none; padding-bottom: 0;">\
<h3 class="modal-title" ng-bind-html="vm.title"></h3>\
<h5 class="modal-sub-title" ng-bind-html="vm.subTitle" ng-if="vm.subTitle"></h5>\
</div>\
<div class="modal-body" ng-if="vm.body" ng-class="vm.bodyClass">\
<div ng-bind-html="vm.body"></div>\
</div>\
<div class="modal-footer" ng-class="vm.footerClass" style="text-align: center; padding-top: 10px; padding-bottom: 15px; border: none">\
<div xclass="btn-group">\
<button ng-repeat="button in vm.buttons" ng-click="vm.onButtonClick(button, $index)" style="min-width: 70px;" class="btn" ng-class="button.className" ng-bind-html="button.text"></button>\
</div>\
</div>\
</div>';
var SPINNER_TEMPLATE = '<div><i class="fa fa-spinner fa-spin fa-2x"></i><span style="margin-left:5px; font-size: 1.3em">{{vm.title}}</span></div>';
var _spinnerModals = [];
_addDirectiveStyle();
return {
alert: _alert,
confirm: _confirm,
spin: _spin,
stopSpin: _stopSpin,
stopAll: _stopAll
//prompt: _prompt,
//show: _show//generic one which can show multiple buttons
};
function _addDirectiveStyle(){
//minified spinner.css
angular.element(document).find('head').prepend('<style type="text/css">@charset "UTF-8";.modal-spinner .modal-content{padding:20px;border-radius:5px;background-color:rgba(0,0,0,.8);color:#fff;text-align:center;text-overflow:ellipsis;font-size:15px}.modal-spinner-text .modal-content{text-align:left}.modal-spinner .modal-dialog{position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;width:80px;height:300px}.modal-spinner-text .modal-dialog{text-align:left;width:250px}</style>');
}
function _alert(opts) {
return _showPopup(extend([{
text: opts.okText || DEFAULTS.okText,
className: opts.okClass || DEFAULTS.okClass,
handler: function() {
return true;
}
}], opts || {}));
}
function _confirm(opts) {
return _showPopup(extend([{
text: opts.cancelText || DEFAULTS.cancelText,
className: opts.cancelClass || DEFAULTS.cancelClass,
handler: function() {
return false;
}
}, {
text: opts.okText || DEFAULTS.okText,
className: opts.okClass || DEFAULTS.okClass,
handler: function() {
return true;
}
}], opts || {}));
}
function _spin(title) { //by default spinner is global
var windowClass = 'modal-spinner';
if (title) {
windowClass += ' modal-spinner-text';
}
var modal = _showPopup({
title: title,
backdrop: 'static',
keyboard: false,
windowClass: windowClass,
isSpinner: true
});
var modalClose = modal.close;
var index = _spinnerModals.length;
_spinnerModals.push(modal);
modal.close = function(calledViaStop) {
modalClose();
if(!calledViaStop){//i.e from UI some one kept the reference of modal and called modal.close()
_spinnerModals.splice(index, 1);
}
};
return modal;
}
function _stopSpin() {
if (!_spinnerModals.length) {
return;
}
var spinnerModal = _spinnerModals.pop();
spinnerModal.close(true);
}
function _stopAll() {
var spinnerModal;
while (_spinnerModals.length) {
spinnerModal = _spinnerModals.pop();
spinnerModal.close(true);
}
}
function extend(buttons, userOpts) {
var options = angular.copy(DEFAULTS);
userOpts = userOpts || 'You there?';
if (typeof userOpts === 'string') {
var obj = {};
obj[DEFAULTS.showStringAs] = userOpts;
if (DEFAULTS.enableDynamicSize && userOpts.length > DEFAULTS.extendSizeCharLength) {
obj.size = 'md';
}
userOpts = obj;
}
options.buttons = buttons;
return angular.extend(options, userOpts);
}
function _showPopup(options) {
var modalInstance = $uibModal.open({
template: options.isSpinner ? SPINNER_TEMPLATE : POPUP_TEMPLATE,
size: options.size,
backdrop: options.backdrop,
keyboard: options.keyboard,
windowClass: options.windowClass,
bindToController: true,
controllerAs: 'vm',
controller: ['$injector', 'options', ModelController],
resolve: {
options: function() {
return options;
}
}
});
var obj = modalInstance.result; //returned promise
obj.close = modalInstance.close; //augment close method
return obj;
}
function ModelController($injector, options) {
var vm = this;
sanitizeInput(options);
angular.extend(vm, options);
vm.onButtonClick = function(button, $index) {
var response = button.handler(); //true for alert, true and false for confirm
vm.$close(response);
};
function sanitizeInput(options) {
if ($injector.has('$sanitize')) {
return; //no need to sanitize
}
var $sce = $injector.get('$sce');
options.title = $sce.trustAsHtml(options.title);
if (options.isSpinner) {
return;
}
options.subTitle = $sce.trustAsHtml(options.subTitle);
options.body = $sce.trustAsHtml(options.body);
options.buttons.forEach(function(button, index, buttons) {
button.text = $sce.trustAsHtml(button.text);
});
}
}
}
})();
/*! popup.service.min.js v1.1 by Amitesh Kumar, updated 2017-10-20. Visit https://github.com/amiteshhh/utilities/angular/popup */
!function(){function t(){var t={okText:"OK",okClass:"btn-info",cancelText:"Cancel",cancelClass:"btn-secondary",headerClass:"text-center",bodyClass:"",footerClass:"",backdrop:"static",keyboard:!1,size:"sm",showStringAs:"body",enableDynamicSize:!0,extendSizeCharLength:300};this.setDefaults=function(n){angular.extend(t,n)},this.$get=["$uibModal",function(e){return new n(t,e)}]}function n(t,n){function e(){angular.element(document).find("head").prepend('<style type="text/css">@charset "UTF-8";.modal-spinner .modal-content{padding:20px;border-radius:5px;background-color:rgba(0,0,0,.8);color:#fff;text-align:center;text-overflow:ellipsis;font-size:15px}.modal-spinner-text .modal-content{text-align:left}.modal-spinner .modal-dialog{position:absolute;left:0;right:0;top:0;bottom:0;margin:auto;width:80px;height:300px}.modal-spinner-text .modal-dialog{text-align:left;width:250px}</style>')}function o(n){return d(r([{text:n.okText||t.okText,className:n.okClass||t.okClass,handler:function(){return!0}}],n||{}))}function s(n){return d(r([{text:n.cancelText||t.cancelText,className:n.cancelClass||t.cancelClass,handler:function(){return!1}},{text:n.okText||t.okText,className:n.okClass||t.okClass,handler:function(){return!0}}],n||{}))}function a(t){var n="modal-spinner";t&&(n+=" modal-spinner-text");var e=d({title:t,backdrop:"static",keyboard:!1,windowClass:n,isSpinner:!0}),o=e.close,s=m.length;return m.push(e),e.close=function(t){o(),t||m.splice(s,1)},e}function l(){if(m.length){var t=m.pop();t.close(!0)}}function i(){for(var t;m.length;)t=m.pop(),t.close(!0)}function r(n,e){var o=angular.copy(t);if(e=e||"You there?","string"==typeof e){var s={};s[t.showStringAs]=e,t.enableDynamicSize&&e.length>t.extendSizeCharLength&&(s.size="md"),e=s}return o.buttons=n,angular.extend(o,e)}function d(t){var e=n.open({template:t.isSpinner?p:u,size:t.size,backdrop:t.backdrop,keyboard:t.keyboard,windowClass:t.windowClass,bindToController:!0,controllerAs:"vm",controller:["$injector","options",c],resolve:{options:function(){return t}}}),o=e.result;return o.close=e.close,o}function c(t,n){function e(n){if(!t.has("$sanitize")){var e=t.get("$sce");n.title=e.trustAsHtml(n.title),n.isSpinner||(n.subTitle=e.trustAsHtml(n.subTitle),n.body=e.trustAsHtml(n.body),n.buttons.forEach(function(t,n,o){t.text=e.trustAsHtml(t.text)}))}}var o=this;e(n),angular.extend(o,n),o.onButtonClick=function(t,n){var e=t.handler();o.$close(e)}}var u=' <div> <div class="modal-header" ng-class="vm.headerClass" ng-if="vm.title" style="border:none; padding-bottom: 0;"> <h3 class="modal-title" ng-bind-html="vm.title"></h3> <h5 class="modal-sub-title" ng-bind-html="vm.subTitle" ng-if="vm.subTitle"></h5> </div> <div class="modal-body" ng-if="vm.body" ng-class="vm.bodyClass"> <div ng-bind-html="vm.body"></div> </div> <div class="modal-footer" ng-class="vm.footerClass" style="text-align: center; padding-top: 10px; padding-bottom: 15px; border: none"> <div xclass="btn-group"> <button ng-repeat="button in vm.buttons" ng-click="vm.onButtonClick(button, $index)" style="min-width: 70px;" class="btn" ng-class="button.className" ng-bind-html="button.text"></button> </div> </div> </div>',p='<div><i class="fa fa-spinner fa-spin fa-2x"></i><span style="margin-left:5px; font-size: 1.3em">{{vm.title}}</span></div>',m=[];return e(),{alert:o,confirm:s,spin:a,stopSpin:l,stopAll:i}}angular.module("popup",[]).provider("PopupSvc",t)}();
# Angular Bootstrap Popup
A simple and elegant angular service inspired by [ionic popup](http://ionicframework.com/docs/v1/api/service/$ionicPopup) to show loader/spinner and popup(or dialogue) window for `alert` and `confirm` with custom content and look.
## Dialoge Box
PopupSvc exposes two methods `alert` and `confirm` which takes one parameter either string/html template or an [option](#advance-usage) object for customized look and feel.
These methods returns [promise](https://docs.angularjs.org/api/ng/service/$q) which is resolved when the popup is dismissed. It also returns `close` method to programmatically close it.
## Spinner
Use below methods to display a loader or spinner as overlay driven by Bootstrap modal window
1. spin : Show a spinner/loader
2. stopSpin: Stop the spinner
## Dependency
[Angular](https://code.angularjs.org/1.5.3/docs/api) (tested on v1.5.3)
[Angular UI Bootstrap](http://angular-ui.github.io/bootstrap/versioned-docs/1.3.3/) (tested on v1.3.3)
> PopupSvc should work fine with any Angular/UI Bootstrap version supporting [ControllerAs](https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/) syntax.
## Demo
Check out the demo at [Plunker](https://embed.plnkr.co/SNhye1/)
## Dialoge Usage
```javascript
angular.module('myApp', ['popup']);//add popup module dependency
angular.controller('myCtrl', ['PopupSvc', function(PopupSvc){//Inject the PopupSvc service into your controller
//1. Basic Usage
PopupSvc.alert("<strong>Hey!</strong> How you doing");//html string
PopupSvc.confirm("Are you sure?");//normal text
//2. Reacting on popup dismissal/button click
var popup = PopupSvc.alert("Hey! How you doing");
popup.then(function(){
console.log('Alert dismissed');
});
PopupSvc.confirm("Hey! How you doing").then(function(response){
if(response){
console.log('Primary/OK button clicked');
}else{
console.log('Secondary/Cancel button clicked');
}
});
//Programmatically closing the popup using `close` method
//close method must be executed in next tick as popup creation is asynchronous
var popup = PopupSvc.alert("Hey! How you doing");
window.setTimeout(popup.close, 3000);
//3. Customized popup
var popupOption = {//only fewer options here
title: 'Confirm',
subTitle: '<span style="color: red;">Are you sure?</span>',
body: 'Operation can not be reverted',
okText: 'Delete',
okClass: 'btn-danger',
size: 'md'//show a medium size modal popup
};
PopupSvc.confirm(popupOption);
}]);
```
## Spinner Usage
```javascript
PopupSvc.spin();//spinner without leading text
PopupSvc.spin('Saving...');//spinner with leading text
PopupSvc.stopSpin();//stop and remove the last spinner
//Advance usage to stop the required spinner in case of multiple spinner showing at a time
var modal = PopupSvc.spin();//will create the spinner and return modal reference to stop it
modal.close();//stop or close the spinner
```
## Install
Download the script file directly from Github.
https://raw.githubusercontent.com/amiteshhh/angular-uib-popup/master/popup.service.min.js
Add `script` reference to your html then add `popup` module as angular module dependency. Now you can use `PopupSvc` service.
## Advance Usage
To have a custom look and feel (e.g button texts etc.) use below option as a parameter to `alert` or `confirm`. All of the option properties are optional. Of course you will provide value for `body` or `title` to render some text.
> popup is created using bootstrap $uibModal hence there are few properties related to that as well
```javascript
{
title: '', // String. The title of the popup.
subTitle: '', // String. The sub-title of the popup. only applicable when title provided
body: '',//String to place in the popup body.
okText: 'OK',//text for OK button
okClass: 'btn-info',//class(es) to be added to OK button; e.g 'btn-info btn-small'
cancelText: 'Cancel',//not applicable for alert
cancelClass: 'btn-secondary',
headerClass: 'text-center',//class to be added to bootstrap modal-header
bodyClass: '',//class for bootstrap modal-body
footerClass: '',//class for bootstrap modal-footer
//Below are the three uibModal related properties, see uibModal Bootstrap documentation for details
backdrop: 'static',//Controls presence of a backdrop. Allowed values: true (default), false (no backdrop), 'static' (disables modal closing by click on the backdrop).
keyboard: false,//Indicates whether the dialog should be closable by hitting the ESC key.
size: 'sm',//modal or popup size, default is small
/*NOTE: Below are the app level configuration applicable when input parameter is string. It can be set during angular config phase.
*/
showStringAs: 'body',//it will display the text as modal body(left aligned smaller font text). Other value is 'title' (center aligned h5 element)
enableDynamicSize: true,//show medium size popup when input string extends the below character limit
extendSizeCharLength: 300
};
```
> Sice all applicable string inputs can contains `html` tags therefore you can easily control the style.
## Default Configuration
You can easily configure the default popup option for the application during config phase using `PopupSvcProvider` as below.
```javascript
angular.module('myApp', ['popup'])
.config(['PopupSvcProvider', function(PopupSvcProvider){
PopupSvcProvider.setDefaults({
okText: 'Dismiss',//Now instead of 'OK' popup will show button with text 'Dismiss'
okClass: 'btn-primary',
cancelText: 'Close',
keyboard: true//popup can be closed now with ESC key.
});
}]);
```
However the option parameter will still take precedence over app level configuration.
## License
MIT
/* Below css already include in directive and therefore not required separately*/
.modal-spinner .modal-content {
padding: 20px;
border-radius: 5px;
background-color: rgba(0, 0, 0, 0.8);
color: #fff;
text-align: center;
text-overflow: ellipsis;
font-size: 15px;
}
.modal-spinner-text .modal-content{
text-align: left;
}
.modal-spinner .modal-dialog {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 80px;
height: 300px;
}
.modal-spinner-text .modal-dialog{
text-align: left;
width: 250px;
}