1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-14 11:59:51 +03:00
inav-configurator/main.js
Dominic Clifton d269d60391 Improve user experience by adding tabs for the welcome and firmware
flasher.

The welcome (aka 'landing') and firmware flasher were already modelled
as tabs but were never displayed as tabs.

The UI didn't make sense when the whether the welcome message or
firmware flasher was displayed since there was no active tab or other
indication.
2015-01-25 17:37:47 +01:00

351 lines
13 KiB
JavaScript
Executable file

'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 are using an old version of ' + chrome.runtime.getManifest().name + '. There may be a more recent version with improvements and fixes.');
}
// 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');
var tabRequiresConnection = $(self).parent().hasClass('mode-connected');
if (tabRequiresConnection && !CONFIGURATOR.connectionValid) {
GUI.log(chrome.i18n.getMessage('tabSwitchConnectionRequired'));
return;
}
if (GUI.connect_lock) { // tab switching disabled while operation is in progress
GUI.log(chrome.i18n.getMessage('tabSwitchWaitForOperation'));
return;
}
if (CONFIGURATOR.connectionValidCliOnly) {
GUI.log(chrome.i18n.getMessage('tabSwitchUpgradeRequired'));
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_landing':
TABS.landing.initialize(content_ready);
break;
case 'tab_firmware_flasher':
TABS.firmware_flasher.initialize(content_ready);
break;
case 'tab_auxiliary':
TABS.auxiliary.initialize(content_ready);
break;
case 'tab_adjustments':
TABS.adjustments.initialize(content_ready);
break;
case 'tab_ports':
TABS.ports.initialize(content_ready);
break;
case 'tab_led_strip':
TABS.led_strip.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 ul.mode-disconnected li a:first').click();
// 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)+"}";
});
};