diff --git a/.gitignore b/.gitignore index 4d6b8e2..71162c2 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ build/Release # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git node_modules -temp \ No newline at end of file +temp +.idea +_SpecRunner.html diff --git a/README.md b/README.md index ccb3f14..222b661 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ > Angular service to easily display prompt and confirmation modals. -This library depends on [angular-ui-bootstrap](https://github.com/angular-ui/bootstrap). +This library depends on [angular-ui-bootstrap](https://github.com/angular-ui/bootstrap). ## Demo @@ -23,7 +23,7 @@ Add `cgPrompt` as a module dependency for your module. angular.module('your_app', ['ui.bootstrap','cgPrompt']); ``` -Now you can inject and use the `prompt` service. +Now you can inject and use the `prompt` service. If you are going to use **html messages** in prompt, you must have installed [`angular-sanitize`](https://github.com/angular/bower-angular-sanitize) module in your app. ```js function MyCtrl($scope, prompt) { @@ -57,12 +57,12 @@ function MyCtrl($scope, prompt) { - #### options.title Type: `String` Default: `''` - The title for the dialog. + The title for the dialog. This can be html. - #### options.message Type: `String` Default: `''` - The message inside the dialog. + The message inside the dialog. This can be html. - #### options.input Type: `Boolean` @@ -87,11 +87,27 @@ function MyCtrl($scope, prompt) { - #### options.buttons Type: `Array` of `Object` with properties `label`,`cancel`, `style`, and `primary` Default: `[{ label:'OK', primary: true }, { label:'Cancel', cancel: true }]` - A list of the buttons to display on the dialog. + A list of the buttons to display on the dialog. Label property can be html. + + - #### options.backdrop + Type: `Boolean` or `String` + Default: `true` + You can set modal backdrop using bootstrap modal options. [See here](https://angular-ui.github.io/bootstrap/#/modal) + - `true` by default, modal will be dismissed when clicking anywhere on backdrop. + - `false` for removing backdrop. + - `static` to make user click on close button to dismiss prompt. The function returns a promise. That promise is resolved with either the button that was pressed, or in the case of input prompts, the value the user entered. If the user pressed a button where `cancel=true` or canceled the dialog another way (hit ESC, etc) then the promise is rejected. ## Release History + * v1.1.2 + * Added HTML support for modal header/title and button labels in footer + * v1.1.1 + * Added a base class `cg-prompt-wrapper` for customization. + * Added `html` message support. + * Added bootstrap modal `backdrop` option. + * Moved to *angular v1.3.15*. + * Moved to *angular-bootstrap v0.13*. * v1.1.0 * Added `style` option to buttons. * v1.0.1 diff --git a/angular-prompt.html b/angular-prompt.html index 4a0b2c8..d2b5786 100644 --- a/angular-prompt.html +++ b/angular-prompt.html @@ -1,13 +1,12 @@ -
+
\ No newline at end of file diff --git a/angular-prompt.js b/angular-prompt.js index b11bb0d..b316c4f 100644 --- a/angular-prompt.js +++ b/angular-prompt.js @@ -7,6 +7,7 @@ angular.module('cgPrompt').factory('prompt',['$modal','$q',function($modal,$q){ var defaults = { title: '', message: '', + backdrop: true, input: false, label: '', value: '', @@ -32,6 +33,7 @@ angular.module('cgPrompt').factory('prompt',['$modal','$q',function($modal,$q){ $modal.open({ templateUrl:'angular-prompt.html', controller: 'cgPromptCtrl', + backdrop: options.backdrop, resolve: { options:function(){ return options; diff --git a/bower.json b/bower.json index 9a831a7..e908122 100644 --- a/bower.json +++ b/bower.json @@ -1,13 +1,14 @@ { "name": "angular-prompt", "description": "Angular service to easily display prompt and confirmation modals.", - "version": "1.1.1", + "version": "1.1.2", "main": [ "dist/angular-prompt.js" ], "dependencies": { - "angular": "~1.2.16", - "angular-bootstrap": "~0.12.0" + "angular": "~1.3.15", + "angular-bootstrap": "~0.13.0", + "angular-sanitize": "~1.3.15" }, "ignore": [ "**/.*", diff --git a/bower_components/angular-bootstrap/.bower.json b/bower_components/angular-bootstrap/.bower.json index 29c7303..23a572a 100644 --- a/bower_components/angular-bootstrap/.bower.json +++ b/bower_components/angular-bootstrap/.bower.json @@ -11,21 +11,21 @@ "license": "MIT", "ignore": [], "description": "Native AngularJS (Angular) directives for Bootstrap.", - "version": "0.12.1", + "version": "0.13.0", "main": [ "./ui-bootstrap-tpls.js" ], "dependencies": { - "angular": ">=1 <1.3.0" + "angular": ">=1.3.0" }, "homepage": "https://github.com/angular-ui/bootstrap-bower", - "_release": "0.12.1", + "_release": "0.13.0", "_resolution": { "type": "version", - "tag": "0.12.1", - "commit": "ab14fbaaf3d592f8e76018f0666c5af6f68ebaa3" + "tag": "0.13.0", + "commit": "a75d899addcafb73344b724bec647620adeebc9a" }, "_source": "git://github.com/angular-ui/bootstrap-bower.git", - "_target": "~0.12.0", + "_target": "~0.13.0", "_originalSource": "angular-bootstrap" } \ No newline at end of file diff --git a/bower_components/angular-bootstrap/bower.json b/bower_components/angular-bootstrap/bower.json index 8f6991b..ea65aad 100644 --- a/bower_components/angular-bootstrap/bower.json +++ b/bower_components/angular-bootstrap/bower.json @@ -11,9 +11,9 @@ "license": "MIT", "ignore": [], "description": "Native AngularJS (Angular) directives for Bootstrap.", - "version": "0.12.1", + "version": "0.13.0", "main": ["./ui-bootstrap-tpls.js"], "dependencies": { - "angular": ">=1 <1.3.0" - } + "angular": ">=1.3.0" + } } diff --git a/bower_components/angular-bootstrap/ui-bootstrap-csp.css b/bower_components/angular-bootstrap/ui-bootstrap-csp.css new file mode 100644 index 0000000..d772f78 --- /dev/null +++ b/bower_components/angular-bootstrap/ui-bootstrap-csp.css @@ -0,0 +1,6 @@ +/* Include this file in your html if you are using the CSP mode. */ + +.ng-animate.item:not(.left):not(.right) { + -webkit-transition: 0s ease-in-out left; + transition: 0s ease-in-out left +} \ No newline at end of file diff --git a/bower_components/angular-bootstrap/ui-bootstrap-tpls.js b/bower_components/angular-bootstrap/ui-bootstrap-tpls.js index eda964c..6119661 100644 --- a/bower_components/angular-bootstrap/ui-bootstrap-tpls.js +++ b/bower_components/angular-bootstrap/ui-bootstrap-tpls.js @@ -2,155 +2,47 @@ * angular-ui-bootstrap * http://angular-ui.github.io/bootstrap/ - * Version: 0.12.1 - 2015-02-20 + * Version: 0.13.0 - 2015-05-02 * License: MIT */ -angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.transition","ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.typeahead"]); -angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]); -angular.module('ui.bootstrap.transition', []) - -/** - * $transition service provides a consistent interface to trigger CSS 3 transitions and to be informed when they complete. - * @param {DOMElement} element The DOMElement that will be animated. - * @param {string|object|function} trigger The thing that will cause the transition to start: - * - As a string, it represents the css class to be added to the element. - * - As an object, it represents a hash of style attributes to be applied to the element. - * - As a function, it represents a function to be called that will cause the transition to occur. - * @return {Promise} A promise that is resolved when the transition finishes. - */ -.factory('$transition', ['$q', '$timeout', '$rootScope', function($q, $timeout, $rootScope) { - - var $transition = function(element, trigger, options) { - options = options || {}; - var deferred = $q.defer(); - var endEventName = $transition[options.animation ? 'animationEndEventName' : 'transitionEndEventName']; - - var transitionEndHandler = function(event) { - $rootScope.$apply(function() { - element.unbind(endEventName, transitionEndHandler); - deferred.resolve(element); - }); - }; - - if (endEventName) { - element.bind(endEventName, transitionEndHandler); - } - - // Wrap in a timeout to allow the browser time to update the DOM before the transition is to occur - $timeout(function() { - if ( angular.isString(trigger) ) { - element.addClass(trigger); - } else if ( angular.isFunction(trigger) ) { - trigger(element); - } else if ( angular.isObject(trigger) ) { - element.css(trigger); - } - //If browser does not support transitions, instantly resolve - if ( !endEventName ) { - deferred.resolve(element); - } - }); +angular.module("ui.bootstrap", ["ui.bootstrap.tpls", "ui.bootstrap.collapse","ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.bindHtml","ui.bootstrap.buttons","ui.bootstrap.carousel","ui.bootstrap.dateparser","ui.bootstrap.position","ui.bootstrap.datepicker","ui.bootstrap.dropdown","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tooltip","ui.bootstrap.popover","ui.bootstrap.progressbar","ui.bootstrap.rating","ui.bootstrap.tabs","ui.bootstrap.timepicker","ui.bootstrap.transition","ui.bootstrap.typeahead"]); +angular.module("ui.bootstrap.tpls", ["template/accordion/accordion-group.html","template/accordion/accordion.html","template/alert/alert.html","template/carousel/carousel.html","template/carousel/slide.html","template/datepicker/datepicker.html","template/datepicker/day.html","template/datepicker/month.html","template/datepicker/popup.html","template/datepicker/year.html","template/modal/backdrop.html","template/modal/window.html","template/pagination/pager.html","template/pagination/pagination.html","template/tooltip/tooltip-html-popup.html","template/tooltip/tooltip-html-unsafe-popup.html","template/tooltip/tooltip-popup.html","template/tooltip/tooltip-template-popup.html","template/popover/popover-template.html","template/popover/popover.html","template/progressbar/bar.html","template/progressbar/progress.html","template/progressbar/progressbar.html","template/rating/rating.html","template/tabs/tab.html","template/tabs/tabset.html","template/timepicker/timepicker.html","template/typeahead/typeahead-match.html","template/typeahead/typeahead-popup.html"]); +angular.module('ui.bootstrap.collapse', []) - // Add our custom cancel function to the promise that is returned - // We can call this if we are about to run a new transition, which we know will prevent this transition from ending, - // i.e. it will therefore never raise a transitionEnd event for that transition - deferred.promise.cancel = function() { - if ( endEventName ) { - element.unbind(endEventName, transitionEndHandler); - } - deferred.reject('Transition cancelled'); - }; - - return deferred.promise; - }; - - // Work out the name of the transitionEnd event - var transElement = document.createElement('trans'); - var transitionEndEventNames = { - 'WebkitTransition': 'webkitTransitionEnd', - 'MozTransition': 'transitionend', - 'OTransition': 'oTransitionEnd', - 'transition': 'transitionend' - }; - var animationEndEventNames = { - 'WebkitTransition': 'webkitAnimationEnd', - 'MozTransition': 'animationend', - 'OTransition': 'oAnimationEnd', - 'transition': 'animationend' - }; - function findEndEventName(endEventNames) { - for (var name in endEventNames){ - if (transElement.style[name] !== undefined) { - return endEventNames[name]; - } - } - } - $transition.transitionEndEventName = findEndEventName(transitionEndEventNames); - $transition.animationEndEventName = findEndEventName(animationEndEventNames); - return $transition; -}]); - -angular.module('ui.bootstrap.collapse', ['ui.bootstrap.transition']) - - .directive('collapse', ['$transition', function ($transition) { + .directive('collapse', ['$animate', function ($animate) { return { link: function (scope, element, attrs) { - - var initialAnimSkip = true; - var currentTransition; - - function doTransition(change) { - var newTransition = $transition(element, change); - if (currentTransition) { - currentTransition.cancel(); - } - currentTransition = newTransition; - newTransition.then(newTransitionDone, newTransitionDone); - return newTransition; - - function newTransitionDone() { - // Make sure it's this transition, otherwise, leave it alone. - if (currentTransition === newTransition) { - currentTransition = undefined; - } - } - } - function expand() { - if (initialAnimSkip) { - initialAnimSkip = false; - expandDone(); - } else { - element.removeClass('collapse').addClass('collapsing'); - doTransition({ height: element[0].scrollHeight + 'px' }).then(expandDone); - } + element.removeClass('collapse').addClass('collapsing'); + $animate.addClass(element, 'in', { + to: { height: element[0].scrollHeight + 'px' } + }).then(expandDone); } function expandDone() { element.removeClass('collapsing'); - element.addClass('collapse in'); element.css({height: 'auto'}); } function collapse() { - if (initialAnimSkip) { - initialAnimSkip = false; - collapseDone(); - element.css({height: 0}); - } else { - // CSS transitions don't work with height: auto, so we have to manually change the height to a specific value - element.css({ height: element[0].scrollHeight + 'px' }); - //trigger reflow so a browser realizes that height was updated from auto to a specific value - var x = element[0].offsetWidth; - - element.removeClass('collapse in').addClass('collapsing'); - - doTransition({ height: 0 }).then(collapseDone); - } + element + // IMPORTANT: The height must be set before adding "collapsing" class. + // Otherwise, the browser attempts to animate from height 0 (in + // collapsing class) to the given height here. + .css({height: element[0].scrollHeight + 'px'}) + // initially all panel collapse have the collapse class, this removal + // prevents the animation from jumping to collapsed state + .removeClass('collapse') + .addClass('collapsing'); + + $animate.removeClass(element, 'in', { + to: {height: '0'} + }).then(collapseDone); } function collapseDone() { + element.css({height: '0'}); // Required so that collapse works when animation is disabled element.removeClass('collapsing'); element.addClass('collapse'); } @@ -272,7 +164,7 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse']) // Pass the heading to the accordion-group controller // so that it can be transcluded into the right place in the template // [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat] - accordionGroupCtrl.setHeading(transclude(scope, function() {})); + accordionGroupCtrl.setHeading(transclude(scope, angular.noop)); } }; }) @@ -295,7 +187,9 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse']) }); } }; -}); +}) + +; angular.module('ui.bootstrap.alert', []) @@ -422,8 +316,8 @@ angular.module('ui.bootstrap.buttons', []) * AngularJS version of an image carousel. * */ -angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) -.controller('CarouselController', ['$scope', '$timeout', '$interval', '$transition', function ($scope, $timeout, $interval, $transition) { +angular.module('ui.bootstrap.carousel', []) +.controller('CarouselController', ['$scope', '$interval', '$animate', function ($scope, $interval, $animate) { var self = this, slides = self.slides = $scope.slides = [], currentIndex = -1, @@ -433,82 +327,76 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) var destroyed = false; /* direction: "prev" or "next" */ self.select = $scope.select = function(nextSlide, direction) { - var nextIndex = slides.indexOf(nextSlide); + var nextIndex = self.indexOfSlide(nextSlide); //Decide direction if it's not given if (direction === undefined) { - direction = nextIndex > currentIndex ? 'next' : 'prev'; + direction = nextIndex > self.getCurrentIndex() ? 'next' : 'prev'; } if (nextSlide && nextSlide !== self.currentSlide) { - if ($scope.$currentTransition) { - $scope.$currentTransition.cancel(); - //Timeout so ng-class in template has time to fix classes for finished slide - $timeout(goNext); - } else { - goNext(); - } + goNext(); } function goNext() { // Scope has been destroyed, stop here. if (destroyed) { return; } - //If we have a slide to transition from and we have a transition type and we're allowed, go - if (self.currentSlide && angular.isString(direction) && !$scope.noTransition && nextSlide.$element) { - //We shouldn't do class manip in here, but it's the same weird thing bootstrap does. need to fix sometime - nextSlide.$element.addClass(direction); - var reflow = nextSlide.$element[0].offsetWidth; //force reflow - - //Set all other slides to stop doing their stuff for the new transition - angular.forEach(slides, function(slide) { - angular.extend(slide, {direction: '', entering: false, leaving: false, active: false}); + + angular.extend(nextSlide, {direction: direction, active: true}); + angular.extend(self.currentSlide || {}, {direction: direction, active: false}); + if ($animate.enabled() && !$scope.noTransition && nextSlide.$element) { + $scope.$currentTransition = true; + nextSlide.$element.one('$animate:close', function closeFn() { + $scope.$currentTransition = null; }); - angular.extend(nextSlide, {direction: direction, active: true, entering: true}); - angular.extend(self.currentSlide||{}, {direction: direction, leaving: true}); - - $scope.$currentTransition = $transition(nextSlide.$element, {}); - //We have to create new pointers inside a closure since next & current will change - (function(next,current) { - $scope.$currentTransition.then( - function(){ transitionDone(next, current); }, - function(){ transitionDone(next, current); } - ); - }(nextSlide, self.currentSlide)); - } else { - transitionDone(nextSlide, self.currentSlide); } + self.currentSlide = nextSlide; currentIndex = nextIndex; //every time you change slides, reset the timer restartTimer(); } - function transitionDone(next, current) { - angular.extend(next, {direction: '', active: true, leaving: false, entering: false}); - angular.extend(current||{}, {direction: '', active: false, leaving: false, entering: false}); - $scope.$currentTransition = null; - } }; $scope.$on('$destroy', function () { destroyed = true; }); + function getSlideByIndex(index) { + if (angular.isUndefined(slides[index].index)) { + return slides[index]; + } + var i, len = slides.length; + for (i = 0; i < slides.length; ++i) { + if (slides[i].index == index) { + return slides[i]; + } + } + } + + self.getCurrentIndex = function() { + if (self.currentSlide && angular.isDefined(self.currentSlide.index)) { + return +self.currentSlide.index; + } + return currentIndex; + }; + /* Allow outside people to call indexOf on slides array */ self.indexOfSlide = function(slide) { - return slides.indexOf(slide); + return angular.isDefined(slide.index) ? +slide.index : slides.indexOf(slide); }; $scope.next = function() { - var newIndex = (currentIndex + 1) % slides.length; + var newIndex = (self.getCurrentIndex() + 1) % slides.length; //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { - return self.select(slides[newIndex], 'next'); + return self.select(getSlideByIndex(newIndex), 'next'); } }; $scope.prev = function() { - var newIndex = currentIndex - 1 < 0 ? slides.length - 1 : currentIndex - 1; + var newIndex = self.getCurrentIndex() - 1 < 0 ? slides.length - 1 : self.getCurrentIndex() - 1; //Prevent this user-triggered transition from occurring if there is already one in progress if (!$scope.$currentTransition) { - return self.select(slides[newIndex], 'prev'); + return self.select(getSlideByIndex(newIndex), 'prev'); } }; @@ -571,6 +459,11 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) }; self.removeSlide = function(slide) { + if (angular.isDefined(slide.index)) { + slides.sort(function(a, b) { + return +a.index > +b.index; + }); + } //get the index of the slide inside the carousel var index = slides.indexOf(slide); slides.splice(index, 1); @@ -650,13 +543,14 @@ angular.module('ui.bootstrap.carousel', ['ui.bootstrap.transition']) * Creates a slide inside a {@link ui.bootstrap.carousel.directive:carousel carousel}. Must be placed as a child of a carousel element. * * @param {boolean=} active Model binding, whether or not this slide is currently active. + * @param {number=} index The index of the slide. The slides will be sorted by this parameter. * * @example
- +