GUI -- User Prefs written as a service; persistent topo settings updated a bit; still WIP.
Change-Id: I6945dd9eb4b325a8f1637c44e2c4b271126b2bc4
diff --git a/web/gui/src/main/webapp/app/fw/util/prefs.js b/web/gui/src/main/webapp/app/fw/util/prefs.js
new file mode 100644
index 0000000..f940ca7
--- /dev/null
+++ b/web/gui/src/main/webapp/app/fw/util/prefs.js
@@ -0,0 +1,107 @@
+/*
+ * 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 -- Util -- User Preference Service
+ */
+(function () {
+ 'use strict';
+
+ // injected refs
+ var $log, $cookies;
+
+ // internal state
+ var cache = {};
+
+ // NOTE: in Angular 1.3.5, $cookies is just a simple object, and
+ // cookie values are just strings. From the 1.3.5 docs:
+ //
+ // "Only a simple Object is exposed and by adding or removing
+ // properties to/from this object, new cookies are created/deleted
+ // at the end of current $eval. The object's properties can only
+ // be strings."
+ //
+ // We may want to upgrade the version of Angular sometime soon
+ // since later version support objects as cookie values.
+
+ // NOTE: prefs represented as simple name/value(number) pairs
+ // => a temporary restriction while we are encoding into cookies
+ /*
+ {
+ foo: 1,
+ bar: 0,
+ goo: 2
+ }
+
+ stored as "foo:1,bar:0,goo:2"
+ */
+
+ // reads cookie with given name and returns an object rep of its value
+ // or null if no such cookie is set
+ function getPrefs(name) {
+ var cook = $cookies[name],
+ bits,
+ obj = {};
+
+ if (cook) {
+ bits = cook.split(',');
+ bits.forEach(function (value) {
+ var x = value.split(':');
+ obj[x[0]] = Number(x[1]);
+ });
+
+ // update the cache
+ cache[name] = obj;
+ return obj;
+ }
+ // perhaps we have a cached copy..
+ return cache[name];
+ }
+
+ function setPrefs(name, obj) {
+ var bits = [],
+ str;
+
+ angular.forEach(obj, function (value, key) {
+ bits.push(key + ':' + value);
+ });
+ str = bits.join(',');
+
+ // keep a cached copy of the object
+ cache[name] = obj;
+
+ // The angular way of doing this...
+ // $cookies[name] = str;
+ // ...but it appears that this gets delayed, and doesn't 'stick' ??
+
+ // FORCE cookie to be set by writing directly to document.cookie...
+ document.cookie = name + '=' + encodeURIComponent(str);
+ $log.debug('<<>> Wrote cookie <'+name+'>:', str);
+ }
+
+ angular.module('onosUtil')
+ .factory('PrefsService', ['$log', '$cookies',
+ function (_$log_, _$cookies_) {
+ $log = _$log_;
+ $cookies = _$cookies_;
+
+ return {
+ getPrefs: getPrefs,
+ setPrefs: setPrefs
+ };
+ }]);
+
+}());
diff --git a/web/gui/src/main/webapp/app/view/topo/topo.js b/web/gui/src/main/webapp/app/view/topo/topo.js
index 5843b56..402ad86 100644
--- a/web/gui/src/main/webapp/app/view/topo/topo.js
+++ b/web/gui/src/main/webapp/app/view/topo/topo.js
@@ -29,7 +29,7 @@
];
// references to injected services etc.
- var $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss,
+ var $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps,
tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs;
// DOM elements
@@ -100,7 +100,7 @@
function toggleInstances(x) {
if (x === 'keyev') {
tis.toggle();
- updateCookieState('insts', tis.isVisible());
+ updatePrefsState('insts', tis.isVisible());
} else if (x) {
tis.show();
} else {
@@ -112,7 +112,7 @@
function toggleMap(x) {
var on = (x === 'keyev') ? !sus.visible(mapG) : !!x;
sus.visible(mapG, on);
- updateCookieState('bg', on);
+ updatePrefsState('bg', on);
}
// TODO: need wrapper functions for state changes needed in cookies
@@ -248,22 +248,9 @@
.attr('opacity', b ? 1 : 0);
}
- // --- Config from Cookies -------------------------------------------
+ // --- User Preferemces ----------------------------------------------
- // TODO: write a general purpose cookie service, rather than custom here
-
- // NOTE: in Angular 1.3.5, $cookies is just a simple object, and
- // cookie values are just strings. From the 1.3.5 docs:
- //
- // "Only a simple Object is exposed and by adding or removing
- // properties to/from this object, new cookies are created/deleted
- // at the end of current $eval. The object's properties can only
- // be strings."
- //
- // We may want to upgrade the version of Angular sometime soon
- // since later version support objects as cookie values.
-
- var defaultCookieState = {
+ var defaultPrefsState = {
bg: 1,
insts: 1,
summary: 1,
@@ -271,54 +258,27 @@
hosts: 0
};
- var cookieState = {};
+ var prefsState = {};
- function writeCookieState() {
- var bits = [],
- str;
- angular.forEach(cookieState, function (value, key) {
- bits.push(key + ':' + value);
- });
- str = bits.join(',');
-
- // The angular way of doing this...
- // $cookies.topo_state = str;
- // ...but it appears that this gets delayed, and doesn't 'stick' ??
-
- // FORCE cookie to be set by writing directly to document.cookie...
- document.cookie = 'topo_state=' + encodeURIComponent(str);
- $log.debug('<<>> Wrote cookie:', str);
+ function topoDefPrefs() {
+ return angular.extend({}, defaultPrefsState);
}
- function readCookieState() {
- var cook = $cookies.topo_state || '',
- bits;
-
- if (!cook) {
- cookieState = angular.extend({}, defaultCookieState);
- writeCookieState(); // seed the pot
-
- } else {
- bits = cook.split(',');
- bits.forEach(function (value) {
- var x = value.split(':');
- cookieState[x[0]] = Number(x[1]);
- });
- }
+ function updatePrefsState(what, b) {
+ prefsState[what] = b ? 1 : 0;
+ ps.setPrefs('topo_prefs', prefsState);
}
- function updateCookieState(what, b) {
- cookieState[what] = b ? 1 : 0;
- writeCookieState();
- }
- function restoreConfigFromCookies() {
- readCookieState();
- $log.debug('Cookie State:', cookieState);
+ function restoreConfigFromPrefs() {
+ // NOTE: toolbar will have set this for us..
+ prefsState = ps.getPrefs('topo_prefs');
- toggleInstances(cookieState.insts);
- tps.toggleSummary(cookieState.summary);
- tps.toggleDetails(cookieState.detail);
+ $log.debug('TOPO---- Prefs State:', prefsState);
+
+ toggleInstances(prefsState.insts);
+ tps.toggleSummary(prefsState.summary);
+ tps.toggleDetails(prefsState.detail);
}
@@ -328,15 +288,15 @@
.controller('OvTopoCtrl', ['$scope', '$log', '$location', '$timeout',
'$cookies', 'FnService', 'MastService', 'KeyService', 'ZoomService',
'GlyphService', 'MapService', 'SvgUtilService', 'FlashService',
- 'WebSocketService',
+ 'WebSocketService', 'PrefsService',
'TopoEventService', 'TopoForceService', 'TopoPanelService',
'TopoInstService', 'TopoSelectService', 'TopoLinkService',
'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService',
'TopoToolbarService',
function ($scope, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_,
- _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _tes_, _tfs_, _tps_,
- _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_) {
+ _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_,
+ _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_) {
var self = this,
projection,
dim,
@@ -359,6 +319,7 @@
sus = _sus_;
flash = _flash_;
wss = _wss_;
+ ps = _ps_;
tes = _tes_;
tfs = _tfs_;
// TODO: consider funnelling actions through TopoForceService...
@@ -403,7 +364,7 @@
function (proj) {
projection = proj;
$log.debug('** We installed the projection: ', proj);
- toggleMap(cookieState.bg);
+ toggleMap(prefsState.bg);
}
);
@@ -414,7 +375,7 @@
tes.start();
// temporary solution for persisting user settings
- restoreConfigFromCookies();
+ restoreConfigFromPrefs();
$log.log('OvTopoCtrl has been created');
}]);
diff --git a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
index eb7c006..8a1895b 100644
--- a/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
+++ b/web/gui/src/main/webapp/app/view/topo/topoToolbar.js
@@ -23,13 +23,14 @@
'use strict';
// injected references
- var $log, tbs, api;
+ var $log, tbs, ps, api;
// internal state
var toolbar, keyData;
// constants
- var name = 'topo-tbar';
+ var name = 'topo-tbar',
+ cooktag = 'topo_prefs';
// key to button mapping data
var k2b = {
@@ -58,8 +59,46 @@
E: { id: 'eqMaster-btn', gid: 'eqMaster' }
};
+ // initial toggle state: default settings and tag to key mapping
+ var defaultPrefsState = {
+ bg: 1,
+ insts: 1,
+ summary: 1,
+ detail: 1,
+ hosts: 0
+ },
+ prefsMap = {
+ bg: 'B',
+ insts: 'I',
+ summary: 'O',
+ details: 'D',
+ hosts: 'H'
+ };
+
function init(_api_) {
api = _api_;
+
+ // retrieve initial toggle button settings from user prefs
+ setInitToggleState();
+ }
+
+ function topoDefPrefs() {
+ return angular.extend({}, defaultPrefsState);
+ }
+
+ function setInitToggleState() {
+ var state = ps.getPrefs(cooktag);
+ $log.debug('TOOLBAR---- read prefs state:', state);
+
+ if (!state) {
+ state = topoDefPrefs();
+ ps.setPrefs(cooktag, state);
+ $log.debug('TOOLBAR---- Set default prefs state:', state);
+ }
+
+ angular.forEach(prefsMap, function (v, k) {
+ k2b[v].isel = !!state[k];
+ });
}
function initKeyData() {
@@ -142,11 +181,13 @@
}
angular.module('ovTopo')
- .factory('TopoToolbarService', ['$log', 'ToolbarService',
+ .factory('TopoToolbarService',
+ ['$log', 'ToolbarService', 'PrefsService',
- function (_$log_, _tbs_) {
+ function (_$log_, _tbs_, _ps_) {
$log = _$log_;
tbs = _tbs_;
+ ps = _ps_;
return {
init: init,
diff --git a/web/gui/src/main/webapp/index.html b/web/gui/src/main/webapp/index.html
index 06e0336..3a335a7 100644
--- a/web/gui/src/main/webapp/index.html
+++ b/web/gui/src/main/webapp/index.html
@@ -45,6 +45,7 @@
<script src="app/fw/util/random.js"></script>
<script src="app/fw/util/theme.js"></script>
<script src="app/fw/util/keys.js"></script>
+ <script src="app/fw/util/prefs.js"></script>
<script src="app/fw/mast/mast.js"></script>
<script src="app/fw/nav/nav.js"></script>
diff --git a/web/gui/src/main/webapp/tests/app/fw/util/prefs-spec.js b/web/gui/src/main/webapp/tests/app/fw/util/prefs-spec.js
new file mode 100644
index 0000000..2b8a15c
--- /dev/null
+++ b/web/gui/src/main/webapp/tests/app/fw/util/prefs-spec.js
@@ -0,0 +1,57 @@
+/*
+ * 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 -- Util -- User Preference Service - Unit Tests
+ */
+describe('factory: fw/util/prefs.js', function() {
+ var $cookies, ps, fs;
+
+ beforeEach(module('onosUtil'));
+
+ var mockCookies = {
+ foo: 'bar'
+ };
+
+ beforeEach(function () {
+ module(function ($provide) {
+ $provide.value('$cookies', mockCookies);
+ });
+ });
+
+ beforeEach(inject(function (PrefsService, FnService, _$cookies_) {
+ ps = PrefsService;
+ fs = FnService;
+ $cookies = _$cookies_;
+ }));
+
+ it('should define PrefsService', function () {
+ expect(ps).toBeDefined();
+ });
+
+ it('should define api functions', function () {
+ expect(fs.areFunctions(ps, [
+ 'getPrefs', 'setPrefs'
+ ])).toBe(true);
+ });
+
+ // === Tests for getPrefs()
+ // TODO unit tests for getPrefs()
+
+ // === Tests for setPrefs()
+ // TODO unit tests for setPrefs()
+
+});
diff --git a/web/gui/src/main/webapp/tests/karma.conf.js b/web/gui/src/main/webapp/tests/karma.conf.js
index afd40ec..bd572c1 100644
--- a/web/gui/src/main/webapp/tests/karma.conf.js
+++ b/web/gui/src/main/webapp/tests/karma.conf.js
@@ -19,6 +19,7 @@
'../tp/angular.js',
'../tp/angular-mocks.js',
'../tp/angular-route.js',
+ '../tp/angular-cookies.js',
'../tp/d3.js',
'../tp/topojson.v1.min.js',