From 86d7c4db5d2c00acb50799cd5da722bc1cc4a2b1 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Tue, 18 Jun 2013 18:01:22 -0900 Subject: [PATCH] Add spinner for loading times --- index.html | 1 + js/controllers.js | 34 +++-- js/services.js | 15 +- lib/spin.js | 349 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 381 insertions(+), 18 deletions(-) create mode 100644 lib/spin.js diff --git a/index.html b/index.html index 6f8537ccb..6945c1bf9 100644 --- a/index.html +++ b/index.html @@ -51,6 +51,7 @@ + diff --git a/js/controllers.js b/js/controllers.js index 63fc8d319..335597cf5 100644 --- a/js/controllers.js +++ b/js/controllers.js @@ -4,7 +4,6 @@ function MastheadController($scope) { } function DashboardController($scope, Container) { - } function StatusBarController($scope, Settings) { @@ -20,7 +19,7 @@ function SideBarController($scope, Container, Settings) { $scope.endpoint = Settings.endpoint; Container.query({all: 0}, function(d) { - $scope.containers = d; + $scope.containers = d; }); } @@ -46,11 +45,11 @@ function SettingsController($scope, Auth, System, Docker, Settings) { }, function(e) { console.log(e); setFailedResponse($scope, e.data, '#response'); - }); - }; + }); + }; Auth.get({}, function(d) { - $scope.auth = d; + $scope.auth = d; }); Docker.get({}, function(d) { @@ -117,34 +116,36 @@ function ContainerController($scope, $routeParams, $location, Container) { $scope.getChanges = function() { Container.changes({id: $routeParams.id}, function(d) { - $scope.changes = d; + $scope.changes = d; }); }; Container.get({id: $routeParams.id}, function(d) { - $scope.container = d; + $scope.container = d; }, function(e) { console.log(e); setFailedResponse($scope, e.data, '#response'); if (e.status === 404) { $('.detail').hide(); } - }); + }); $scope.getChanges(); } // Controller for the list of containers -function ContainersController($scope, Container, Settings) { +function ContainersController($scope, Container, Settings, ViewSpinner) { $scope.displayAll = Settings.displayAll; $scope.predicate = '-Created'; var update = function(data) { + ViewSpinner.spin(); Container.query(data, function(d) { - $scope.containers = d; - }); + $scope.containers = d; + ViewSpinner.stop(); + }); }; - + $scope.toggleGetAll = function() { Settings.displayAll = $scope.displayAll; var u = update; @@ -156,11 +157,11 @@ function ContainersController($scope, Container, Settings) { u(data); }; - update({all: $scope.displayAll ? 1 : 0}); + update({all: $scope.displayAll ? 1 : 0}); } // Controller for the list of images -function ImagesController($scope, Image) { +function ImagesController($scope, Image, ViewSpinner) { $scope.predicate = '-Created'; $('#response').hide(); $scope.alertClass = 'block'; @@ -169,11 +170,14 @@ function ImagesController($scope, Image) { $('#build-modal').modal('show'); }; + ViewSpinner.spin(); Image.query({}, function(d) { $scope.images = d; + ViewSpinner.stop(); }, function (e) { console.log(e); setFailedResponse($scope, e.data, '#response'); + ViewSpinner.stop(); }); } @@ -285,7 +289,7 @@ function BuilderController($scope, Dockerfile) { $scope.build = function() { Dockerfile.build(editor.getValue(), function(e) { - console.log(e); + console.log(e); }); }; } diff --git a/js/services.js b/js/services.js index d14af9e78..cddac3f98 100644 --- a/js/services.js +++ b/js/services.js @@ -62,14 +62,23 @@ angular.module('dockerui.services', ['ngResource']) displayAll: false, endpoint: DOCKER_ENDPOINT, version: DOCKER_API_VERSION, - rawUrl: DOCKER_ENDPOINT + '/' + DOCKER_API_VERSION, + rawUrl: DOCKER_ENDPOINT + DOCKER_PORT + '/' + DOCKER_API_VERSION, uiVersion: UI_VERSION, url: url }; }) + .factory('ViewSpinner', function() { + var spinner = new Spinner(); + var target = document.getElementById('view'); + + return { + spin: function() { spinner.spin(target); }, + stop: function() { spinner.stop(); } + }; + }) .factory('Dockerfile', function(Settings) { + var url = Settings.rawUrl + '/build'; return { - settings: Settings, build: function(file, callback) { var data = new FormData(); var dockerfile = new Blob([file], { type: 'text/text' }); @@ -77,7 +86,7 @@ angular.module('dockerui.services', ['ngResource']) var request = new XMLHttpRequest(); request.onload = callback; - request.open('POST', 'http://192.168.1.9:4243/v1.1/build'); + request.open('POST', url); request.send(data); } }; diff --git a/lib/spin.js b/lib/spin.js new file mode 100644 index 000000000..c66c607a7 --- /dev/null +++ b/lib/spin.js @@ -0,0 +1,349 @@ +//fgnass.github.com/spin.js#v1.3 + +/** + * Copyright (c) 2011-2013 Felix Gnass + * Licensed under the MIT license + */ +(function(root, factory) { + + /* CommonJS */ + if (typeof exports == 'object') module.exports = factory() + + /* AMD module */ + else if (typeof define == 'function' && define.amd) define(factory) + + /* Browser global */ + else root.Spinner = factory() +} +(this, function() { + "use strict"; + + var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */ + , animations = {} /* Animation rules keyed by their name */ + , useCssAnimations /* Whether to use CSS animations or setTimeout */ + + /** + * Utility function to create elements. If no tag name is given, + * a DIV is created. Optionally properties can be passed. + */ + function createEl(tag, prop) { + var el = document.createElement(tag || 'div') + , n + + for(n in prop) el[n] = prop[n] + return el + } + + /** + * Appends children and returns the parent. + */ + function ins(parent /* child1, child2, ...*/) { + for (var i=1, n=arguments.length; i> 1) : parseInt(o.left, 10) + mid) + 'px', + top: (o.top == 'auto' ? tp.y-ep.y + (target.offsetHeight >> 1) : parseInt(o.top, 10) + mid) + 'px' + }) + } + + el.setAttribute('role', 'progressbar') + self.lines(el, self.opts) + + if (!useCssAnimations) { + // No CSS animation support, use setTimeout() instead + var i = 0 + , start = (o.lines - 1) * (1 - o.direction) / 2 + , alpha + , fps = o.fps + , f = fps/o.speed + , ostep = (1-o.opacity) / (f*o.trail / 100) + , astep = f/o.lines + + ;(function anim() { + i++; + for (var j = 0; j < o.lines; j++) { + alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity) + + self.opacity(el, j * o.direction + start, alpha, o) + } + self.timeout = self.el && setTimeout(anim, ~~(1000/fps)) + })() + } + return self + }, + + /** + * Stops and removes the Spinner. + */ + stop: function() { + var el = this.el + if (el) { + clearTimeout(this.timeout) + if (el.parentNode) el.parentNode.removeChild(el) + this.el = undefined + } + return this + }, + + /** + * Internal method that draws the individual lines. Will be overwritten + * in VML fallback mode below. + */ + lines: function(el, o) { + var i = 0 + , start = (o.lines - 1) * (1 - o.direction) / 2 + , seg + + function fill(color, shadow) { + return css(createEl(), { + position: 'absolute', + width: (o.length+o.width) + 'px', + height: o.width + 'px', + background: color, + boxShadow: shadow, + transformOrigin: 'left', + transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)', + borderRadius: (o.corners * o.width>>1) + 'px' + }) + } + + for (; i < o.lines; i++) { + seg = css(createEl(), { + position: 'absolute', + top: 1+~(o.width/2) + 'px', + transform: o.hwaccel ? 'translate3d(0,0,0)' : '', + opacity: o.opacity, + animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1/o.speed + 's linear infinite' + }) + + if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'})) + + ins(el, ins(seg, fill(o.color, '0 0 1px rgba(0,0,0,.1)'))) + } + return el + }, + + /** + * Internal method that adjusts the opacity of a single line. + * Will be overwritten in VML fallback mode below. + */ + opacity: function(el, i, val) { + if (i < el.childNodes.length) el.childNodes[i].style.opacity = val + } + + }) + + + function initVML() { + + /* Utility function to create a VML tag */ + function vml(tag, attr) { + return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr) + } + + // No CSS transforms but VML support, add a CSS rule for VML elements: + sheet.addRule('.spin-vml', 'behavior:url(#default#VML)') + + Spinner.prototype.lines = function(el, o) { + var r = o.length+o.width + , s = 2*r + + function grp() { + return css( + vml('group', { + coordsize: s + ' ' + s, + coordorigin: -r + ' ' + -r + }), + { width: s, height: s } + ) + } + + var margin = -(o.width+o.length)*2 + 'px' + , g = css(grp(), {position: 'absolute', top: margin, left: margin}) + , i + + function seg(i, dx, filter) { + ins(g, + ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}), + ins(css(vml('roundrect', {arcsize: o.corners}), { + width: r, + height: o.width, + left: o.radius, + top: -o.width>>1, + filter: filter + }), + vml('fill', {color: o.color, opacity: o.opacity}), + vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change + ) + ) + ) + } + + if (o.shadow) + for (i = 1; i <= o.lines; i++) + seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)') + + for (i = 1; i <= o.lines; i++) seg(i) + return ins(el, g) + } + + Spinner.prototype.opacity = function(el, i, val, o) { + var c = el.firstChild + o = o.shadow && o.lines || 0 + if (c && i+o < c.childNodes.length) { + c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild + if (c) c.opacity = val + } + } + } + + var probe = css(createEl('group'), {behavior: 'url(#default#VML)'}) + + if (!vendor(probe, 'transform') && probe.adj) initVML() + else useCssAnimations = vendor(probe, 'animation') + + return Spinner + +}));