summaryrefslogtreecommitdiffstats
path: root/framework/src/onos/web/gui/src/main/webapp/app/fw/util
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/web/gui/src/main/webapp/app/fw/util')
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/fn.js292
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js215
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/prefs.js128
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/random.js51
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/theme.js121
-rw-r--r--framework/src/onos/web/gui/src/main/webapp/app/fw/util/util.js25
6 files changed, 832 insertions, 0 deletions
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/fn.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/fn.js
new file mode 100644
index 00000000..defb8458
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/fn.js
@@ -0,0 +1,292 @@
+/*
+ * 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 -- Util -- General Purpose Functions
+ */
+(function () {
+ 'use strict';
+
+ // injected services
+ var $window, $log;
+
+ // internal state
+ var debugFlags = {};
+
+
+ function _parseDebugFlags(dbgstr) {
+ var bits = dbgstr ? dbgstr.split(",") : [];
+ bits.forEach(function (key) {
+ debugFlags[key] = true;
+ });
+ $log.debug('Debug flags:', dbgstr);
+ }
+
+ function isF(f) {
+ return typeof f === 'function' ? f : null;
+ }
+
+ function isA(a) {
+ // NOTE: Array.isArray() is part of EMCAScript 5.1
+ return Array.isArray(a) ? a : null;
+ }
+
+ function isS(s) {
+ return typeof s === 'string' ? s : null;
+ }
+
+ function isO(o) {
+ return (o && typeof o === 'object' && o.constructor === Object) ? o : null;
+ }
+
+ function contains(a, x) {
+ return isA(a) && a.indexOf(x) > -1;
+ }
+
+ // Returns true if all names in the array are defined as functions
+ // on the given api object; false otherwise.
+ // Also returns false if there are properties on the api that are NOT
+ // listed in the array of names.
+ function areFunctions(api, fnNames) {
+ var fnLookup = {},
+ extraFound = false;
+
+ if (!isA(fnNames)) {
+ return false;
+ }
+ var n = fnNames.length,
+ i, name;
+ for (i=0; i<n; i++) {
+ name = fnNames[i];
+ if (!isF(api[name])) {
+ return false;
+ }
+ fnLookup[name] = true;
+ }
+
+ // check for properties on the API that are not listed in the array,
+ angular.forEach(api, function (value, key) {
+ if (!fnLookup[key]) {
+ extraFound = true;
+ }
+ });
+ return !extraFound;
+ }
+
+ // Returns true if all names in the array are defined as functions
+ // on the given api object; false otherwise. This is a non-strict version
+ // that does not care about other properties on the api.
+ function areFunctionsNonStrict(api, fnNames) {
+ if (!isA(fnNames)) {
+ return false;
+ }
+ var n = fnNames.length,
+ i, name;
+ for (i=0; i<n; i++) {
+ name = fnNames[i];
+ if (!isF(api[name])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Returns width and height of window inner dimensions.
+ // offH, offW : offset width/height are subtracted, if present
+ function windowSize(offH, offW) {
+ var oh = offH || 0,
+ ow = offW || 0;
+ return {
+ height: $window.innerHeight - oh,
+ width: $window.innerWidth - ow
+ };
+ }
+
+ // Returns true if current browser determined to be a mobile device
+ function isMobile() {
+ var ua = $window.navigator.userAgent,
+ patt = /iPhone|iPod|iPad|Silk|Android|BlackBerry|Opera Mini|IEMobile/;
+ return patt.test(ua);
+ }
+
+ // Returns true if the current browser determined to be Chrome
+ function isChrome() {
+ var isChromium = $window.chrome,
+ vendorName = $window.navigator.vendor,
+ isOpera = $window.navigator.userAgent.indexOf("OPR") > -1;
+ return (isChromium !== null &&
+ isChromium !== undefined &&
+ vendorName === "Google Inc." &&
+ isOpera == false);
+ }
+
+ // Returns true if the current browser determined to be Safari
+ function isSafari() {
+ return ($window.navigator.userAgent.indexOf('Safari') !== -1 &&
+ $window.navigator.userAgent.indexOf('Chrome') === -1);
+ }
+
+ // Returns true if the current browser determined to be Firefox
+ function isFirefox() {
+ return typeof InstallTrigger !== 'undefined';
+ }
+
+ // search through an array of objects, looking for the one with the
+ // tagged property matching the given key. tag defaults to 'id'.
+ // returns the index of the matching object, or -1 for no match.
+ function find(key, array, tag) {
+ var _tag = tag || 'id',
+ idx, n, d;
+ for (idx = 0, n = array.length; idx < n; idx++) {
+ d = array[idx];
+ if (d[_tag] === key) {
+ return idx;
+ }
+ }
+ return -1;
+ }
+
+ // search through array to find (the first occurrence of) item,
+ // returning its index if found; otherwise returning -1.
+ function inArray(item, array) {
+ var i;
+ if (isA(array)) {
+ for (i=0; i<array.length; i++) {
+ if (array[i] === item) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ // remove (the first occurrence of) the specified item from the given
+ // array, if any. Return true if the removal was made; false otherwise.
+ function removeFromArray(item, array) {
+ var found = false,
+ i = inArray(item, array);
+ if (i >= 0) {
+ array.splice(i, 1);
+ found = true;
+ }
+ return found;
+ }
+
+ // return true if the object is empty, return false otherwise
+ function isEmptyObject(obj) {
+ var key;
+ for (key in obj) {
+ return false;
+ }
+ return true;
+ }
+
+ // returns true if the two objects have all the same properties
+ function sameObjProps(obj1, obj2) {
+ var key;
+ for (key in obj1) {
+ if (obj1.hasOwnProperty(key)) {
+ if (!(obj1[key] === obj2[key])) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // returns true if the array contains the object
+ // does NOT use strict object reference equality,
+ // instead checks each property individually for equality
+ function containsObj(arr, obj) {
+ var i,
+ len = arr.length;
+ for (i = 0; i < len; i++) {
+ if (sameObjProps(arr[i], obj)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // return the given string with the first character capitalized.
+ function cap(s) {
+ return s.toLowerCase().replace(/^[a-z]/, function (m) {
+ return m.toUpperCase();
+ });
+ }
+
+ // return the parameter without a px suffix
+ function noPx(num) {
+ return Number(num.replace(/px$/, ''));
+ }
+
+ // return an element's given style property without px suffix
+ function noPxStyle(elem, prop) {
+ return Number(elem.style(prop).replace(/px$/, ''));
+ }
+
+ function endsWith(str, suffix) {
+ return str.indexOf(suffix, str.length - suffix.length) !== -1;
+ }
+
+ function parseBitRate(str) {
+ return Number(str.replace(/,/, '')
+ .replace(/\s+.bps/i, '')
+ .replace(/\.\d*/, ''));
+ }
+
+ // return true if the given debug flag was specified in the query params
+ function debugOn(tag) {
+ return debugFlags[tag];
+ }
+
+ angular.module('onosUtil')
+ .factory('FnService',
+ ['$window', '$location', '$log', function (_$window_, $loc, _$log_) {
+ $window = _$window_;
+ $log = _$log_;
+
+ _parseDebugFlags($loc.search().debug);
+
+ return {
+ isF: isF,
+ isA: isA,
+ isS: isS,
+ isO: isO,
+ contains: contains,
+ areFunctions: areFunctions,
+ areFunctionsNonStrict: areFunctionsNonStrict,
+ windowSize: windowSize,
+ isMobile: isMobile,
+ isChrome: isChrome,
+ isSafari: isSafari,
+ isFirefox: isFirefox,
+ debugOn: debugOn,
+ find: find,
+ inArray: inArray,
+ removeFromArray: removeFromArray,
+ isEmptyObject: isEmptyObject,
+ sameObjProps: sameObjProps,
+ containsObj: containsObj,
+ cap: cap,
+ noPx: noPx,
+ noPxStyle: noPxStyle,
+ endsWith: endsWith,
+ parseBitRate: parseBitRate
+ };
+ }]);
+
+}());
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js
new file mode 100644
index 00000000..2985565c
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/keys.js
@@ -0,0 +1,215 @@
+/*
+ * 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 -- Util -- Key Handler Service
+ */
+(function () {
+ 'use strict';
+
+ // references to injected services
+ var $log, fs, ts, ns, qhs;
+
+ // internal state
+ var enabled = true,
+ keyHandler = {
+ globalKeys: {},
+ maskedKeys: {},
+ viewKeys: {},
+ viewFn: null,
+ viewGestures: []
+ };
+
+ function whatKey(code) {
+ switch (code) {
+ case 13: return 'enter';
+ case 16: return 'shift';
+ case 17: return 'ctrl';
+ case 18: return 'alt';
+ case 27: return 'esc';
+ case 32: return 'space';
+ case 37: return 'leftArrow';
+ case 38: return 'upArrow';
+ case 39: return 'rightArrow';
+ case 40: return 'downArrow';
+ case 91: return 'cmdLeft';
+ case 93: return 'cmdRight';
+ case 187: return 'equals';
+ case 188: return 'comma';
+ case 189: return 'dash';
+ case 190: return 'dot';
+ case 191: return 'slash';
+ case 192: return 'backQuote';
+ case 220: return 'backSlash';
+ default:
+ if ((code >= 48 && code <= 57) ||
+ (code >= 65 && code <= 90)) {
+ return String.fromCharCode(code);
+ } else if (code >= 112 && code <= 123) {
+ return 'F' + (code - 111);
+ }
+ return '.';
+ }
+ }
+
+ function keyIn() {
+ var event = d3.event,
+ keyCode = event.keyCode,
+ key = whatKey(keyCode),
+ kh = keyHandler,
+ gk = kh.globalKeys[key],
+ gcb = fs.isF(gk) || (fs.isA(gk) && fs.isF(gk[0])),
+ vk = kh.viewKeys[key],
+ kl = fs.isF(kh.viewKeys._keyListener),
+ vcb = fs.isF(vk) || (fs.isA(vk) && fs.isF(vk[0])) || fs.isF(kh.viewFn),
+ token = 'keyev'; // indicate this was a key-pressed event
+
+ d3.event.stopPropagation();
+
+ if (enabled) {
+ // global callback?
+ if (gcb && gcb(token, key, keyCode, event)) {
+ // if the event was 'handled', we are done
+ return;
+ }
+ // otherwise, let the view callback have a shot
+ if (vcb) {
+ vcb(token, key, keyCode, event);
+ }
+ if (kl) {
+ kl(key);
+ }
+ }
+ }
+
+ function setupGlobalKeys() {
+ angular.extend(keyHandler, {
+ globalKeys: {
+ backSlash: [quickHelp, 'Show / hide Quick Help'],
+ slash: [quickHelp, 'Show / hide Quick Help'],
+ esc: [escapeKey, 'Dismiss dialog or cancel selections'],
+ T: [toggleTheme, "Toggle theme"]
+ },
+ globalFormat: ['backSlash', 'slash', 'esc', 'T'],
+
+ // Masked keys are global key handlers that always return true.
+ // That is, the view will never see the event for that key.
+ maskedKeys: {
+ slash: true,
+ backSlash: true,
+ T: true
+ }
+ });
+ }
+
+ function quickHelp(view, key, code, ev) {
+ qhs.showQuickHelp(keyHandler);
+ return true;
+ }
+
+ // returns true if we 'consumed' the ESC keypress, false otherwise
+ function escapeKey(view, key, code, ev) {
+ return ns.hideIfShown() || qhs.hideQuickHelp();
+ }
+
+ function toggleTheme(view, key, code, ev) {
+ ts.toggleTheme();
+ return true;
+ }
+
+ function setKeyBindings(keyArg) {
+ var viewKeys,
+ masked = [];
+
+ if (fs.isF(keyArg)) {
+ // set general key handler callback
+ keyHandler.viewFn = keyArg;
+ } else {
+ // set specific key filter map
+ viewKeys = d3.map(keyArg).keys();
+ viewKeys.forEach(function (key) {
+ if (keyHandler.maskedKeys[key]) {
+ masked.push('setKeyBindings(): Key "' + key + '" is reserved');
+ }
+ });
+
+ if (masked.length) {
+ $log.warn(masked.join('\n'));
+ }
+ keyHandler.viewKeys = keyArg;
+ }
+ }
+
+ function getKeyBindings() {
+ var gkeys = d3.map(keyHandler.globalKeys).keys(),
+ masked = d3.map(keyHandler.maskedKeys).keys(),
+ vkeys = d3.map(keyHandler.viewKeys).keys(),
+ vfn = !!fs.isF(keyHandler.viewFn);
+
+ return {
+ globalKeys: gkeys,
+ maskedKeys: masked,
+ viewKeys: vkeys,
+ viewFunction: vfn
+ };
+ }
+
+ function unbindKeys() {
+ keyHandler.viewKeys = {};
+ keyHandler.viewFn = null;
+ keyHandler.viewGestures = [];
+ }
+
+ angular.module('onosUtil')
+ .factory('KeyService',
+ ['$log', 'FnService', 'ThemeService', 'NavService',
+
+ function (_$log_, _fs_, _ts_, _ns_) {
+ $log = _$log_;
+ fs = _fs_;
+ ts = _ts_;
+ ns = _ns_;
+
+ return {
+ bindQhs: function (_qhs_) {
+ qhs = _qhs_;
+ },
+ installOn: function (elem) {
+ elem.on('keydown', keyIn);
+ setupGlobalKeys();
+ },
+ keyBindings: function (x) {
+ if (x === undefined) {
+ return getKeyBindings();
+ } else {
+ setKeyBindings(x);
+ }
+ },
+ unbindKeys: unbindKeys,
+ gestureNotes: function (g) {
+ if (g === undefined) {
+ return keyHandler.viewGestures;
+ } else {
+ keyHandler.viewGestures = fs.isA(g) || [];
+ }
+ },
+ enableKeys: function (b) {
+ enabled = b;
+ }
+ };
+ }]);
+
+}());
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/prefs.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/prefs.js
new file mode 100644
index 00000000..02a23909
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/prefs.js
@@ -0,0 +1,128 @@
+/*
+ * 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, fs;
+
+ // 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 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]] = x[1];
+ });
+
+ // update the cache
+ cache[name] = obj;
+ return obj;
+ }
+ // perhaps we have a cached copy..
+ return cache[name];
+ }
+
+ // converts string values to numbers for selected (or all) keys
+ function asNumbers(obj, keys) {
+ if (!obj) return null;
+
+ if (!keys) {
+ // do them all
+ angular.forEach(obj, function (v, k) {
+ obj[k] = Number(obj[k]);
+ });
+ } else {
+ keys.forEach(function (k) {
+ obj[k] = Number(obj[k]);
+ });
+ }
+ return obj;
+ }
+
+ 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);
+ if (fs.debugOn('prefs')) {
+ $log.debug('<<>> Wrote cookie <'+name+'>:', str);
+ }
+ }
+
+ angular.module('onosUtil')
+ .factory('PrefsService', ['$log', '$cookies', 'FnService',
+ function (_$log_, _$cookies_, _fs_) {
+ $log = _$log_;
+ $cookies = _$cookies_;
+ fs = _fs_;
+
+ return {
+ getPrefs: getPrefs,
+ asNumbers: asNumbers,
+ setPrefs: setPrefs
+ };
+ }]);
+
+}());
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/random.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/random.js
new file mode 100644
index 00000000..2298a944
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/random.js
@@ -0,0 +1,51 @@
+/*
+ * 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 -- Random -- Encapsulated randomness
+ */
+(function () {
+ 'use strict';
+
+ var $log, fs;
+
+ var halfRoot2 = 0.7071;
+
+ // given some value, s, returns an integer between -s/2 and s/2
+ // e.g. s = 100; result in the range [-50..50)
+ function spread(s) {
+ return Math.floor((Math.random() * s) - s / 2);
+ }
+
+ // for a given dimension, d, choose a random value somewhere between
+ // 0 and d where the value is within (d / (2 * sqrt(2))) of d/2.
+ function randDim(d) {
+ return d / 2 + spread(d * halfRoot2);
+ }
+
+ angular.module('onosUtil')
+ .factory('RandomService', ['$log', 'FnService',
+
+ function (_$log_, _fs_) {
+ $log = _$log_;
+ fs = _fs_;
+
+ return {
+ spread: spread,
+ randDim: randDim
+ };
+ }]);
+}());
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/theme.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/theme.js
new file mode 100644
index 00000000..0e0ee649
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/theme.js
@@ -0,0 +1,121 @@
+/*
+ * 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 -- Util -- Theme Service
+ */
+(function () {
+ 'use strict';
+
+ var $log, fs;
+
+ var themes = ['light', 'dark'],
+ themeStr = themes.join(' '),
+ thidx,
+ listeners = {},
+ nextListenerId = 1;
+
+ function init() {
+ thidx = 0;
+ updateBodyClass();
+ }
+
+ function getTheme() {
+ return themes[thidx];
+ }
+
+ function setTheme(t) {
+ var idx = themes.indexOf(t);
+ if (idx > -1 && idx !== thidx) {
+ thidx = idx;
+ updateBodyClass();
+ themeEvent('set');
+ }
+ }
+
+ function toggleTheme() {
+ var i = thidx + 1;
+ thidx = (i===themes.length) ? 0 : i;
+ updateBodyClass();
+ themeEvent('toggle');
+ return getTheme();
+ }
+
+ function updateBodyClass() {
+ var body = d3.select('body');
+ body.classed(themeStr, false);
+ body.classed(getTheme(), true);
+ }
+
+ function themeEvent(w) {
+ var t = getTheme(),
+ m = 'Theme-Change-('+w+'): ' + t;
+ $log.debug(m);
+ angular.forEach(listeners, function(value) {
+ value.cb(
+ {
+ 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 removeListener(lsnr) {
+ var id = lsnr && lsnr.id,
+ o = listeners[id];
+ if (o) {
+ delete listeners[id];
+ }
+ }
+
+ angular.module('onosUtil')
+ .factory('ThemeService', ['$log', 'FnService',
+ function (_$log_, _fs_) {
+ $log = _$log_;
+ fs = _fs_;
+ thidx = 0;
+
+ return {
+ init: init,
+ theme: function (x) {
+ if (x === undefined) {
+ return getTheme();
+ } else {
+ setTheme(x);
+ }
+ },
+ toggleTheme: toggleTheme,
+ addListener: addListener,
+ removeListener: removeListener
+ };
+ }]);
+
+}());
diff --git a/framework/src/onos/web/gui/src/main/webapp/app/fw/util/util.js b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/util.js
new file mode 100644
index 00000000..dc3b09c2
--- /dev/null
+++ b/framework/src/onos/web/gui/src/main/webapp/app/fw/util/util.js
@@ -0,0 +1,25 @@
+/*
+ * 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 -- Utilities Module
+ */
+(function () {
+ 'use strict';
+
+ angular.module('onosUtil', []);
+
+}());