angular-busy.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. angular.module('cgBusy',[]);
  2. //loosely modeled after angular-promise-tracker
  3. angular.module('cgBusy').factory('_cgBusyTrackerFactory',['$timeout','$q',function($timeout,$q){
  4. return function(){
  5. var tracker = {};
  6. tracker.promises = [];
  7. tracker.delayPromise = null;
  8. tracker.durationPromise = null;
  9. tracker.delayJustFinished = false;
  10. tracker.reset = function(options){
  11. tracker.minDuration = options.minDuration;
  12. tracker.promises = [];
  13. angular.forEach(options.promises,function(p){
  14. if (!p || p.$cgBusyFulfilled) {
  15. return;
  16. }
  17. addPromiseLikeThing(p);
  18. });
  19. if (tracker.promises.length === 0) {
  20. //if we have no promises then dont do the delay or duration stuff
  21. return;
  22. }
  23. tracker.delayJustFinished = false;
  24. if (options.delay) {
  25. tracker.delayPromise = $timeout(function(){
  26. tracker.delayPromise = null;
  27. tracker.delayJustFinished = true;
  28. },parseInt(options.delay,10));
  29. }
  30. if (options.minDuration) {
  31. tracker.durationPromise = $timeout(function(){
  32. tracker.durationPromise = null;
  33. },parseInt(options.minDuration,10) + (options.delay ? parseInt(options.delay,10) : 0));
  34. }
  35. };
  36. tracker.isPromise = function(promiseThing){
  37. var then = promiseThing && (promiseThing.then || promiseThing.$then ||
  38. (promiseThing.$promise && promiseThing.$promise.then));
  39. return typeof then !== 'undefined';
  40. };
  41. tracker.callThen = function(promiseThing,success,error){
  42. var promise;
  43. if (promiseThing.then || promiseThing.$then){
  44. promise = promiseThing;
  45. } else if (promiseThing.$promise){
  46. promise = promiseThing.$promise;
  47. } else if (promiseThing.denodeify){
  48. promise = $q.when(promiseThing);
  49. }
  50. var then = (promise.then || promise.$then);
  51. then.call(promise,success,error);
  52. };
  53. var addPromiseLikeThing = function(promise){
  54. if (!tracker.isPromise(promise)) {
  55. throw new Error('cgBusy expects a promise (or something that has a .promise or .$promise');
  56. }
  57. if (tracker.promises.indexOf(promise) !== -1){
  58. return;
  59. }
  60. tracker.promises.push(promise);
  61. tracker.callThen(promise, function(){
  62. promise.$cgBusyFulfilled = true;
  63. if (tracker.promises.indexOf(promise) === -1) {
  64. return;
  65. }
  66. tracker.promises.splice(tracker.promises.indexOf(promise),1);
  67. },function(){
  68. promise.$cgBusyFulfilled = true;
  69. if (tracker.promises.indexOf(promise) === -1) {
  70. return;
  71. }
  72. tracker.promises.splice(tracker.promises.indexOf(promise),1);
  73. });
  74. };
  75. tracker.active = function(){
  76. if (tracker.delayPromise){
  77. return false;
  78. }
  79. if (!tracker.delayJustFinished){
  80. if (tracker.durationPromise){
  81. return true;
  82. }
  83. return tracker.promises.length > 0;
  84. } else {
  85. //if both delay and min duration are set,
  86. //we don't want to initiate the min duration if the
  87. //promise finished before the delay was complete
  88. tracker.delayJustFinished = false;
  89. if (tracker.promises.length === 0) {
  90. tracker.durationPromise = null;
  91. }
  92. return tracker.promises.length > 0;
  93. }
  94. };
  95. return tracker;
  96. };
  97. }]);
  98. angular.module('cgBusy').value('cgBusyDefaults',{});
  99. angular.module('cgBusy').directive('cgBusy',['$compile','$templateCache','cgBusyDefaults','$http','_cgBusyTrackerFactory',
  100. function($compile,$templateCache,cgBusyDefaults,$http,_cgBusyTrackerFactory){
  101. return {
  102. restrict: 'A',
  103. link: function(scope, element, attrs, fn) {
  104. //Apply position:relative to parent element if necessary
  105. var position = element.css('position');
  106. if (position === 'static' || position === '' || typeof position === 'undefined'){
  107. element.css('position','relative');
  108. }
  109. var templateElement;
  110. var backdropElement;
  111. var currentTemplate;
  112. var templateScope;
  113. var backdrop;
  114. var tracker = _cgBusyTrackerFactory();
  115. var defaults = {
  116. templateUrl: 'angular-busy.html',
  117. delay:0,
  118. minDuration:0,
  119. backdrop: true,
  120. message:'Please Wait...',
  121. wrapperClass: 'cg-busy cg-busy-animation'
  122. };
  123. angular.extend(defaults,cgBusyDefaults);
  124. scope.$watchCollection(attrs.cgBusy,function(options){
  125. if (!options) {
  126. options = {promise:null};
  127. }
  128. if (angular.isString(options)) {
  129. throw new Error('Invalid value for cg-busy. cgBusy no longer accepts string ids to represent promises/trackers.');
  130. }
  131. //is it an array (of promises) or one promise
  132. if (angular.isArray(options) || tracker.isPromise(options)) {
  133. options = {promise:options};
  134. }
  135. options = angular.extend(angular.copy(defaults),options);
  136. if (!options.templateUrl){
  137. options.templateUrl = defaults.templateUrl;
  138. }
  139. if (!angular.isArray(options.promise)){
  140. options.promise = [options.promise];
  141. }
  142. // options.promise = angular.isArray(options.promise) ? options.promise : [options.promise];
  143. // options.message = options.message ? options.message : 'Please Wait...';
  144. // options.template = options.template ? options.template : cgBusyTemplateName;
  145. // options.minDuration = options.minDuration ? options.minDuration : 0;
  146. // options.delay = options.delay ? options.delay : 0;
  147. if (!templateScope) {
  148. templateScope = scope.$new();
  149. }
  150. templateScope.$message = options.message;
  151. if (!angular.equals(tracker.promises,options.promise)) {
  152. tracker.reset({
  153. promises:options.promise,
  154. delay:options.delay,
  155. minDuration: options.minDuration
  156. });
  157. }
  158. templateScope.$cgBusyIsActive = function() {
  159. return tracker.active();
  160. };
  161. if (!templateElement || currentTemplate !== options.templateUrl || backdrop !== options.backdrop) {
  162. if (templateElement) {
  163. templateElement.remove();
  164. }
  165. if (backdropElement){
  166. backdropElement.remove();
  167. }
  168. currentTemplate = options.templateUrl;
  169. backdrop = options.backdrop;
  170. $http.get(currentTemplate,{cache: $templateCache}).success(function(indicatorTemplate){
  171. options.backdrop = typeof options.backdrop === 'undefined' ? true : options.backdrop;
  172. if (options.backdrop){
  173. var backdrop = '<div class="cg-busy cg-busy-backdrop cg-busy-backdrop-animation ng-hide" ng-show="$cgBusyIsActive()"></div>';
  174. backdropElement = $compile(backdrop)(templateScope);
  175. element.append(backdropElement);
  176. }
  177. var template = '<div class="'+options.wrapperClass+' ng-hide" ng-show="$cgBusyIsActive()">' + indicatorTemplate + '</div>';
  178. templateElement = $compile(template)(templateScope);
  179. angular.element(templateElement.children()[0])
  180. .css('position','absolute')
  181. .css('top',0)
  182. .css('left',0)
  183. .css('right',0)
  184. .css('bottom',0);
  185. element.append(templateElement);
  186. }).error(function(data){
  187. throw new Error('Template specified for cgBusy ('+options.templateUrl+') could not be loaded. ' + data);
  188. });
  189. }
  190. },true);
  191. }
  192. };
  193. }
  194. ]);