Simon Hunt

GUI -- Implemented the flash service.

Change-Id: I4fb03f4c8df687ab499921d1bf2b8cb424ec306e
/*
* Copyright 2014,2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Flash Service -- CSS file
*/
#flash {
z-index: 1400;
}
#flash svg {
position: absolute;
bottom: 0;
opacity: 0.8;
}
.light #flash svg g.flashItem rect {
fill: #ccc;
}
.dark #flash svg g.flashItem rect {
fill: #555;
}
#flash svg g.flashItem text {
stroke: none;
text-anchor: middle;
alignment-baseline: middle;
font-size: 16pt;
}
.light #flash svg g.flashItem text {
fill: #333;
}
.dark #flash svg g.flashItem text {
fill: #999;
}
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Layer -- Flash Service
Provides a mechanism to flash short informational messages to the screen
to alert the user of something, e.g. "Hosts visible" or "Hosts hidden".
*/
(function () {
'use strict';
// injected references
var $log, $timeout;
// configuration
var defaultSettings = {
fade: 200,
showFor: 1200
},
w = '100%',
h = 200,
xpad = 20,
ypad = 10,
rx = 10,
vbox = '-200 -' + (h/2) + ' 400 ' + h;
// internal state
var settings,
timer = null,
data = [];
// DOM elements
var flashDiv, svg;
function computeBox(el) {
var text = el.select('text'),
box = text.node().getBBox();
// center
box.x = -box.width / 2;
box.y = -box.height / 2;
// add some padding
box.x -= xpad;
box.width += xpad * 2;
box.y -= ypad;
box.height += ypad * 2;
return box;
}
function updateFlash() {
if (!svg) {
svg = flashDiv.append('svg').attr({
width: w,
height: h,
viewBox: vbox
});
}
var items = svg.selectAll('.flashItem')
.data(data);
// this is when there is an existing item
items.each(function (msg) {
var el = d3.select(this),
box;
el.select('text').text(msg);
box = computeBox(el);
el.select('rect').attr(box);
});
// this is when there is no existing item
var entering = items.enter()
.append('g')
.attr({
class: 'flashItem',
opacity: 0
})
.transition()
.duration(settings.fade)
.attr('opacity', 1);
entering.each(function (msg) {
var el = d3.select(this),
box;
el.append('rect').attr('rx', rx);
el.append('text').text(msg);
box = computeBox(el);
el.select('rect').attr(box);
});
items.exit()
.transition()
.duration(settings.fade)
.attr('opacity', 0)
.remove();
if (svg && data.length === 0) {
svg.transition()
.delay(settings.fade + 10)
.remove();
svg = null;
}
}
function flash(msg) {
if (timer) {
$timeout.cancel(timer);
}
timer = $timeout(function () {
data = [];
updateFlash();
}, settings.showFor);
data = [msg];
updateFlash();
}
angular.module('onosLayer')
.factory('FlashService', ['$log', '$timeout',
function (_$log_, _$timeout_) {
$log = _$log_;
$timeout = _$timeout_;
function initFlash(opts) {
settings = angular.extend({}, defaultSettings, opts);
flashDiv = d3.select('#flash');
}
return {
initFlash: initFlash,
flash: flash
};
}]);
}());
......@@ -60,6 +60,7 @@
<script src="fw/layer/layer.js"></script>
<script src="fw/layer/panel.js"></script>
<script src="fw/layer/flash.js"></script>
<!-- Framework and library stylesheets included here -->
<!-- TODO: use a single catenated-minified file here -->
......@@ -69,6 +70,7 @@
<link rel="stylesheet" href="fw/svg/glyph.css">
<link rel="stylesheet" href="fw/svg/icon.css">
<link rel="stylesheet" href="fw/layer/panel.css">
<link rel="stylesheet" href="fw/layer/flash.css">
<link rel="stylesheet" href="fw/nav/nav.css">
<!-- This is where contributed javascript will get injected -->
......
......@@ -65,8 +65,9 @@
.controller('OnosCtrl', [
'$log', '$route', '$routeParams', '$location',
'KeyService', 'ThemeService', 'GlyphService', 'PanelService',
'FlashService',
function ($log, $route, $routeParams, $location, ks, ts, gs, ps) {
function ($log, $route, $routeParams, $location, ks, ts, gs, ps, flash) {
var self = this;
self.$route = $route;
......@@ -79,6 +80,7 @@
ks.installOn(d3.select('body'));
gs.init();
ps.init();
flash.initFlash();
$log.log('OnosCtrl has been created');
......
/*
* Copyright 2015 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
ONOS GUI -- Layer -- Flash Service - Unit Tests
*/
describe('factory: fw/layer/flash.js', function () {
var $log, $timeout, fs, flash, d3Elem;
beforeEach(module('onosLayer'));
beforeEach(inject(function (_$log_, _$timeout_, FnService, FlashService) {
$log = _$log_;
$timeout = _$timeout_;
fs = FnService;
flash = FlashService;
d3Elem = d3.select('body').append('div').attr('id', 'myflashdiv');
flash.initFlash();
}));
afterEach(function () {
d3.select('#myflashdiv').remove();
});
function flashItemSelection() {
return d3Elem.selectAll('.flashItem');
}
it('should define FlashService', function () {
expect(flash).toBeDefined();
});
it('should define api functions', function () {
expect(fs.areFunctions(flash, [
'initFlash', 'flash'
])).toBeTruthy();
});
it('should have no items to start', function () {
expect(flashItemSelection().size()).toBe(0);
});
it('should flash the message Foo', function () {
var item, rect, text;
flash.flash('foo');
setTimeout(function () {
item = flashItemSelection();
expect(item.size()).toEqual(1);
expect(item.classed('flashItem')).toBeTruthy();
expect(item.select('rect').size()).toEqual(1);
text = item.select('text');
expect(text.size()).toEqual(1);
expect(text.text()).toEqual('foo');
}, 500);
});
// TODO: testing these time-sensitive behaviors is hard...
// need to work on this some other time.
});