Simon Hunt

WEB UI -- Simplified listener mechanism in theme.js to match that of prefs.js

 - minor cleanup of app.js

Change-Id: I1a05c5cb43c994937747ef69841d24a863128f4d
......@@ -24,7 +24,8 @@
var $log, fs, wss;
// internal state
var cache = {}, listeners = [];
var cache = {},
listeners = [];
// returns the preference settings for the specified key
function getPrefs(name, defaults, qparams) {
......
......@@ -20,14 +20,18 @@
(function () {
'use strict';
// injected refs
var $log, fs, ps;
// configuration
var themes = ['light', 'dark'],
themeStr = themes.join(' '),
themeStr = themes.join(' ');
// internal state
var listeners = [],
currentTheme,
thidx,
listeners = {},
nextListenerId = 1;
thidx;
function init() {
thidx = ps.getPrefs('theme', { idx: 0 }).idx;
......@@ -73,37 +77,20 @@
function themeEvent(w) {
var t = getTheme(),
m = 'Theme-Change-('+w+'): ' + t;
m = 'Theme-Change-(' + w + '): ' + t;
$log.debug(m);
angular.forEach(listeners, function(value) {
value.cb({
event: 'themeChange',
value: t
}
);
listeners.forEach(function (lsnr) {
lsnr({event: 'themeChange', value: t});
});
}
function addListener(callback) {
var id = nextListenerId++,
cb = fs.isF(callback),
o = { id: id, cb: cb };
if (cb) {
listeners[id] = o;
} else {
$log.error('ThemeService.addListener(): callback not a function');
o.error = 'No callback defined';
}
return o;
function addListener(lsnr) {
listeners.push(lsnr);
}
function removeListener(lsnr) {
var id = lsnr && lsnr.id,
o = listeners[id];
if (o) {
delete listeners[id];
}
listeners = listeners.filter(function(obj) { return obj === lsnr; });
}
angular.module('onosUtil')
......
......@@ -212,7 +212,8 @@
'WebSocketService', 'FnService', 'KeyService', 'PanelService',
'IconService', 'UrlFnService', 'DialogService', 'TableBuilderService',
function (_$log_, _$scope_, $http, $timeout, _wss_, _fs_, _ks_, _ps_, _is_, ufs, ds, tbs) {
function (_$log_, _$scope_, $http, $timeout, _wss_, _fs_, _ks_, _ps_, _is_,
ufs, ds, tbs) {
$log = _$log_;
$scope = _$scope_;
wss = _wss_;
......@@ -333,21 +334,23 @@
$scope.$on('FileChanged', function () {
var formData = new FormData(),
url;
if ($scope.appFile) {
formData.append('file', $scope.appFile);
url = fileUploadUrl + (activateImmediately || '');
url = fileUploadUrl + activateImmediately;
$http.post(ufs.rsUrl(url), formData, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
})
.finally(function () {
activateImmediately = null;
$scope.sortCallback($scope.sortParams);
document.getElementById('inputFileForm').reset();
$timeout(function () { wss.sendEvent(detailsReq); }, 250);
});
.finally(function () {
activateImmediately = '';
$scope.sortCallback($scope.sortParams);
document.getElementById('inputFileForm').reset();
$timeout(function () { wss.sendEvent(detailsReq); }, 250);
});
}
});
......@@ -382,22 +385,22 @@
// binds the model file to the scope in scope.appFile
// sends upload request to the server
.directive('fileModel', ['$parse',
function ($parse) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var model = $parse(attrs.fileModel),
modelSetter = model.assign;
elem.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, elem[0].files[0]);
function ($parse) {
return {
restrict: 'A',
link: function (scope, elem, attrs) {
var model = $parse(attrs.fileModel),
modelSetter = model.assign;
elem.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, elem[0].files[0]);
});
scope.$emit('FileChanged');
});
scope.$emit('FileChanged');
});
}
};
}])
}
};
}])
.directive("filedrop", function ($parse, $document) {
return {
......
......@@ -37,7 +37,7 @@
var ovtopo, svg, defs, zoomLayer, mapG, spriteG, forceG, noDevsLayer;
// Internal state
var zoomer, actionMap, themeListener;
var zoomer, actionMap;
// --- Short Cut Keys ------------------------------------------------
......@@ -433,15 +433,17 @@
return promise;
}
function mapReshader() {
$log.debug('... Re-shading map ...')
ms.reshade(shading());
}
// set up theme listener to re-shade the map when required.
function mapShader(on) {
if (on) {
themeListener = th.addListener(function () {
ms.reshade(shading());
});
th.addListener(mapReshader);
} else {
th.removeListener(themeListener);
themeListener = null;
th.removeListener(mapReshader);
}
}
......
......@@ -1040,6 +1040,11 @@
};
}
function updateLinksAndNodes() {
updateLinks();
updateNodes();
}
angular.module('ovTopo')
.factory('TopoForceService',
['$log', '$timeout', 'FnService', 'SvgUtilService',
......@@ -1067,10 +1072,7 @@
fltr = _fltr_;
tls = _tls_;
var themeListener = ts.addListener(function () {
updateLinks();
updateNodes();
});
ts.addListener(updateLinksAndNodes);
// forceG is the SVG group to display the force layout in
// uplink is the api from the main topo source file
......@@ -1138,8 +1140,7 @@
td3.destroyD3();
tms.destroyModel();
// note: no need to destroy overlay service
ts.removeListener(themeListener);
themeListener = null;
ts.removeListener(updateLinksAndNodes);
// clean up the DOM
svg.selectAll('g').remove();
......
......@@ -43,12 +43,9 @@
var onosInstances,
onosOrder,
oiShowMaster,
oiBox,
themeListener;
oiBox;
// ==========================
function addInstance(data) {
var id = data.id;
......@@ -273,12 +270,11 @@
oiShowMaster = false;
// we want to update the instances, each time the theme changes
themeListener = ts.addListener(updateInstances);
ts.addListener(updateInstances);
}
function destroyInst() {
ts.removeListener(themeListener);
themeListener = null;
ts.removeListener(updateInstances);
ps.destroyPanel(idIns);
oiBox = null;
......
......@@ -97,24 +97,6 @@ describe('factory: fw/util/theme.js', function() {
// === Unit Tests for listeners
it('should report lack of callback', function () {
spyOn($log, 'error');
var list = ts.addListener();
expect($log.error).toHaveBeenCalledWith(
'ThemeService.addListener(): callback not a function'
);
expect(list.error).toEqual('No callback defined');
});
it('should report non-functional callback', function () {
spyOn($log, 'error');
var list = ts.addListener(['some array']);
expect($log.error).toHaveBeenCalledWith(
'ThemeService.addListener(): callback not a function'
);
expect(list.error).toEqual('No callback defined');
});
it('should invoke our callback with an event', function () {
var event;
......@@ -132,26 +114,30 @@ describe('factory: fw/util/theme.js', function() {
});
it('should invoke our callback at appropriate times', function () {
var cb = jasmine.createSpy('cb');
var listener;
expect(cb.calls.count()).toEqual(0);
ts.toggleTheme(); // -> dark
expect(cb.calls.count()).toEqual(0);
ts.addListener(cb);
expect(cb.calls.count()).toEqual(0);
listener = ts.addListener(cb);
ts.toggleTheme(); // -> light
expect(cb.calls.count()).toEqual(1);
ts.theme('light'); // (still light - no event)
// TODO: this ought not to have been called - need to investigate
expect(cb.calls.count()).toEqual(2);
ts.theme('dark'); // -> dark
expect(cb.calls.count()).toEqual(3);
ts.removeListener(listener);
ts.toggleTheme(); // -> light
ts.removeListener(cb);
expect(cb.calls.count()).toEqual(3);
ts.toggleTheme(); // -> light
expect(cb.calls.count()).toEqual(4);
});
});
......