Add spin.js-based throbber for all loading

This commit is contained in:
Joseph Schorr 2013-10-01 16:42:20 -04:00
parent ee41f79bcc
commit 76d9cbc14f
8 changed files with 90 additions and 23 deletions

View file

@ -1,3 +1,7 @@
.loading {
padding: 20px;
}
.landing {
position: relative;
width: 100%;

View file

@ -1,3 +1,31 @@
// Register any plugin code.
$.fn.spin = function(opts) {
this.each(function() {
var $this = $(this),
spinner = $this.data('spinner');
if (spinner) spinner.stop();
if (opts !== false) {
options = {
color: $this.css('color') || '#000',
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
speed: 1, // Rounds per second
trail: 100, // Afterglow percentage
shadow: false // Whether to render a shadow
};
opts = $.extend(options, opts);
spinner = new Spinner(opts).spin(this);
$this.data('spinner', spinner);
}
});
return this;
};
// Start the application code itself.
quayApp = angular.module('quay', ['restangular', 'angularMoment'], function($provide) {
$provide.factory('UserService', ['Restangular', function(Restangular) {
var userResponse = {

View file

@ -78,11 +78,6 @@ function HeaderCtrl($scope, UserService) {
}
function RepoListCtrl($scope, Restangular) {
var repositoryFetch = Restangular.all('repository/');
repositoryFetch.getList().then(function(resp) {
$scope.repositories = resp.repositories;
});
$scope.getCommentFirstLine = function(commentString) {
return getMarkedDown(getFirstTextLine(commentString));
};
@ -91,6 +86,16 @@ function RepoListCtrl($scope, Restangular) {
if (!string) { return ''; }
return getMarkedDown(string);
};
$('.spin').spin();
$scope.loading = true;
// Load the list of repositories.
var repositoryFetch = Restangular.all('repository/');
repositoryFetch.getList().then(function(resp) {
$scope.repositories = resp.repositories;
$scope.loading = false;
});
}
function LandingCtrl($scope) {
@ -162,25 +167,31 @@ function RepoCtrl($scope, Restangular, $routeParams, $rootScope) {
var name = $routeParams.name;
var tag = $routeParams.tag || 'latest';
$('.spin').spin();
$scope.loading = true;
var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name);
repositoryFetch.get().then(function(repo) {
$rootScope.title = namespace + '/' + name;
$scope.repo = repo;
$scope.currentTag = repo.tags[tag] || repo.tags['latest'];
var clip = new ZeroClipboard($('#copyClipboard'), { 'moviePath': 'static/lib/ZeroClipboard.swf' });
clip.on('complete', function() {
// Resets the animation.
var elem = $('#clipboardCopied')[0];
elem.style.display = 'none';
var clip = new ZeroClipboard($('#copyClipboard'), { 'moviePath': 'static/lib/ZeroClipboard.swf' });
clip.on('complete', function() {
// Resets the animation.
var elem = $('#clipboardCopied')[0];
elem.style.display = 'none';
// Show the notification.
setTimeout(function() {
elem.style.display = 'block';
}, 1);
});
// Show the notification.
setTimeout(function() {
elem.style.display = 'block';
}, 1);
});
$scope.loading = false;
}, function() {
$scope.repo = null;
$scope.loading = false;
$rootScope.title = 'Unknown Repository';
});
}
@ -189,7 +200,7 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
var namespace = $routeParams.namespace;
var name = $routeParams.name;
$('#userSearch').typeahead({
$('#userSearch').typeahead({
name: 'users',
remote: {
url: '/api/users/%QUERY',
@ -311,11 +322,19 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
$('#cannotchangeModal').modal({});
});
};
$('.spin').spin();
$scope.loading = true;
// Fetch the repository information.
var repositoryFetch = Restangular.one('repository/' + namespace + '/' + name);
repositoryFetch.get().then(function(repo) {
$scope.repo = repo;
$scope.loading = !($scope.permissions && $scope.repo);
}, function() {
$scope.permissions = null;
$rootScope.title = 'Unknown Repository';
$scope.loading = false;
});
// Fetch the permissions.
@ -323,8 +342,10 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
permissionsFetch.get().then(function(resp) {
$rootScope.title = 'Settings - ' + namespace + '/' + name;
$scope.permissions = resp.permissions;
$scope.loading = !($scope.permissions && $scope.repo);
}, function() {
$scope.permissions = null;
$rootScope.title = 'Unknown Repository';
$scope.loading = false;
});
}

1
static/lib/spin.min.js vendored Normal file
View file

@ -0,0 +1 @@
(function(a,b,c){function O(a){H(arguments,function(b,d){a[b]===c&&(a[b]=d)});return a}function N(a){H(arguments,function(b,c){a[m][M(a,b)||b]=c});return a}function M(a,b){var d=a[m],f,g;if(d[b]!==c){return b}b=b.charAt(0).toUpperCase()+b.slice(1);for(g=0;g<E[e];g++){f=E[g]+b;if(d[f]!==c){return f}}}function L(a,b){var c=[j,b,~~(a*100)].join("-"),d="{"+j+":"+a+"}",f;if(!F[c]){for(f=0;f<E[e];f++){try{K.insertRule("@"+(E[f]&&"-"+E[f].toLowerCase()+"-"||"")+"keyframes "+c+"{0%{"+j+":1}"+b+"%"+d+"to"+d+"}",K.cssRules[e])}catch(g){}}F[c]=1}return c}function J(a,b,c){c&&!c[t]&&J(a,c),a.insertBefore(b,c||null);return a}function I(a){var c=b.createElement(a||"div");H(arguments,function(a,b){c[a]=b});return c}function H(a,b){var c=~~((a[e]-1)/2);for(var d=1;d<=c;d++){b(a[d*2-1],a[d*2])}}var d="width",e="length",f="radius",g="lines",h="trail",i="color",j="opacity",k="speed",l="shadow",m="style",n="height",o="left",p="top",q="px",r="childNodes",s="firstChild",t="parentNode",u="position",v="relative",w="absolute",x="animation",y="transform",z="Origin",A="Timeout",B="coord",C="#000",D=m+"Sheets",E="webkit0Moz0ms0O".split(0),F={},G;J(b.getElementsByTagName("head")[0],I(m));var K=b[D][b[D][e]-1],P=function(a){this.opts=O(a||{},g,12,h,100,e,7,d,5,f,10,i,C,j,0.25,k,1)},Q=P.prototype={spin:function(b){var c=this,d=c.el=c[g](c.opts);b&&J(b,N(d,o,~~(b.offsetWidth/2)+q,p,~~(b.offsetHeight/2)+q),b[s]);if(!G){var e=c.opts,f=0,i=20/e[k],l=(1-e[j])/(i*e[h]/100),m=i/e[g];(function n(){f++;for(var b=e[g];b;b--){var h=Math.max(1-(f+b*m)%i*l,e[j]);c[j](d,e[g]-b,h,e)}c[A]=c.el&&a["set"+A](n,50)})()}return c},stop:function(){var b=this,d=b.el;a["clear"+A](b[A]),d&&d[t]&&d[t].removeChild(d),b.el=c;return b}};Q[g]=function(a){function s(b,c){return N(I(),u,w,d,a[e]+a[d]+q,n,a[d]+q,"background",b,"boxShadow",c,y+z,o,y,"rotate("+~~(360/a[g]*m)+"deg) translate("+a[f]+q+",0)","borderRadius","100em")}var b=N(I(),u,v),c=L(a[j],a[h]),m=0,r;for(;m<a[g];m++){r=N(I(),u,w,p,1+~(a[d]/2)+q,y,"translate3d(0,0,0)",x,c+" "+1/a[k]+"s linear infinite "+(1/a[g]/a[k]*m-1/a[k])+"s"),a[l]&&J(r,N(s(C,"0 0 4px "+C),p,2+q)),J(b,J(r,s(a[i],"0 0 1px rgba(0,0,0,.1)")))}return b},Q[j]=function(a,b,c){a[r][b][m][j]=c};var R="behavior",S="url(#default#VML)",T="group0roundrect0fill0stroke".split(0);(function(){var a=N(I(T[0]),R,S),b;if(!M(a,y)&&a.adj){for(b=0;b<T[e];b++){K.addRule(T[b],R+":"+S)}Q[g]=function(){function s(c,e,l){J(k,J(N(h(),"rotation",360/a[g]*c+"deg",o,~~e),J(N(I(T[1],"arcsize",1),d,b,n,a[d],o,a[f],p,-a[d]/2,"filter",l),I(T[2],i,a[i],j,a[j]),I(T[3],j,0))))}function h(){return N(I(T[0],B+"size",c+" "+c,B+z,-b+" "+-b),d,c,n,c)}var a=this.opts,b=a[e]+a[d],c=2*b,k=h(),m=~(a[e]+a[f]+a[d])+q,r;if(a[l]){for(r=1;r<=a[g];r++){s(r,-2,"progid:DXImage"+y+".Microsoft.Blur(pixel"+f+"=2,make"+l+"=1,"+l+j+"=.3)")}}for(r=1;r<=a[g];r++){s(r)}return J(N(I(),"margin",m+" 0 0 "+m,u,v),k)},Q[j]=function(a,b,c,d){d=d[l]&&d[g]||0,a[s][r][b+d][s][s][j]=c}}else{G=M(a,x)}})(),a.Spinner=P})(window,document);

View file

@ -1,8 +1,12 @@
<div class="container" ng-show="!repo || !permissions">
<div class="loading" ng-show="loading">
<div class="spin"></div>
</div>
<div class="container" ng-show="!loading && (!repo || !permissions)">
No repository found
</div>
<div class="container repo repo-admin" ng-show="repo && permissions">
<div class="container repo repo-admin" ng-show="!loading && repo && permissions">
<div class="header">
<a href="{{ '#/repository/' + repo.namespace + '/' + repo.name }}" class="back"><i class="icon-chevron-left"></i></a>
<h3>
@ -14,7 +18,7 @@
<div class="panel panel-default">
<div class="panel-heading">User Access Permissions</div>
<div class="panel-body">
<table class="permissions">
<thead>
<tr>

View file

@ -1,4 +1,8 @@
<div class="container">
<div class="loading" ng-show="loading">
<div class="spin"></div>
</div>
<div class="container" ng-show="!loading">
<h3>Repositories</h3>
<div class="repo-listing" ng-repeat="repository in repositories">
<i class="icon-hdd icon-large"></i>

View file

@ -1,8 +1,12 @@
<div class="container" ng-hide="repo">
<div class="container" ng-show="!loading && !repo">
No repository found
</div>
<div class="container repo" ng-show="repo">
<div class="loading" ng-show="loading">
<div class="spin"></div>
</div>
<div class="container repo" ng-show="!loading && repo">
<!-- Repo Header -->
<div class="header">
<h3>
@ -81,7 +85,7 @@
<div id="image-history" style="display: none">
<div ng-hide="imageHistory">
Loading images...
<div class="spin"></div>
</div>
<div ng-show="imageHistory">

View file

@ -26,6 +26,7 @@
<script src="static/lib/ZeroClipboard.min.js"></script>
<script src="static/lib/typeahead.min.js"></script>
<script src="static/lib/spin.min.js"></script>
<script src="static/js/app.js"></script>
<script src="static/js/controllers.js"></script>