GUI -- User Prefs written as a service; persistent topo settings updated a bit; still WIP.
Change-Id: I6945dd9eb4b325a8f1637c44e2c4b271126b2bc4
Showing
6 changed files
with
236 additions
and
68 deletions
web/gui/src/main/webapp/app/fw/util/prefs.js
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/* | ||
18 | + ONOS GUI -- Util -- User Preference Service | ||
19 | + */ | ||
20 | +(function () { | ||
21 | + 'use strict'; | ||
22 | + | ||
23 | + // injected refs | ||
24 | + var $log, $cookies; | ||
25 | + | ||
26 | + // internal state | ||
27 | + var cache = {}; | ||
28 | + | ||
29 | + // NOTE: in Angular 1.3.5, $cookies is just a simple object, and | ||
30 | + // cookie values are just strings. From the 1.3.5 docs: | ||
31 | + // | ||
32 | + // "Only a simple Object is exposed and by adding or removing | ||
33 | + // properties to/from this object, new cookies are created/deleted | ||
34 | + // at the end of current $eval. The object's properties can only | ||
35 | + // be strings." | ||
36 | + // | ||
37 | + // We may want to upgrade the version of Angular sometime soon | ||
38 | + // since later version support objects as cookie values. | ||
39 | + | ||
40 | + // NOTE: prefs represented as simple name/value(number) pairs | ||
41 | + // => a temporary restriction while we are encoding into cookies | ||
42 | + /* | ||
43 | + { | ||
44 | + foo: 1, | ||
45 | + bar: 0, | ||
46 | + goo: 2 | ||
47 | + } | ||
48 | + | ||
49 | + stored as "foo:1,bar:0,goo:2" | ||
50 | + */ | ||
51 | + | ||
52 | + // reads cookie with given name and returns an object rep of its value | ||
53 | + // or null if no such cookie is set | ||
54 | + function getPrefs(name) { | ||
55 | + var cook = $cookies[name], | ||
56 | + bits, | ||
57 | + obj = {}; | ||
58 | + | ||
59 | + if (cook) { | ||
60 | + bits = cook.split(','); | ||
61 | + bits.forEach(function (value) { | ||
62 | + var x = value.split(':'); | ||
63 | + obj[x[0]] = Number(x[1]); | ||
64 | + }); | ||
65 | + | ||
66 | + // update the cache | ||
67 | + cache[name] = obj; | ||
68 | + return obj; | ||
69 | + } | ||
70 | + // perhaps we have a cached copy.. | ||
71 | + return cache[name]; | ||
72 | + } | ||
73 | + | ||
74 | + function setPrefs(name, obj) { | ||
75 | + var bits = [], | ||
76 | + str; | ||
77 | + | ||
78 | + angular.forEach(obj, function (value, key) { | ||
79 | + bits.push(key + ':' + value); | ||
80 | + }); | ||
81 | + str = bits.join(','); | ||
82 | + | ||
83 | + // keep a cached copy of the object | ||
84 | + cache[name] = obj; | ||
85 | + | ||
86 | + // The angular way of doing this... | ||
87 | + // $cookies[name] = str; | ||
88 | + // ...but it appears that this gets delayed, and doesn't 'stick' ?? | ||
89 | + | ||
90 | + // FORCE cookie to be set by writing directly to document.cookie... | ||
91 | + document.cookie = name + '=' + encodeURIComponent(str); | ||
92 | + $log.debug('<<>> Wrote cookie <'+name+'>:', str); | ||
93 | + } | ||
94 | + | ||
95 | + angular.module('onosUtil') | ||
96 | + .factory('PrefsService', ['$log', '$cookies', | ||
97 | + function (_$log_, _$cookies_) { | ||
98 | + $log = _$log_; | ||
99 | + $cookies = _$cookies_; | ||
100 | + | ||
101 | + return { | ||
102 | + getPrefs: getPrefs, | ||
103 | + setPrefs: setPrefs | ||
104 | + }; | ||
105 | + }]); | ||
106 | + | ||
107 | +}()); |
... | @@ -29,7 +29,7 @@ | ... | @@ -29,7 +29,7 @@ |
29 | ]; | 29 | ]; |
30 | 30 | ||
31 | // references to injected services etc. | 31 | // references to injected services etc. |
32 | - var $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, | 32 | + var $log, $cookies, fs, ks, zs, gs, ms, sus, flash, wss, ps, |
33 | tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs; | 33 | tes, tfs, tps, tis, tss, tls, tts, tos, fltr, ttbs; |
34 | 34 | ||
35 | // DOM elements | 35 | // DOM elements |
... | @@ -100,7 +100,7 @@ | ... | @@ -100,7 +100,7 @@ |
100 | function toggleInstances(x) { | 100 | function toggleInstances(x) { |
101 | if (x === 'keyev') { | 101 | if (x === 'keyev') { |
102 | tis.toggle(); | 102 | tis.toggle(); |
103 | - updateCookieState('insts', tis.isVisible()); | 103 | + updatePrefsState('insts', tis.isVisible()); |
104 | } else if (x) { | 104 | } else if (x) { |
105 | tis.show(); | 105 | tis.show(); |
106 | } else { | 106 | } else { |
... | @@ -112,7 +112,7 @@ | ... | @@ -112,7 +112,7 @@ |
112 | function toggleMap(x) { | 112 | function toggleMap(x) { |
113 | var on = (x === 'keyev') ? !sus.visible(mapG) : !!x; | 113 | var on = (x === 'keyev') ? !sus.visible(mapG) : !!x; |
114 | sus.visible(mapG, on); | 114 | sus.visible(mapG, on); |
115 | - updateCookieState('bg', on); | 115 | + updatePrefsState('bg', on); |
116 | } | 116 | } |
117 | 117 | ||
118 | // TODO: need wrapper functions for state changes needed in cookies | 118 | // TODO: need wrapper functions for state changes needed in cookies |
... | @@ -248,22 +248,9 @@ | ... | @@ -248,22 +248,9 @@ |
248 | .attr('opacity', b ? 1 : 0); | 248 | .attr('opacity', b ? 1 : 0); |
249 | } | 249 | } |
250 | 250 | ||
251 | - // --- Config from Cookies ------------------------------------------- | 251 | + // --- User Preferemces ---------------------------------------------- |
252 | 252 | ||
253 | - // TODO: write a general purpose cookie service, rather than custom here | 253 | + var defaultPrefsState = { |
254 | - | ||
255 | - // NOTE: in Angular 1.3.5, $cookies is just a simple object, and | ||
256 | - // cookie values are just strings. From the 1.3.5 docs: | ||
257 | - // | ||
258 | - // "Only a simple Object is exposed and by adding or removing | ||
259 | - // properties to/from this object, new cookies are created/deleted | ||
260 | - // at the end of current $eval. The object's properties can only | ||
261 | - // be strings." | ||
262 | - // | ||
263 | - // We may want to upgrade the version of Angular sometime soon | ||
264 | - // since later version support objects as cookie values. | ||
265 | - | ||
266 | - var defaultCookieState = { | ||
267 | bg: 1, | 254 | bg: 1, |
268 | insts: 1, | 255 | insts: 1, |
269 | summary: 1, | 256 | summary: 1, |
... | @@ -271,54 +258,27 @@ | ... | @@ -271,54 +258,27 @@ |
271 | hosts: 0 | 258 | hosts: 0 |
272 | }; | 259 | }; |
273 | 260 | ||
274 | - var cookieState = {}; | 261 | + var prefsState = {}; |
275 | - | ||
276 | - function writeCookieState() { | ||
277 | - var bits = [], | ||
278 | - str; | ||
279 | - angular.forEach(cookieState, function (value, key) { | ||
280 | - bits.push(key + ':' + value); | ||
281 | - }); | ||
282 | - str = bits.join(','); | ||
283 | - | ||
284 | - // The angular way of doing this... | ||
285 | - // $cookies.topo_state = str; | ||
286 | - // ...but it appears that this gets delayed, and doesn't 'stick' ?? | ||
287 | 262 | ||
288 | - // FORCE cookie to be set by writing directly to document.cookie... | 263 | + function topoDefPrefs() { |
289 | - document.cookie = 'topo_state=' + encodeURIComponent(str); | 264 | + return angular.extend({}, defaultPrefsState); |
290 | - $log.debug('<<>> Wrote cookie:', str); | ||
291 | } | 265 | } |
292 | 266 | ||
293 | - function readCookieState() { | 267 | + function updatePrefsState(what, b) { |
294 | - var cook = $cookies.topo_state || '', | 268 | + prefsState[what] = b ? 1 : 0; |
295 | - bits; | 269 | + ps.setPrefs('topo_prefs', prefsState); |
296 | - | ||
297 | - if (!cook) { | ||
298 | - cookieState = angular.extend({}, defaultCookieState); | ||
299 | - writeCookieState(); // seed the pot | ||
300 | - | ||
301 | - } else { | ||
302 | - bits = cook.split(','); | ||
303 | - bits.forEach(function (value) { | ||
304 | - var x = value.split(':'); | ||
305 | - cookieState[x[0]] = Number(x[1]); | ||
306 | - }); | ||
307 | - } | ||
308 | } | 270 | } |
309 | 271 | ||
310 | - function updateCookieState(what, b) { | ||
311 | - cookieState[what] = b ? 1 : 0; | ||
312 | - writeCookieState(); | ||
313 | - } | ||
314 | 272 | ||
315 | - function restoreConfigFromCookies() { | 273 | + function restoreConfigFromPrefs() { |
316 | - readCookieState(); | 274 | + // NOTE: toolbar will have set this for us.. |
317 | - $log.debug('Cookie State:', cookieState); | 275 | + prefsState = ps.getPrefs('topo_prefs'); |
276 | + | ||
277 | + $log.debug('TOPO---- Prefs State:', prefsState); | ||
318 | 278 | ||
319 | - toggleInstances(cookieState.insts); | 279 | + toggleInstances(prefsState.insts); |
320 | - tps.toggleSummary(cookieState.summary); | 280 | + tps.toggleSummary(prefsState.summary); |
321 | - tps.toggleDetails(cookieState.detail); | 281 | + tps.toggleDetails(prefsState.detail); |
322 | } | 282 | } |
323 | 283 | ||
324 | 284 | ||
... | @@ -328,15 +288,15 @@ | ... | @@ -328,15 +288,15 @@ |
328 | .controller('OvTopoCtrl', ['$scope', '$log', '$location', '$timeout', | 288 | .controller('OvTopoCtrl', ['$scope', '$log', '$location', '$timeout', |
329 | '$cookies', 'FnService', 'MastService', 'KeyService', 'ZoomService', | 289 | '$cookies', 'FnService', 'MastService', 'KeyService', 'ZoomService', |
330 | 'GlyphService', 'MapService', 'SvgUtilService', 'FlashService', | 290 | 'GlyphService', 'MapService', 'SvgUtilService', 'FlashService', |
331 | - 'WebSocketService', | 291 | + 'WebSocketService', 'PrefsService', |
332 | 'TopoEventService', 'TopoForceService', 'TopoPanelService', | 292 | 'TopoEventService', 'TopoForceService', 'TopoPanelService', |
333 | 'TopoInstService', 'TopoSelectService', 'TopoLinkService', | 293 | 'TopoInstService', 'TopoSelectService', 'TopoLinkService', |
334 | 'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService', | 294 | 'TopoTrafficService', 'TopoObliqueService', 'TopoFilterService', |
335 | 'TopoToolbarService', | 295 | 'TopoToolbarService', |
336 | 296 | ||
337 | function ($scope, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_, | 297 | function ($scope, _$log_, $loc, $timeout, _$cookies_, _fs_, mast, _ks_, |
338 | - _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _tes_, _tfs_, _tps_, | 298 | + _zs_, _gs_, _ms_, _sus_, _flash_, _wss_, _ps_, _tes_, _tfs_, |
339 | - _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_) { | 299 | + _tps_, _tis_, _tss_, _tls_, _tts_, _tos_, _fltr_, _ttbs_) { |
340 | var self = this, | 300 | var self = this, |
341 | projection, | 301 | projection, |
342 | dim, | 302 | dim, |
... | @@ -359,6 +319,7 @@ | ... | @@ -359,6 +319,7 @@ |
359 | sus = _sus_; | 319 | sus = _sus_; |
360 | flash = _flash_; | 320 | flash = _flash_; |
361 | wss = _wss_; | 321 | wss = _wss_; |
322 | + ps = _ps_; | ||
362 | tes = _tes_; | 323 | tes = _tes_; |
363 | tfs = _tfs_; | 324 | tfs = _tfs_; |
364 | // TODO: consider funnelling actions through TopoForceService... | 325 | // TODO: consider funnelling actions through TopoForceService... |
... | @@ -403,7 +364,7 @@ | ... | @@ -403,7 +364,7 @@ |
403 | function (proj) { | 364 | function (proj) { |
404 | projection = proj; | 365 | projection = proj; |
405 | $log.debug('** We installed the projection: ', proj); | 366 | $log.debug('** We installed the projection: ', proj); |
406 | - toggleMap(cookieState.bg); | 367 | + toggleMap(prefsState.bg); |
407 | } | 368 | } |
408 | ); | 369 | ); |
409 | 370 | ||
... | @@ -414,7 +375,7 @@ | ... | @@ -414,7 +375,7 @@ |
414 | tes.start(); | 375 | tes.start(); |
415 | 376 | ||
416 | // temporary solution for persisting user settings | 377 | // temporary solution for persisting user settings |
417 | - restoreConfigFromCookies(); | 378 | + restoreConfigFromPrefs(); |
418 | 379 | ||
419 | $log.log('OvTopoCtrl has been created'); | 380 | $log.log('OvTopoCtrl has been created'); |
420 | }]); | 381 | }]); | ... | ... |
... | @@ -23,13 +23,14 @@ | ... | @@ -23,13 +23,14 @@ |
23 | 'use strict'; | 23 | 'use strict'; |
24 | 24 | ||
25 | // injected references | 25 | // injected references |
26 | - var $log, tbs, api; | 26 | + var $log, tbs, ps, api; |
27 | 27 | ||
28 | // internal state | 28 | // internal state |
29 | var toolbar, keyData; | 29 | var toolbar, keyData; |
30 | 30 | ||
31 | // constants | 31 | // constants |
32 | - var name = 'topo-tbar'; | 32 | + var name = 'topo-tbar', |
33 | + cooktag = 'topo_prefs'; | ||
33 | 34 | ||
34 | // key to button mapping data | 35 | // key to button mapping data |
35 | var k2b = { | 36 | var k2b = { |
... | @@ -58,8 +59,46 @@ | ... | @@ -58,8 +59,46 @@ |
58 | E: { id: 'eqMaster-btn', gid: 'eqMaster' } | 59 | E: { id: 'eqMaster-btn', gid: 'eqMaster' } |
59 | }; | 60 | }; |
60 | 61 | ||
62 | + // initial toggle state: default settings and tag to key mapping | ||
63 | + var defaultPrefsState = { | ||
64 | + bg: 1, | ||
65 | + insts: 1, | ||
66 | + summary: 1, | ||
67 | + detail: 1, | ||
68 | + hosts: 0 | ||
69 | + }, | ||
70 | + prefsMap = { | ||
71 | + bg: 'B', | ||
72 | + insts: 'I', | ||
73 | + summary: 'O', | ||
74 | + details: 'D', | ||
75 | + hosts: 'H' | ||
76 | + }; | ||
77 | + | ||
61 | function init(_api_) { | 78 | function init(_api_) { |
62 | api = _api_; | 79 | api = _api_; |
80 | + | ||
81 | + // retrieve initial toggle button settings from user prefs | ||
82 | + setInitToggleState(); | ||
83 | + } | ||
84 | + | ||
85 | + function topoDefPrefs() { | ||
86 | + return angular.extend({}, defaultPrefsState); | ||
87 | + } | ||
88 | + | ||
89 | + function setInitToggleState() { | ||
90 | + var state = ps.getPrefs(cooktag); | ||
91 | + $log.debug('TOOLBAR---- read prefs state:', state); | ||
92 | + | ||
93 | + if (!state) { | ||
94 | + state = topoDefPrefs(); | ||
95 | + ps.setPrefs(cooktag, state); | ||
96 | + $log.debug('TOOLBAR---- Set default prefs state:', state); | ||
97 | + } | ||
98 | + | ||
99 | + angular.forEach(prefsMap, function (v, k) { | ||
100 | + k2b[v].isel = !!state[k]; | ||
101 | + }); | ||
63 | } | 102 | } |
64 | 103 | ||
65 | function initKeyData() { | 104 | function initKeyData() { |
... | @@ -142,11 +181,13 @@ | ... | @@ -142,11 +181,13 @@ |
142 | } | 181 | } |
143 | 182 | ||
144 | angular.module('ovTopo') | 183 | angular.module('ovTopo') |
145 | - .factory('TopoToolbarService', ['$log', 'ToolbarService', | 184 | + .factory('TopoToolbarService', |
185 | + ['$log', 'ToolbarService', 'PrefsService', | ||
146 | 186 | ||
147 | - function (_$log_, _tbs_) { | 187 | + function (_$log_, _tbs_, _ps_) { |
148 | $log = _$log_; | 188 | $log = _$log_; |
149 | tbs = _tbs_; | 189 | tbs = _tbs_; |
190 | + ps = _ps_; | ||
150 | 191 | ||
151 | return { | 192 | return { |
152 | init: init, | 193 | init: init, | ... | ... |
... | @@ -45,6 +45,7 @@ | ... | @@ -45,6 +45,7 @@ |
45 | <script src="app/fw/util/random.js"></script> | 45 | <script src="app/fw/util/random.js"></script> |
46 | <script src="app/fw/util/theme.js"></script> | 46 | <script src="app/fw/util/theme.js"></script> |
47 | <script src="app/fw/util/keys.js"></script> | 47 | <script src="app/fw/util/keys.js"></script> |
48 | + <script src="app/fw/util/prefs.js"></script> | ||
48 | 49 | ||
49 | <script src="app/fw/mast/mast.js"></script> | 50 | <script src="app/fw/mast/mast.js"></script> |
50 | <script src="app/fw/nav/nav.js"></script> | 51 | <script src="app/fw/nav/nav.js"></script> | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 Open Networking Laboratory | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/* | ||
18 | + ONOS GUI -- Util -- User Preference Service - Unit Tests | ||
19 | + */ | ||
20 | +describe('factory: fw/util/prefs.js', function() { | ||
21 | + var $cookies, ps, fs; | ||
22 | + | ||
23 | + beforeEach(module('onosUtil')); | ||
24 | + | ||
25 | + var mockCookies = { | ||
26 | + foo: 'bar' | ||
27 | + }; | ||
28 | + | ||
29 | + beforeEach(function () { | ||
30 | + module(function ($provide) { | ||
31 | + $provide.value('$cookies', mockCookies); | ||
32 | + }); | ||
33 | + }); | ||
34 | + | ||
35 | + beforeEach(inject(function (PrefsService, FnService, _$cookies_) { | ||
36 | + ps = PrefsService; | ||
37 | + fs = FnService; | ||
38 | + $cookies = _$cookies_; | ||
39 | + })); | ||
40 | + | ||
41 | + it('should define PrefsService', function () { | ||
42 | + expect(ps).toBeDefined(); | ||
43 | + }); | ||
44 | + | ||
45 | + it('should define api functions', function () { | ||
46 | + expect(fs.areFunctions(ps, [ | ||
47 | + 'getPrefs', 'setPrefs' | ||
48 | + ])).toBe(true); | ||
49 | + }); | ||
50 | + | ||
51 | + // === Tests for getPrefs() | ||
52 | + // TODO unit tests for getPrefs() | ||
53 | + | ||
54 | + // === Tests for setPrefs() | ||
55 | + // TODO unit tests for setPrefs() | ||
56 | + | ||
57 | +}); |
... | @@ -19,6 +19,7 @@ module.exports = function(config) { | ... | @@ -19,6 +19,7 @@ module.exports = function(config) { |
19 | '../tp/angular.js', | 19 | '../tp/angular.js', |
20 | '../tp/angular-mocks.js', | 20 | '../tp/angular-mocks.js', |
21 | '../tp/angular-route.js', | 21 | '../tp/angular-route.js', |
22 | + '../tp/angular-cookies.js', | ||
22 | '../tp/d3.js', | 23 | '../tp/d3.js', |
23 | '../tp/topojson.v1.min.js', | 24 | '../tp/topojson.v1.min.js', |
24 | 25 | ... | ... |
-
Please register or login to post a comment