'use strict' ;
// Google Analytics
var googleAnalyticsService = analytics . getService ( 'ice_cream_app' ) ;
var googleAnalytics = googleAnalyticsService . getTracker ( atob ( "VUEtNTI4MjA5MjAtMQ==" ) ) ;
var googleAnalyticsConfig = false ;
googleAnalyticsService . getConfig ( ) . addCallback ( function ( config ) {
googleAnalyticsConfig = config ;
} ) ;
$ ( document ) . ready ( function ( ) {
// translate to user-selected language
localize ( ) ;
// alternative - window.navigator.appVersion.match(/Chrome\/([0-9.]*)/)[1];
GUI . log ( 'Running - OS: <strong>' + GUI . operating _system + '</strong>, ' +
'Chrome: <strong>' + window . navigator . appVersion . replace ( /.*Chrome\/([0-9.]*).*/ , "$1" ) + '</strong>, ' +
'Configurator: <strong>' + chrome . runtime . getManifest ( ) . version + '</strong>' ) ;
$ ( '#status-bar .version' ) . text ( chrome . runtime . getManifest ( ) . version ) ;
// notification messages for various operating systems
switch ( GUI . operating _system ) {
case 'Windows' :
break ;
case 'MacOS' :
// var main_chromium_version = window.navigator.appVersion.replace(/.*Chrome\/([0-9.]*).*/,"$1").split('.')[0];
break ;
case 'ChromeOS' :
break ;
case 'Linux' :
break ;
case 'UNIX' :
break ;
}
// check release time to inform people in case they are running old release
if ( CONFIGURATOR . releaseDate > ( new Date ( ) . getTime ( ) - ( 86400000 * 60 ) ) ) { // 1 day = 86400000 miliseconds, * 60 = 2 month window
console . log ( 'Application version is valid for another: ' + Math . round ( ( CONFIGURATOR . releaseDate - ( new Date ( ) . getTime ( ) - ( 86400000 * 60 ) ) ) / 86400000 ) + ' days' ) ;
} else {
console . log ( 'Application version expired' ) ;
GUI . log ( 'You\'re using an old version of ' + chrome . runtime . getManifest ( ) . name + '. Please update so you can benefit from recently added features and bugfixes.' ) ;
}
// log webgl capability
// it would seem the webgl "enabling" through advanced settings will be ignored in the future
// and webgl will be supported if gpu supports it by default (canary 40.0.2175.0), keep an eye on this one
var canvas = document . createElement ( 'canvas' ) ;
if ( window . WebGLRenderingContext && ( canvas . getContext ( 'webgl' ) || canvas . getContext ( 'experimental-webgl' ) ) ) {
googleAnalytics . sendEvent ( 'Capability' , 'WebGL' , 'true' ) ;
} else {
googleAnalytics . sendEvent ( 'Capability' , 'WebGL' , 'false' ) ;
}
// log library versions in console to make version tracking easier
console . log ( 'Libraries: jQuery - ' + $ . fn . jquery + ', d3 - ' + d3 . version + ', three.js - ' + THREE . REVISION ) ;
// Tabs
var ui _tabs = $ ( '#tabs > ul' ) ;
$ ( 'a' , ui _tabs ) . click ( function ( ) {
if ( $ ( this ) . parent ( ) . hasClass ( 'active' ) == false && ! GUI . tab _switch _in _progress ) { // only initialize when the tab isn't already active
var self = this ,
tab = $ ( self ) . parent ( ) . prop ( 'class' ) ;
// if there is no active connection, return
if ( ! CONFIGURATOR . connectionValid ) {
GUI . log ( 'You need to <strong>connect</strong> before you can view any of the tabs' ) ;
return ;
}
GUI . tab _switch _in _progress = true ;
GUI . tab _switch _cleanup ( function ( ) {
// disable previously active tab highlight
$ ( 'li' , ui _tabs ) . removeClass ( 'active' ) ;
// Highlight selected tab
$ ( self ) . parent ( ) . addClass ( 'active' ) ;
// detach listeners and remove element data
var content = $ ( '#content' ) ;
content . empty ( ) ;
// display loading screen
$ ( '#cache .data-loading' ) . clone ( ) . appendTo ( content ) ;
function content _ready ( ) {
GUI . tab _switch _in _progress = false ;
}
switch ( tab ) {
case 'tab_auxiliary' :
TABS . auxiliary . initialize ( content _ready ) ;
break ;
case 'tab_adjustments' :
TABS . adjustments . initialize ( content _ready ) ;
break ;
case 'tab_setup' :
TABS . setup . initialize ( content _ready ) ;
break ;
case 'tab_configuration' :
TABS . configuration . initialize ( content _ready ) ;
break ;
case 'tab_pid_tuning' :
TABS . pid _tuning . initialize ( content _ready ) ;
break ;
case 'tab_receiver' :
TABS . receiver . initialize ( content _ready ) ;
break ;
case 'tab_modes' :
TABS . modes . initialize ( content _ready ) ;
break ;
case 'tab_servos' :
TABS . servos . initialize ( content _ready ) ;
break ;
case 'tab_gps' :
TABS . gps . initialize ( content _ready ) ;
break ;
case 'tab_motors' :
TABS . motors . initialize ( content _ready ) ;
break ;
case 'tab_sensors' :
TABS . sensors . initialize ( content _ready ) ;
break ;
case 'tab_logging' :
TABS . logging . initialize ( content _ready ) ;
break ;
case 'tab_cli' :
TABS . cli . initialize ( content _ready ) ;
break ;
default :
console . log ( 'Tab not found' ) ;
}
} ) ;
}
} ) ;
TABS . landing . initialize ( ) ;
// options
$ ( 'a#options' ) . click ( function ( ) {
var el = $ ( this ) ;
if ( ! el . hasClass ( 'active' ) ) {
el . addClass ( 'active' ) ;
el . after ( '<div id="options-window"></div>' ) ;
$ ( 'div#options-window' ) . load ( './tabs/options.html' , function ( ) {
googleAnalytics . sendAppView ( 'Options' ) ;
// translate to user-selected language
localize ( ) ;
// if notifications are enabled, or wasn't set, check the notifications checkbox
chrome . storage . local . get ( 'update_notify' , function ( result ) {
if ( typeof result . update _notify === 'undefined' || result . update _notify ) {
$ ( 'div.notifications input' ) . prop ( 'checked' , true ) ;
}
} ) ;
$ ( 'div.notifications input' ) . change ( function ( ) {
var check = $ ( this ) . is ( ':checked' ) ;
googleAnalytics . sendEvent ( 'Settings' , 'Notifications' , check ) ;
chrome . storage . local . set ( { 'update_notify' : check } ) ;
} ) ;
// if tracking is enabled, check the statistics checkbox
if ( googleAnalyticsConfig . isTrackingPermitted ( ) ) {
$ ( 'div.statistics input' ) . prop ( 'checked' , true ) ;
}
$ ( 'div.statistics input' ) . change ( function ( ) {
var check = $ ( this ) . is ( ':checked' ) ;
googleAnalytics . sendEvent ( 'Settings' , 'GoogleAnalytics' , check ) ;
googleAnalyticsConfig . setTrackingPermitted ( check ) ;
} ) ;
function close _and _cleanup ( e ) {
if ( e . type == 'click' && ! $ . contains ( $ ( 'div#options-window' ) [ 0 ] , e . target ) || e . type == 'keyup' && e . keyCode == 27 ) {
$ ( document ) . unbind ( 'click keyup' , close _and _cleanup ) ;
$ ( 'div#options-window' ) . slideUp ( 250 , function ( ) {
el . removeClass ( 'active' ) ;
$ ( this ) . empty ( ) . remove ( ) ;
} ) ;
}
}
$ ( document ) . bind ( 'click keyup' , close _and _cleanup ) ;
$ ( this ) . slideDown ( 250 ) ;
} ) ;
}
} ) ;
// listen to all input change events and adjust the value within limits if necessary
$ ( "#content" ) . on ( 'focus' , 'input[type="number"]' , function ( ) {
var element = $ ( this ) ,
val = element . val ( ) ;
if ( ! isNaN ( val ) ) {
element . data ( 'previousValue' , parseFloat ( val ) ) ;
}
} ) ;
$ ( "#content" ) . on ( 'keydown' , 'input[type="number"]' , function ( e ) {
// whitelist all that we need for numeric control
var whitelist = [
96 , 97 , 98 , 99 , 100 , 101 , 102 , 103 , 104 , 105 , 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 , 56 , 57 , // numpad and standard number keypad
109 , 189 , // minus on numpad and in standard keyboard
8 , 46 , 9 , // backspace, delete, tab
190 , 110 , // decimal point
37 , 38 , 39 , 40 , 13 // arrows and enter
] ;
if ( whitelist . indexOf ( e . keyCode ) == - 1 ) {
e . preventDefault ( ) ;
}
} ) ;
$ ( "#content" ) . on ( 'change' , 'input[type="number"]' , function ( ) {
var element = $ ( this ) ,
min = parseFloat ( element . prop ( 'min' ) ) ,
max = parseFloat ( element . prop ( 'max' ) ) ,
step = parseFloat ( element . prop ( 'step' ) ) ,
val = parseFloat ( element . val ( ) ) ,
decimal _places ;
// only adjust minimal end if bound is set
if ( element . prop ( 'min' ) ) {
if ( val < min ) {
element . val ( min ) ;
val = min ;
}
}
// only adjust maximal end if bound is set
if ( element . prop ( 'max' ) ) {
if ( val > max ) {
element . val ( max ) ;
val = max ;
}
}
// if entered value is illegal use previous value instead
if ( isNaN ( val ) ) {
element . val ( element . data ( 'previousValue' ) ) ;
val = element . data ( 'previousValue' ) ;
}
// if step is not set or step is int and value is float use previous value instead
if ( isNaN ( step ) || step % 1 === 0 ) {
if ( val % 1 !== 0 ) {
element . val ( element . data ( 'previousValue' ) ) ;
val = element . data ( 'previousValue' ) ;
}
}
// if step is set and is float and value is int, convert to float, keep decimal places in float according to step *experimental*
if ( ! isNaN ( step ) && step % 1 !== 0 ) {
decimal _places = String ( step ) . split ( '.' ) [ 1 ] . length ;
if ( val % 1 === 0 ) {
element . val ( val . toFixed ( decimal _places ) ) ;
} else if ( String ( val ) . split ( '.' ) [ 1 ] . length != decimal _places ) {
element . val ( val . toFixed ( decimal _places ) ) ;
}
}
} ) ;
} ) ;
function catch _startup _time ( startTime ) {
var endTime = new Date ( ) . getTime ( ) ,
timeSpent = endTime - startTime ;
googleAnalytics . sendTiming ( 'Load Times' , 'Application Startup' , timeSpent ) ;
}
function microtime ( ) {
var now = new Date ( ) . getTime ( ) / 1000 ;
return now ;
}
function millitime ( ) {
var now = new Date ( ) . getTime ( ) ;
return now ;
}
function bytesToSize ( bytes ) {
if ( bytes < 1024 ) {
bytes = bytes + ' Bytes' ;
} else if ( bytes < 1048576 ) {
bytes = ( bytes / 1024 ) . toFixed ( 3 ) + ' KB' ;
} else if ( bytes < 1073741824 ) {
bytes = ( bytes / 1048576 ) . toFixed ( 3 ) + ' MB' ;
} else {
bytes = ( bytes / 1073741824 ) . toFixed ( 3 ) + ' GB' ;
}
return bytes ;
}
Number . prototype . clamp = function ( min , max ) {
return Math . min ( Math . max ( this , min ) , max ) ;
} ;
/ * *
* String formatting now supports currying ( partial application ) .
* For a format string with N replacement indices , you can call . format
* with M <= N arguments . The result is going to be a format string
* with N - M replacement indices , properly counting from 0 . . N - M .
* The following Example should explain the usage of partial applied format :
* "{0}:{1}:{2}" . format ( "a" , "b" , "c" ) === "{0}:{1}:{2}" . format ( "a" , "b" ) . format ( "c" )
* "{0}:{1}:{2}" . format ( "a" ) . format ( "b" ) . format ( "c" ) === "{0}:{1}:{2}" . format ( "a" ) . format ( "b" , "c" )
* * /
String . prototype . format = function ( ) {
var args = arguments ;
return this . replace ( /\{(\d+)\}/g , function ( t , i ) {
return args [ i ] !== void 0 ? args [ i ] : "{" + ( i - args . length ) + "}" ;
} ) ;
} ;