diff options
Diffstat (limited to 'framework/src/onos/web/gui/src/main/webapp/app/fw/util')
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', []); + +}()); |