[#369] add angular spinner; some fixes
This commit is contained in:
parent
a0f3225dad
commit
c08fd6d569
1
Gemfile
1
Gemfile
|
@ -74,6 +74,7 @@ gem 'momentjs-rails'
|
||||||
gem 'angular-i18n', '0.1.2'
|
gem 'angular-i18n', '0.1.2'
|
||||||
gem 'js-routes'
|
gem 'js-routes'
|
||||||
gem 'soundmanager-rails'
|
gem 'soundmanager-rails'
|
||||||
|
gem 'angular-ui-bootstrap-rails'
|
||||||
|
|
||||||
gem 'time_diff'
|
gem 'time_diff'
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ GEM
|
||||||
ancestry (2.0.0)
|
ancestry (2.0.0)
|
||||||
activerecord (>= 3.0.0)
|
activerecord (>= 3.0.0)
|
||||||
angular-i18n (0.1.2)
|
angular-i18n (0.1.2)
|
||||||
|
angular-ui-bootstrap-rails (0.10.0)
|
||||||
angularjs-rails (1.2.14)
|
angularjs-rails (1.2.14)
|
||||||
arel (4.0.2)
|
arel (4.0.2)
|
||||||
atomic (1.1.16)
|
atomic (1.1.16)
|
||||||
|
@ -465,6 +466,7 @@ DEPENDENCIES
|
||||||
airbrake (~> 3.1.2)
|
airbrake (~> 3.1.2)
|
||||||
ancestry (~> 2.0.0)
|
ancestry (~> 2.0.0)
|
||||||
angular-i18n (= 0.1.2)
|
angular-i18n (= 0.1.2)
|
||||||
|
angular-ui-bootstrap-rails
|
||||||
angularjs-rails
|
angularjs-rails
|
||||||
attr_encrypted (~> 1.3.2)
|
attr_encrypted (~> 1.3.2)
|
||||||
better_errors
|
better_errors
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
var RosaABF = angular.module('RosaABF', ['ui.bootstrap', 'cgBusy']);
|
||||||
|
|
||||||
|
RosaABF.controller('ActivityCtrl', ['$scope', '$http', '$timeout', 'promiseTracker', '$q',
|
||||||
|
function($scope, $http, $timeout, promiseTracker, $q) {
|
||||||
|
$scope.tabs = [
|
||||||
|
{ title:"All", content:[] , isLoaded:false , active:true, filter:'all'},
|
||||||
|
{ title:"Issues", content:[] , isLoaded:false, filter:'issues' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$scope.getContent=function(tabIndex){
|
||||||
|
|
||||||
|
/* see if we have data already */
|
||||||
|
if($scope.tabs[tabIndex].isLoaded){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
/* or make request for data */
|
||||||
|
var path = Routes.root_path({ filter: $scope.tabs[tabIndex].filter, format: 'json' });
|
||||||
|
$http.get(path, { tracker: 'activity' }).then(function(res){
|
||||||
|
$scope.tabs[tabIndex].content=res.data;
|
||||||
|
$scope.tabs[tabIndex].isLoaded=true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]);
|
|
@ -1,3 +1,10 @@
|
||||||
//= require jquery
|
//= require jquery
|
||||||
|
//= require js-routes
|
||||||
// Loads all Bootstrap javascripts
|
// Loads all Bootstrap javascripts
|
||||||
//= require bootstrap
|
//= require bootstrap
|
||||||
|
//= require unstable/angular
|
||||||
|
// require angular
|
||||||
|
//= require angular-ui-bootstrap-tpls
|
||||||
|
//= require_tree ./angular-new
|
||||||
|
//= require angular-busy
|
||||||
|
//= require promise-tracker
|
|
@ -6,4 +6,5 @@ $navbar-height: 51px;
|
||||||
$navbar-default-link-hover-color: #CEE7FF;
|
$navbar-default-link-hover-color: #CEE7FF;
|
||||||
|
|
||||||
@import "bootstrap";
|
@import "bootstrap";
|
||||||
@import "custom_bootstrap"
|
@import "custom_bootstrap";
|
||||||
|
@import "angular-busy";
|
||||||
|
|
|
@ -2,8 +2,16 @@
|
||||||
%h3.fix
|
%h3.fix
|
||||||
= t("layout.activity_feed.header")
|
= t("layout.activity_feed.header")
|
||||||
= link_to image_tag("rss.ico", width: '15px', height: '15px', class: 'atom_icon'), atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token)
|
= link_to image_tag("rss.ico", width: '15px', height: '15px', class: 'atom_icon'), atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token)
|
||||||
=render 'feed_tabs'
|
/ =#render 'feed_tabs'
|
||||||
=render 'list'
|
/ =render 'list'
|
||||||
|
|
||||||
- content_for :sidebar, render('sidebar')
|
/ - content_for :sidebar, render('sidebar')
|
||||||
- render 'top_menu'
|
/ - render 'top_menu'
|
||||||
|
|
||||||
|
%div{ 'ng-controller' => 'ActivityCtrl', "cg-busy" => "'activity'" }
|
||||||
|
%tabset
|
||||||
|
%tab{ 'ng-repeat' => "tab in tabs", 'heading' => "{{tab.title}}", 'active' => "tab.active", 'select' => 'getContent($index)' }
|
||||||
|
%div{ 'ng-hide' => "!tab.isLoaded" }
|
||||||
|
%h5 Content 1
|
||||||
|
%div{ 'ng-repeat' => "item in tab.content" }
|
||||||
|
{{item}}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
- if user_signed_in?
|
- if user_signed_in?
|
||||||
= auto_discovery_link_tag :atom, atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token), title: t("layout.atom_link_tag_title", nickname: current_user.uname, app_name: APP_CONFIG['project_name'])
|
= auto_discovery_link_tag :atom, atom_activity_feeds_path(format: 'atom', token: current_user.authentication_token), title: t("layout.atom_link_tag_title", nickname: current_user.uname, app_name: APP_CONFIG['project_name'])
|
||||||
|
|
||||||
%body
|
%body{ 'ng-app' => 'RosaABF' }
|
||||||
= render 'layouts/menu/new_top'
|
= render 'layouts/menu/new_top'
|
||||||
%article.container-fluid
|
%article.container-fluid
|
||||||
.row= yield
|
.row= yield
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
%ul
|
%ul
|
||||||
%li= t('bottom_menu.copyright', year: Date.today.year)
|
%li= t('bottom_menu.copyright', year: Date.today.year)
|
||||||
%li ·
|
%li ·
|
||||||
%li= image_tag 'flag.png', alt: 'flag'
|
%li= image_tag 'flag.png', alt: 'flag', class: 'img-responsive'
|
||||||
%li ·
|
%li ·
|
||||||
%li= link_to t('bottom_menu.about'), t('bottom_menu.about_url')
|
%li= link_to t('bottom_menu.about'), t('bottom_menu.about_url')
|
||||||
%li ·
|
%li ·
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
.container-fluid
|
.container-fluid
|
||||||
/ Brand and toggle get grouped for better mobile display
|
/ Brand and toggle get grouped for better mobile display
|
||||||
.navbar-header
|
.navbar-header
|
||||||
%button.navbar-toggle{ "data-target" => "#bs-example-navbar-collapse-1", "data-toggle" => "collapse", type: "button" }
|
%button.navbar-toggle{ "data-target" => "#top-menu-navbar-collapse-1", "data-toggle" => "collapse", type: "button" }
|
||||||
%span.sr-only Toggle navigation
|
%span.sr-only Toggle navigation
|
||||||
%span.icon-bar
|
%span.icon-bar
|
||||||
%span.icon-bar
|
%span.icon-bar
|
||||||
%span.icon-bar
|
%span.icon-bar
|
||||||
= link_to image_tag('logo-mini.png', alt: 'ABF'), root_path, class: 'navbar-brand'
|
= link_to image_tag('logo-mini.png', alt: 'ABF'), root_path, class: 'navbar-brand'
|
||||||
/ Collect the nav links, forms, and other content for toggling
|
/ Collect the nav links, forms, and other content for toggling
|
||||||
#bs-example-navbar-collapse-1.collapse.navbar-collapse
|
#top-menu-navbar-collapse-1.collapse.navbar-collapse
|
||||||
%ul.nav.navbar-nav
|
%ul.nav.navbar-nav
|
||||||
- (collection = t 'top_menu').each do |base, title|
|
- (collection = t 'top_menu').each do |base, title|
|
||||||
- if can? :index, base.to_s.classify.constantize
|
- if can? :index, base.to_s.classify.constantize
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
= text_field_tag 'query', @query, placeholder: t('layout.search.header'), class: 'form-control'
|
= text_field_tag 'query', @query, placeholder: t('layout.search.header'), class: 'form-control'
|
||||||
%ul.nav.navbar-nav.navbar-right
|
%ul.nav.navbar-nav.navbar-right
|
||||||
%li
|
%li
|
||||||
.avatar= image_tag avatar_url(current_user), alt: 'avatar', height: "32"
|
.avatar= image_tag avatar_url(current_user), alt: 'avatar', height: "32", class: 'img-responsive'
|
||||||
- if current_user
|
- if current_user
|
||||||
%li.dropdown
|
%li.dropdown
|
||||||
%a.dropdown-toggle{ "data-toggle" => "dropdown", href: "#" }
|
%a.dropdown-toggle{ "data-toggle" => "dropdown", href: "#" }
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/* ============================================================
|
||||||
|
* angular-busy.js v3.0.2
|
||||||
|
* https://github.com/cgross/angular-busy
|
||||||
|
* ============================================================
|
||||||
|
* Copyright 2013 Chris Gross
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
angular.module('cgBusy',['ajoslin.promise-tracker']);
|
||||||
|
|
||||||
|
angular.module('cgBusy').value('cgBusyTemplateName','angular-busy.html');
|
||||||
|
|
||||||
|
angular.module('cgBusy').directive('cgBusy',['promiseTracker','$compile','$templateCache','cgBusyTemplateName','$http',
|
||||||
|
function(promiseTracker,$compile,$templateCache,cgBusyTemplateName,$http){
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
link: function(scope, element, attrs, fn) {
|
||||||
|
|
||||||
|
var options = scope.$eval(attrs.cgBusy);
|
||||||
|
|
||||||
|
if (typeof options === 'string'){
|
||||||
|
options = {tracker:options};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof options === 'undefined' || typeof options.tracker === 'undefined'){
|
||||||
|
throw new Error('Options for cgBusy directive must be provided (tracker option is required).');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scope.$cgBusyTracker){
|
||||||
|
scope.$cgBusyTracker = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.$cgBusyTracker[options.tracker] = promiseTracker(options.tracker);
|
||||||
|
|
||||||
|
var position = element.css('position');
|
||||||
|
if (position === 'static' || position === '' || typeof position === 'undefined'){
|
||||||
|
element.css('position','relative');
|
||||||
|
}
|
||||||
|
|
||||||
|
var indicatorTemplateName = options.template ? options.template : cgBusyTemplateName;
|
||||||
|
|
||||||
|
$http.get(indicatorTemplateName,{cache: $templateCache}).success(function(indicatorTemplate){
|
||||||
|
|
||||||
|
options.backdrop = typeof options.backdrop === 'undefined' ? true : options.backdrop;
|
||||||
|
var backdrop = options.backdrop ? '<div class="cg-busy cg-busy-backdrop"></div>' : '';
|
||||||
|
|
||||||
|
var template = '<div class="cg-busy" ng-show="$cgBusyTracker[\''+options.tracker+'\'].active()" ng-animate="\'cg-busy\'" style="display:none">'+ backdrop + indicatorTemplate+'</div>';
|
||||||
|
var templateElement = $compile(template)(scope);
|
||||||
|
|
||||||
|
angular.element(templateElement.children()[options.backdrop?1:0])
|
||||||
|
.css('position','absolute')
|
||||||
|
.css('top',0)
|
||||||
|
.css('left',0)
|
||||||
|
.css('right',0)
|
||||||
|
.css('bottom',0);
|
||||||
|
|
||||||
|
element.append(templateElement);
|
||||||
|
|
||||||
|
}).error(function(data){
|
||||||
|
throw new Error('Template specified for cgBusy ('+options.template+') could not be loaded. ' + data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
angular.module("cgBusy").run(["$templateCache", function($templateCache) {
|
||||||
|
|
||||||
|
$templateCache.put("angular-busy.html",
|
||||||
|
"<div class=\"cg-busy-default-wrapper\">" +
|
||||||
|
"" +
|
||||||
|
" <div class=\"cg-busy-default-sign\">" +
|
||||||
|
"" +
|
||||||
|
" <div class=\"cg-busy-default-spinner\">" +
|
||||||
|
" <div class=\"bar1\"></div>" +
|
||||||
|
" <div class=\"bar2\"></div>" +
|
||||||
|
" <div class=\"bar3\"></div>" +
|
||||||
|
" <div class=\"bar4\"></div>" +
|
||||||
|
" <div class=\"bar5\"></div>" +
|
||||||
|
" <div class=\"bar6\"></div>" +
|
||||||
|
" <div class=\"bar7\"></div>" +
|
||||||
|
" <div class=\"bar8\"></div>" +
|
||||||
|
" <div class=\"bar9\"></div>" +
|
||||||
|
" <div class=\"bar10\"></div>" +
|
||||||
|
" <div class=\"bar11\"></div>" +
|
||||||
|
" <div class=\"bar12\"></div>" +
|
||||||
|
" </div>" +
|
||||||
|
"" +
|
||||||
|
" <div class=\"cg-busy-default-text\">Please Wait...</div>" +
|
||||||
|
"" +
|
||||||
|
" </div>" +
|
||||||
|
"" +
|
||||||
|
"</div>"
|
||||||
|
);
|
||||||
|
|
||||||
|
}]);
|
||||||
|
|
|
@ -0,0 +1,242 @@
|
||||||
|
/*
|
||||||
|
* promise-tracker - v1.2.0 - 2013-04-24
|
||||||
|
* http://github.com/ajoslin/angular-promise-tracker
|
||||||
|
* Created by Andy Joslin; Licensed under Public Domain
|
||||||
|
*/
|
||||||
|
angular.module('ajoslin.promise-tracker', [])
|
||||||
|
|
||||||
|
.config(function($httpProvider) {
|
||||||
|
if ($httpProvider.interceptors) {
|
||||||
|
//Support angularJS 1.1.4: interceptors
|
||||||
|
$httpProvider.interceptors.push('trackerHttpInterceptor');
|
||||||
|
} else {
|
||||||
|
//Support angularJS pre 1.1.4: responseInterceptors
|
||||||
|
$httpProvider.responseInterceptors.push('trackerResponseInterceptor');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
angular.module('ajoslin.promise-tracker')
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Intercept all http requests that have a `tracker` option in their config,
|
||||||
|
* and add that http promise to the specified `tracker`
|
||||||
|
*/
|
||||||
|
|
||||||
|
//angular versions before 1.1.4 use responseInterceptor format
|
||||||
|
.factory('trackerResponseInterceptor', function($q, promiseTracker, $injector) {
|
||||||
|
//We use $injector get around circular dependency problem for $http
|
||||||
|
var $http;
|
||||||
|
return function spinnerResponseInterceptor(promise) {
|
||||||
|
if (!$http) $http = $injector.get('$http'); //lazy-load http
|
||||||
|
//We know the latest request is always going to be last in the list
|
||||||
|
var config = $http.pendingRequests[$http.pendingRequests.length-1];
|
||||||
|
if (config.tracker) {
|
||||||
|
promiseTracker(config.tracker).addPromise(promise, config);
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
.factory('trackerHttpInterceptor', function($q, promiseTracker, $injector) {
|
||||||
|
return {
|
||||||
|
request: function(config) {
|
||||||
|
if (config.tracker) {
|
||||||
|
var deferred = promiseTracker(config.tracker).createPromise(config);
|
||||||
|
config.$promiseTrackerDeferred = deferred;
|
||||||
|
}
|
||||||
|
return $q.when(config);
|
||||||
|
},
|
||||||
|
response: function(response) {
|
||||||
|
if (response.config.$promiseTrackerDeferred) {
|
||||||
|
response.config.$promiseTrackerDeferred.resolve(response);
|
||||||
|
}
|
||||||
|
return $q.when(response);
|
||||||
|
},
|
||||||
|
responseError: function(response) {
|
||||||
|
if (response.config.$promiseTrackerDeferred) {
|
||||||
|
response.config.$promiseTrackerDeferred.reject(response);
|
||||||
|
}
|
||||||
|
return $q.reject(response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
angular.module('ajoslin.promise-tracker')
|
||||||
|
|
||||||
|
.provider('promiseTracker', function() {
|
||||||
|
var trackers = {};
|
||||||
|
|
||||||
|
this.$get = ['$q', '$timeout', function($q, $timeout) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
function Tracker(options) {
|
||||||
|
options = options || {};
|
||||||
|
var self = this,
|
||||||
|
//Define our callback types. The user can catch when a promise starts,
|
||||||
|
//has an error, is successful, or just is done with error or success.
|
||||||
|
callbacks = {
|
||||||
|
start: [], //Start is called when a new promise is added
|
||||||
|
done: [], //Called when a promise is resolved (error or success)
|
||||||
|
error: [], //Called on error.
|
||||||
|
success: [] //Called on success.
|
||||||
|
},
|
||||||
|
trackedPromises = [];
|
||||||
|
|
||||||
|
//Allow an optional "minimum duration" that the tracker has to stay
|
||||||
|
//active for. For example, if minimum duration is 1000ms and the user
|
||||||
|
//adds three promises that all resolve after 650ms, the tracker will
|
||||||
|
//still count itself as active until 1000ms have passed.
|
||||||
|
self.setMinDuration = function(minimum) {
|
||||||
|
self._minDuration = minimum;
|
||||||
|
};
|
||||||
|
self.setMinDuration(options.minDuration);
|
||||||
|
|
||||||
|
//Allow an option "maximum duration" that the tracker can stay active.
|
||||||
|
//Ideally, the user would resolve his promises after a certain time to
|
||||||
|
//achieve this 'maximum duration' option, but there are a few cases
|
||||||
|
//where it is necessary anyway.
|
||||||
|
self.setMaxDuration = function(maximum) {
|
||||||
|
self._maxDuration = maximum;
|
||||||
|
};
|
||||||
|
self.setMaxDuration(options.maxDuration);
|
||||||
|
|
||||||
|
//## active()
|
||||||
|
//Returns whether the promiseTracker is active - detect if we're
|
||||||
|
//currently tracking any promises.
|
||||||
|
self.active = function() {
|
||||||
|
return trackedPromises.length > 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//## cancel()
|
||||||
|
//Resolves all the current promises, immediately ending the tracker.
|
||||||
|
self.cancel = function() {
|
||||||
|
angular.forEach(trackedPromises, function(deferred) {
|
||||||
|
deferred.resolve();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function fireEvent(event, param) {
|
||||||
|
angular.forEach(callbacks[event], function(cb) {
|
||||||
|
cb.call(self, param);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a promise that will make our tracker active until it is resolved.
|
||||||
|
//@param startArg: params to pass to 'start' event
|
||||||
|
//@return deferred - our deferred object that is being tracked
|
||||||
|
function createPromise(startArg) {
|
||||||
|
//We create our own promise to track. This usually piggybacks on a given
|
||||||
|
//promise, or we give it back and someone else can resolve it (like
|
||||||
|
//with the httpResponseInterceptor).
|
||||||
|
//Using our own promise also lets us do things like cancel early or add
|
||||||
|
//a minimum duration.
|
||||||
|
var deferred = $q.defer();
|
||||||
|
|
||||||
|
trackedPromises.push(deferred);
|
||||||
|
fireEvent('start', startArg);
|
||||||
|
|
||||||
|
//If the tracker was just inactive and this the first in the list of
|
||||||
|
//promises, we reset our 'minimum duration' and 'maximum duration'
|
||||||
|
//again.
|
||||||
|
if (trackedPromises.length === 1) {
|
||||||
|
if (self._minDuration) {
|
||||||
|
self.minPromise = $timeout(angular.noop, self._minDuration);
|
||||||
|
} else {
|
||||||
|
//No minDuration means we just instantly resolve for our 'wait'
|
||||||
|
//promise.
|
||||||
|
self.minPromise = $q.when(true);
|
||||||
|
}
|
||||||
|
if (self._maxDuration) {
|
||||||
|
self.maxPromise = $timeout(deferred.resolve, self._maxDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create a callback for when this promise is done. It will remove our
|
||||||
|
//tracked promise from the array and call the appropriate event
|
||||||
|
//callbacks depending on whether there was an error or not.
|
||||||
|
function onDone(isError) {
|
||||||
|
return function(value) {
|
||||||
|
//Before resolving our promise, make sure the minDuration timeout
|
||||||
|
//has finished.
|
||||||
|
self.minPromise.then(function() {
|
||||||
|
fireEvent('done', value);
|
||||||
|
fireEvent(isError ? 'error' : 'success', value);
|
||||||
|
var index = trackedPromises.indexOf(deferred);
|
||||||
|
trackedPromises.splice(index, 1);
|
||||||
|
|
||||||
|
//If this is the last promise, cleanup the timeout
|
||||||
|
//for maxDuration so it doesn't stick around.
|
||||||
|
if (trackedPromises.length === 0 && self.maxPromise) {
|
||||||
|
$timeout.cancel(self.maxPromise);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
deferred.promise.then(onDone(false), onDone(true));
|
||||||
|
|
||||||
|
return deferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
//## addPromise()
|
||||||
|
//Adds a given promise to our tracking
|
||||||
|
self.addPromise = function(promise, startArg) {
|
||||||
|
var deferred = createPromise(startArg);
|
||||||
|
|
||||||
|
//When given promise is done, resolve our created promise
|
||||||
|
promise.then(function success(value) {
|
||||||
|
deferred.resolve(value);
|
||||||
|
return value;
|
||||||
|
}, function error(value) {
|
||||||
|
deferred.reject(value);
|
||||||
|
return $q.reject(value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return deferred;
|
||||||
|
};
|
||||||
|
|
||||||
|
//## createPromise()
|
||||||
|
//Create a new promise and return it, and let the user resolve it how
|
||||||
|
//they see fit.
|
||||||
|
self.createPromise = function(startArg) {
|
||||||
|
return createPromise(startArg);
|
||||||
|
};
|
||||||
|
|
||||||
|
//## on(), bind()
|
||||||
|
self.on = self.bind = function(event, cb) {
|
||||||
|
if (!callbacks[event]) {
|
||||||
|
throw "Cannot create callback for event '" + event +
|
||||||
|
"'. Allowed types: 'start', 'done', 'error', 'success'";
|
||||||
|
}
|
||||||
|
callbacks[event].push(cb);
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
self.off = self.unbind = function(event, cb) {
|
||||||
|
if (!callbacks[event]) {
|
||||||
|
throw "Cannot create callback for event '" + event +
|
||||||
|
"'. Allowed types: 'start', 'done', 'error', 'success'";
|
||||||
|
}
|
||||||
|
if (cb) {
|
||||||
|
var index = callbacks[event].indexOf(cb);
|
||||||
|
callbacks[event].splice(index, 1);
|
||||||
|
} else {
|
||||||
|
//Erase all events of this type if no cb specified to remvoe
|
||||||
|
callbacks[event].length = 0;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return function promiseTracker(trackerName, options) {
|
||||||
|
if (!trackers[trackerName]) {
|
||||||
|
trackers[trackerName] = new Tracker(options);
|
||||||
|
}
|
||||||
|
return trackers[trackerName];
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
})
|
||||||
|
;
|
|
@ -0,0 +1,295 @@
|
||||||
|
/* ============================================================
|
||||||
|
* angular-busy.css v3.0.2
|
||||||
|
* https://github.com/cgross/angular-busy
|
||||||
|
* ============================================================
|
||||||
|
* Copyright 2013 Chris Gross
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
* ============================================================ */
|
||||||
|
|
||||||
|
.cg-busy{
|
||||||
|
position:absolute;
|
||||||
|
top:0px;
|
||||||
|
left:0px;
|
||||||
|
right:0px;
|
||||||
|
bottom:0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cg-busy-animation.ng-hide-add,
|
||||||
|
.cg-busy-animation.ng-hide-remove {
|
||||||
|
-webkit-transition:all .3s ease;
|
||||||
|
-moz-transition:all .3s ease;
|
||||||
|
-o-transition:all .3s ease;
|
||||||
|
transition:all .3s ease;
|
||||||
|
display:block !important;
|
||||||
|
}
|
||||||
|
.cg-busy-animation.ng-hide-remove {
|
||||||
|
opacity:0;
|
||||||
|
-webkit-transform:translate(0px,-40px);
|
||||||
|
-moz-transform:translate(0px,-40px);
|
||||||
|
-ms-transform:translate(0px,-40px);
|
||||||
|
-o-transform:translate(0px,-40px);
|
||||||
|
transform:translate(0px,-40px);
|
||||||
|
}
|
||||||
|
.cg-busy-animation.ng-hide-remove.ng-hide-remove-active {
|
||||||
|
opacity:1;
|
||||||
|
-webkit-transform:translate(0px,0px);
|
||||||
|
-moz-transform:translate(0px,0px);
|
||||||
|
-ms-transform:translate(0px,0px);
|
||||||
|
-o-transform:translate(0px,0px);
|
||||||
|
transform:translate(0px,0px);
|
||||||
|
}
|
||||||
|
.cg-busy-animation.ng-hide-add {
|
||||||
|
opacity:1;
|
||||||
|
-webkit-transform:translate(0px,0px);
|
||||||
|
-moz-transform:translate(0px,0px);
|
||||||
|
-ms-transform:translate(0px,0px);
|
||||||
|
-o-transform:translate(0px,0px);
|
||||||
|
transform:translate(0px,0px);
|
||||||
|
}
|
||||||
|
.cg-busy-animation.ng-hide-add.ng-hide-add-active {
|
||||||
|
opacity:0;
|
||||||
|
-webkit-transform:translate(0px,-40px);
|
||||||
|
-moz-transform:translate(0px,-40px);
|
||||||
|
-ms-transform:translate(0px,-40px);
|
||||||
|
-o-transform:translate(0px,-40px);
|
||||||
|
transform:translate(0px,-40px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cg-busy-backdrop {
|
||||||
|
background-color:white;
|
||||||
|
opacity:.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All styles below are for the default template. */
|
||||||
|
|
||||||
|
.cg-busy-default-sign{
|
||||||
|
position:absolute;
|
||||||
|
top:0;
|
||||||
|
left:50%;
|
||||||
|
margin-left:-100px;
|
||||||
|
width:170px;
|
||||||
|
height:50px;
|
||||||
|
color:#333333;
|
||||||
|
text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);
|
||||||
|
background-color:#e9eeee;
|
||||||
|
border:1px solid #dddddd;
|
||||||
|
border-top-width:0;
|
||||||
|
-webkit-border-radius:7px;
|
||||||
|
-moz-border-radius:7px;
|
||||||
|
border-radius:7px;
|
||||||
|
border-top-left-radius:0;
|
||||||
|
border-top-right-radius:0;
|
||||||
|
-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||||
|
-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||||
|
box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
|
||||||
|
}
|
||||||
|
.cg-busy-default-text{
|
||||||
|
position:absolute;
|
||||||
|
left:49px;
|
||||||
|
top:15px;
|
||||||
|
font-size:16px;
|
||||||
|
color:#555;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner{
|
||||||
|
position:absolute;
|
||||||
|
width:25px;
|
||||||
|
height:25px;
|
||||||
|
display:inline-block;
|
||||||
|
top:12px;
|
||||||
|
left:14px;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div{
|
||||||
|
width:12%;
|
||||||
|
height:26%;
|
||||||
|
background:#000;
|
||||||
|
position:absolute;
|
||||||
|
left:44.5%;
|
||||||
|
top:37%;
|
||||||
|
opacity:0;
|
||||||
|
-webkit-animation:cg-busy-spinner-anim 1s linear infinite;
|
||||||
|
-moz-animation:cg-busy-spinner-anim 1s linear infinite;
|
||||||
|
-ms-animation:cg-busy-spinner-anim 1s linear infinite;
|
||||||
|
-o-animation:cg-busy-spinner-anim 1s linear infinite;
|
||||||
|
animation:cg-busy-spinner-anim 1s linear infinite;
|
||||||
|
-webkit-border-radius:50px;
|
||||||
|
-moz-border-radius:50px;
|
||||||
|
border-radius:50px;
|
||||||
|
-webkit-box-shadow:0 0 3px rgba(0,0,0,0.2);
|
||||||
|
-moz-box-shadow:0 0 3px rgba(0,0,0,0.2);
|
||||||
|
box-shadow:0 0 3px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar1{
|
||||||
|
-webkit-transform:rotate(0deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(0deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(0deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(0deg) translate(0, -142%);
|
||||||
|
transform:rotate(0deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:0s;
|
||||||
|
-moz-animation-delay:0s;
|
||||||
|
-ms-animation-delay:0s;
|
||||||
|
-o-animation-delay:0s;
|
||||||
|
animation-delay:0s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar2{
|
||||||
|
-webkit-transform:rotate(30deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(30deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(30deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(30deg) translate(0, -142%);
|
||||||
|
transform:rotate(30deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.9167s;
|
||||||
|
-moz-animation-delay:-0.9167s;
|
||||||
|
-ms-animation-delay:-0.9167s;
|
||||||
|
-o-animation-delay:-0.9167s;
|
||||||
|
animation-delay:-0.9167s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar3{
|
||||||
|
-webkit-transform:rotate(60deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(60deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(60deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(60deg) translate(0, -142%);
|
||||||
|
transform:rotate(60deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.833s;
|
||||||
|
-moz-animation-delay:-0.833s;
|
||||||
|
-ms-animation-delay:-0.833s;
|
||||||
|
-o-animation-delay:-0.833s;
|
||||||
|
animation-delay:-0.833s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar4{
|
||||||
|
-webkit-transform:rotate(90deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(90deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(90deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(90deg) translate(0, -142%);
|
||||||
|
transform:rotate(90deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.75s;
|
||||||
|
-moz-animation-delay:-0.75s;
|
||||||
|
-ms-animation-delay:-0.75s;
|
||||||
|
-o-animation-delay:-0.75s;
|
||||||
|
animation-delay:-0.75s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar5{
|
||||||
|
-webkit-transform:rotate(120deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(120deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(120deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(120deg) translate(0, -142%);
|
||||||
|
transform:rotate(120deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.667s;
|
||||||
|
-moz-animation-delay:-0.667s;
|
||||||
|
-ms-animation-delay:-0.667s;
|
||||||
|
-o-animation-delay:-0.667s;
|
||||||
|
animation-delay:-0.667s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar6{
|
||||||
|
-webkit-transform:rotate(150deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(150deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(150deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(150deg) translate(0, -142%);
|
||||||
|
transform:rotate(150deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.5833s;
|
||||||
|
-moz-animation-delay:-0.5833s;
|
||||||
|
-ms-animation-delay:-0.5833s;
|
||||||
|
-o-animation-delay:-0.5833s;
|
||||||
|
animation-delay:-0.5833s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar7{
|
||||||
|
-webkit-transform:rotate(180deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(180deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(180deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(180deg) translate(0, -142%);
|
||||||
|
transform:rotate(180deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.5s;
|
||||||
|
-moz-animation-delay:-0.5s;
|
||||||
|
-ms-animation-delay:-0.5s;
|
||||||
|
-o-animation-delay:-0.5s;
|
||||||
|
animation-delay:-0.5s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar8{
|
||||||
|
-webkit-transform:rotate(210deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(210deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(210deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(210deg) translate(0, -142%);
|
||||||
|
transform:rotate(210deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.41667s;
|
||||||
|
-moz-animation-delay:-0.41667s;
|
||||||
|
-ms-animation-delay:-0.41667s;
|
||||||
|
-o-animation-delay:-0.41667s;
|
||||||
|
animation-delay:-0.41667s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar9{
|
||||||
|
-webkit-transform:rotate(240deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(240deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(240deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(240deg) translate(0, -142%);
|
||||||
|
transform:rotate(240deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.333s;
|
||||||
|
-moz-animation-delay:-0.333s;
|
||||||
|
-ms-animation-delay:-0.333s;
|
||||||
|
-o-animation-delay:-0.333s;
|
||||||
|
animation-delay:-0.333s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar10{
|
||||||
|
-webkit-transform:rotate(270deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(270deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(270deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(270deg) translate(0, -142%);
|
||||||
|
transform:rotate(270deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.25s;
|
||||||
|
-moz-animation-delay:-0.25s;
|
||||||
|
-ms-animation-delay:-0.25s;
|
||||||
|
-o-animation-delay:-0.25s;
|
||||||
|
animation-delay:-0.25s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar11{
|
||||||
|
-webkit-transform:rotate(300deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(300deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(300deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(300deg) translate(0, -142%);
|
||||||
|
transform:rotate(300deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.1667s;
|
||||||
|
-moz-animation-delay:-0.1667s;
|
||||||
|
-ms-animation-delay:-0.1667s;
|
||||||
|
-o-animation-delay:-0.1667s;
|
||||||
|
animation-delay:-0.1667s;
|
||||||
|
}
|
||||||
|
.cg-busy-default-spinner div.bar12{
|
||||||
|
-webkit-transform:rotate(330deg) translate(0, -142%);
|
||||||
|
-moz-transform:rotate(330deg) translate(0, -142%);
|
||||||
|
-ms-transform:rotate(330deg) translate(0, -142%);
|
||||||
|
-o-transform:rotate(330deg) translate(0, -142%);
|
||||||
|
transform:rotate(330deg) translate(0, -142%);
|
||||||
|
-webkit-animation-delay:-0.0833s;
|
||||||
|
-moz-animation-delay:-0.0833s;
|
||||||
|
-ms-animation-delay:-0.0833s;
|
||||||
|
-o-animation-delay:-0.0833s;
|
||||||
|
animation-delay:-0.0833s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes cg-busy-spinner-anim{
|
||||||
|
from {opacity: 1;}
|
||||||
|
to {opacity: 0.25;}
|
||||||
|
}
|
||||||
|
@-moz-keyframes cg-busy-spinner-anim{
|
||||||
|
from {opacity: 1;}
|
||||||
|
to {opacity: 0.25;}
|
||||||
|
}
|
||||||
|
@keyframes cg-busy-spinner-anim{
|
||||||
|
from {opacity: 1;}
|
||||||
|
to {opacity: 0.25;}
|
||||||
|
}
|
Loading…
Reference in New Issue