Cordova framework integration, Android support, mobile UI & options tab

Cordova integration and android platform :
- Added cordova directory with required config
- Added cordova applications generation in gulpfile
- Added cordova development instructions
- Used cordova plugins to simulate missing chrome api  plugins (chrome.serial and chrome.fileSystem)
- Added cordova clipboard support
- Added android operating system and Cordova gui mode
- Fixed some css and js files to make them working on Android as well as on computers
- Added --skipdep argument to accelerate cordova build (gulp task)
- Added a webview helper to help people to update the webview app of their device

New options tab :
- Added options tab replacing the options dropdown
- Added option to switch between phones UI and computers UI

Mobile interface and global interface improvements :
- Simplified the structure of the header with flex css
- Made headerbar and tab container responsive (compact headerbar and side menu)
- All tabs are adapted to mobile interface (except firmware flasher)
- The servos and adjustments tabs are not fully adapted but are "usable"
- Improved header bar animation
- Improved log expandation animation
- Added swipe gesture to toggle side menu

Fixes during the development :
- Logo position
- Dark mode
- Auto connection
- Error messages (cordova_chromeapi.js)
- Responsive grid
- Testing
- Disconnection
- Width of boxes inside the OSD tab
- Fixed cli tab
- OSD tab
- Motor stop switch
- White spaces in boxes
- Dialogs size
- Connect button state
- Prevent tablet with a height larger than 575px to switch to computers ui
- Fixed logging tab
- Fixed code smell
- Fixed yarn cordova plugin install issue
- Fixed content_wrapper
- Fixed vibrations when scrolling
- Fixed scrolling bar alignment
- Fixed dialogReportProblem height
- Fixed rates logo
- Fixed auto connection default value (true)
- Fixed D to D max
- Fixed dialogs

Added required messages in locales/en/messages.json file

Requested changes
10.8-maintenance
WalcoFPV 2020-07-03 16:18:55 +02:00
parent ea880840a8
commit 4f93e54ae6
99 changed files with 9095 additions and 3015 deletions

7
.gitignore vendored
View File

@ -13,6 +13,13 @@ debug/
release/
testresults/
# Cordova
cordova/www/
cordova/platforms/
cordova/plugins/
cordova/resources/
cordova/package-lock.json
# OSX
.DS_store

View File

@ -48,14 +48,15 @@ Unstable testing versions of the lates builds of the configurator for most platf
**Be aware that these versions are intended for testing / feedback only, and may be buggy or broken, and can cause flight controller settings to be corrupted. Caution is advised when using these versions.**
## Native app build via NW.js
## Native app build via NW.js (windows/linux/macos) or Cordova (android)
### Development
1. Install node.js (version 10 required)
2. Install yarn: `npm install yarn -g`
3. Change to project folder and run `yarn install`.
4. Run `yarn start`.
3. (For Android platform only) Install Java JDK 8, Gradle and Android Studio (Android SDK at least level 19)
4. Change to project folder and run `yarn install`.
5. Run `yarn start`.
### Running tests
@ -69,12 +70,14 @@ yarn gulp <taskname> [[platform] [platform] ...]
```
List of possible values of `<task-name>`:
* **dist** copies all the JS and CSS files in the `./dist` folder.
* **dist** copies all the JS and CSS files in the `./dist` folder [2].
* **apps** builds the apps in the `./apps` folder [1].
* **debug** builds debug version of the apps in the `./debug` folder [1].
* **debug** builds debug version of the apps in the `./debug` folder [1][3].
* **release** zips up the apps into individual archives in the `./release` folder [1].
[1] Running this task on macOS or Linux requires Wine, since it's needed to set the icon for the Windows app (build for specific platform to avoid errors).
[2] For Android platform, **dist** task will generate the `./cordova` folder
[3] For Android platform, you need to configure an emulator or to plug an Android device with USB debugging enabled
#### Build or release app for one specific platform
To build or release only for one specific platform you can append the plaform after the `task-name`.
@ -84,6 +87,7 @@ If no platform is provided, all the platforms will be done in sequence.
* **Linux** use `yarn gulp <task-name> --linux64`
* **Windows** use `yarn gulp <task-name> --win32`
* **ChromeOS** use `yarn gulp <task-name> --chromeos`
* **Android** use `yarn gulp <task-name> --android`
You can also use multiple platforms e.g. `yarn gulp <taskname> --osx64 --linux64`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 296 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

10
cordova/build.json Normal file
View File

@ -0,0 +1,10 @@
{
"android": {
"release": {
"keystore": "release.keystore",
"storePassword": "betaflight",
"alias": "betaflight",
"password" : "betaflight"
}
}
}

52
cordova/config.xml Normal file
View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0" xmlns:android="http://schemas.android.com/apk/res/android" id="com.betaflight.betaflightconfigurator" version="[INJECTED_BY_GULPFILE]">
<name>[INJECTED_BY_GULPFILE]</name>
<description>[INJECTED_BY_GULPFILE]</description>
<author href="https://betaflight.com">[INJECTED_BY_GULPFILE]</author>
<content src="main_cordova.html"/>
<access origin="*"/>
<allow-intent href="http://*/*"/>
<allow-intent href="https://*/*"/>
<allow-intent href="tel:*"/>
<allow-intent href="sms:*"/>
<allow-intent href="mailto:*"/>
<allow-intent href="geo:*"/>
<preference name="Orientation" value="default"/>
<preference name="ShowSplashScreenSpinner" value="false"/>
<preference name="AutoHideSplashScreen" value="false"/>
<platform name="android">
<allow-intent href="market:*"/>
<icon src="resources/android/icon/drawable-ldpi-icon.png" density="ldpi"/>
<icon src="resources/android/icon/drawable-mdpi-icon.png" density="mdpi"/>
<icon src="resources/android/icon/drawable-hdpi-icon.png" density="hdpi"/>
<icon src="resources/android/icon/drawable-xhdpi-icon.png" density="xhdpi"/>
<icon src="resources/android/icon/drawable-xxhdpi-icon.png" density="xxhdpi"/>
<icon src="resources/android/icon/drawable-xxxhdpi-icon.png" density="xxxhdpi"/>
<splash src="resources/android/splash/drawable-land-hdpi-screen.png" density="land-hdpi"/>
<splash src="resources/android/splash/drawable-land-ldpi-screen.png" density="land-ldpi"/>
<splash src="resources/android/splash/drawable-land-mdpi-screen.png" density="land-mdpi"/>
<splash src="resources/android/splash/drawable-land-xhdpi-screen.png" density="land-xhdpi"/>
<splash src="resources/android/splash/drawable-land-xxhdpi-screen.png" density="land-xxhdpi"/>
<splash src="resources/android/splash/drawable-land-xxxhdpi-screen.png" density="land-xxxhdpi"/>
<splash src="resources/android/splash/drawable-port-hdpi-screen.png" density="port-hdpi"/>
<splash src="resources/android/splash/drawable-port-ldpi-screen.png" density="port-ldpi"/>
<splash src="resources/android/splash/drawable-port-mdpi-screen.png" density="port-mdpi"/>
<splash src="resources/android/splash/drawable-port-xhdpi-screen.png" density="port-xhdpi"/>
<splash src="resources/android/splash/drawable-port-xxhdpi-screen.png" density="port-xxhdpi"/>
<splash src="resources/android/splash/drawable-port-xxxhdpi-screen.png" density="port-xxxhdpi"/>
<preference name="SplashMaintainAspectRatio" value="true"/>
<preference name="SplashShowOnlyFirstTime" value="true"/>
<preference name="android-minSdkVersion" value="19"/>
<config-file parent="/manifest/application/activity" target="AndroidManifest.xml">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"/>
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" android:resource="@xml/usb_device_filter"/>
</config-file>
<resource-file src="usb_device_filter.xml" target="app/src/main/res/xml/usb_device_filter.xml"/>
</platform>
<platform name="ios">
<allow-intent href="itms:*"/>
<allow-intent href="itms-apps:*"/>
</platform>
</widget>

54
cordova/package.json Normal file
View File

@ -0,0 +1,54 @@
{
"name": "[INJECTED_BY_GULPFILE]",
"displayName": "Betaflight Configurator",
"version": "[INJECTED_BY_GULPFILE]",
"description": "[INJECTED_BY_GULPFILE]",
"main": "index.js",
"scripts": {},
"author": "[INJECTED_BY_GULPFILE]",
"license": "[INJECTED_BY_GULPFILE]",
"dependencies": {
"cordova": "^9.0.0",
"cordova-android": "^8.1.0",
"cordova-clipboard": "^1.3.0",
"bf-cordova-open-native-settings": "^2.0.4",
"bf-cordova-plugin-appavailability": "^1.0.3",
"cordova-plugin-chrome-apps-common": "^1.0.7",
"cordova-plugin-chrome-apps-runtime": "^2.0.0",
"cordova-plugin-chrome-apps-storage": "^1.0.4",
"bf-cordova-plugin-chrome-apps-usb": "^2.0.1",
"cordova-plugin-dialogs": "^2.0.2",
"cordova-plugin-file": "^6.0.2",
"cordova-plugin-filechooser": "^1.2.0",
"cordova-plugin-market": "^1.2.0",
"cordova-plugin-permission": "^0.1.0",
"cordova-plugin-splashscreen": "^5.0.3",
"cordova-plugin-usb-event": "^1.0.2",
"cordova-plugin-whitelist": "^1.3.4",
"bf-cordovarduino": "^1.0.0"
},
"cordova": {
"platforms": [
"android"
],
"plugins": {
"cordova-plugin-chrome-apps-common": {},
"cordova-plugin-chrome-apps-runtime": {},
"cordova-plugin-chrome-apps-storage": {},
"cordova-plugin-whitelist": {},
"cordova-plugin-splashscreen": {},
"cordova-plugin-permission": {},
"cordova-plugin-usb-event": {},
"cordova-plugin-dialogs": {},
"bf-cordovarduino": {},
"cordova-plugin-file": {},
"cordova-plugin-filechooser": {},
"bf-cordova-plugin-chrome-apps-usb": {},
"cordova-clipboard": {},
"cordova-plugin-screen-orientation": {},
"cordova-plugin-market": {},
"bf-cordova-open-native-settings": {},
"bf-cordova-plugin-appavailability": {}
}
}
}

BIN
cordova/release.keystore Normal file

Binary file not shown.

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<usb-device vendor-id="1155" product-id="22336" /> <!--STMicroelectronics / Virtual COM Port -->
</resources>

2989
cordova/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,15 +23,21 @@ const gulp = require('gulp');
const concat = require('gulp-concat');
const yarn = require("gulp-yarn");
const rename = require('gulp-rename');
const replace = require('gulp-replace');
const jeditor = require("gulp-json-editor");
const xmlTransformer = require("gulp-xml-transformer");
const os = require('os');
const git = require('gulp-git');
const source = require('vinyl-source-stream');
const stream = require('stream');
const cordova = require("cordova-lib").cordova;
const DIST_DIR = './dist/';
const APPS_DIR = './apps/';
const DEBUG_DIR = './debug/';
const RELEASE_DIR = './release/';
const CORDOVA_DIR = './cordova/';
const LINUX_INSTALL_DIR = '/opt/betaflight';
@ -49,6 +55,8 @@ var nwBuilderOptions = {
var nwArmVersion = '0.27.6';
let cordovaDependencies = true;
//-----------------
//Pre tasks operations
//-----------------
@ -70,16 +78,18 @@ gulp.task('clean-release', clean_release);
gulp.task('clean-cache', clean_cache);
gulp.task('clean-cordova', cordova_clean);
// Function definitions are processed before function calls.
const getChangesetId = gulp.series(getHash, writeChangesetId);
gulp.task('get-changeset-id', getChangesetId);
// dist_yarn MUST be done after dist_src
const distBuild = gulp.series(dist_src, dist_changelog, dist_yarn, dist_locale, dist_libraries, dist_resources, getChangesetId);
const distBuild = gulp.series(dist_src, dist_changelog, dist_yarn, dist_locale, dist_libraries, dist_resources, getChangesetId, gulp.series(cordova_dist()));
const distRebuild = gulp.series(clean_dist, distBuild);
gulp.task('dist', distRebuild);
const appsBuild = gulp.series(gulp.parallel(clean_apps, distRebuild), apps, gulp.parallel(listPostBuildTasks(APPS_DIR)));
const appsBuild = gulp.series(gulp.parallel(clean_apps, distRebuild), apps, gulp.series(cordova_apps()), gulp.parallel(listPostBuildTasks(APPS_DIR)));
gulp.task('apps', appsBuild);
const debugAppsBuild = gulp.series(gulp.parallel(clean_debug, distRebuild), debug, gulp.parallel(listPostBuildTasks(DEBUG_DIR)));
@ -101,10 +111,10 @@ gulp.task('default', debugBuild);
// Get platform from commandline args
// #
// # gulp <task> [<platform>]+ Run only for platform(s) (with <platform> one of --linux64, --linux32, --armv7, --osx64, --win32, --win64, or --chromeos)
// # gulp <task> [<platform>]+ Run only for platform(s) (with <platform> one of --linux64, --linux32, --armv7, --osx64, --win32, --win64, --chromeos or --android)
// #
function getInputPlatforms() {
var supportedPlatforms = ['linux64', 'linux32', 'armv7', 'osx64', 'win32','win64', 'chromeos'];
const supportedPlatforms = ['linux64', 'linux32', 'armv7', 'osx64', 'win32','win64', 'chromeos', 'android'];
var platforms = [];
var regEx = /--(\w+)/;
console.log(process.argv);
@ -112,9 +122,12 @@ function getInputPlatforms() {
var arg = process.argv[i].match(regEx)[1];
if (supportedPlatforms.indexOf(arg) > -1) {
platforms.push(arg);
} else if (arg == 'nowinicon') {
console.log('ignoring winIco')
} else if (arg === 'nowinicon') {
console.log('ignoring winIco');
delete nwBuilderOptions['winIco'];
} else if (arg === 'skipdep') {
console.log('ignoring cordova dependencies');
cordovaDependencies = false;
} else {
console.log('Unknown platform: ' + arg);
process.exit();
@ -282,6 +295,7 @@ function dist_resources() {
function apps(done) {
var platforms = getPlatforms();
removeItem(platforms, 'chromeos');
removeItem(platforms, 'android');
buildNWAppsWrapper(platforms, 'normal', APPS_DIR, done);
}
@ -341,6 +355,7 @@ function post_build(arch, folder, done) {
function debug(done) {
var platforms = getPlatforms();
removeItem(platforms, 'chromeos');
removeItem(platforms, 'android');
buildNWAppsWrapper(platforms, 'sdk', DEBUG_DIR, done);
}
@ -498,9 +513,13 @@ function start_debug(done) {
var exec = require('child_process').exec;
if (platforms.length === 1) {
var run = getRunDebugAppCommand(platforms[0]);
console.log('Starting debug app (' + run + ')...');
exec(run);
if (platforms[0] === 'android') {
cordova_debug();
} else {
var run = getRunDebugAppCommand(platforms[0]);
console.log('Starting debug app (' + run + ')...');
exec(run);
}
} else {
console.log('More than one platform specified, not starting debug app');
}
@ -762,5 +781,136 @@ function listReleaseTasks(appDirectory) {
});
}
if (platforms.indexOf('android') !== -1) {
releaseTasks.push(function release_android() {
return cordova_release();
});
}
return releaseTasks;
}
// Cordova
function cordova_dist() {
const distTasks = [];
const platforms = getPlatforms();
if (platforms.indexOf('android') !== -1) {
distTasks.push(cordova_clean);
distTasks.push(cordova_copy_www);
distTasks.push(cordova_locales_www);
distTasks.push(cordova_resources);
distTasks.push(cordova_include_www);
distTasks.push(cordova_packagejson);
distTasks.push(cordova_configxml);
distTasks.push(cordova_depedencies);
if (cordovaDependencies) {
distTasks.push(cordova_platforms);
}
} else {
distTasks.push(function cordova_dist_none(done) {
done();
});
}
return distTasks;
}
function cordova_apps() {
const appsTasks = [];
const platforms = getPlatforms();
if (platforms.indexOf('android') !== -1) {
appsTasks.push(cordova_build);
} else {
appsTasks.push(function cordova_dist_none(done) {
done();
});
}
return appsTasks;
}
function cordova_clean() {
const patterns = ['./cordova/www/**', './cordova/resources/**'];
if (cordovaDependencies) {
patterns.push('./cordova/plugins/**');
patterns.push('./cordova/platforms/**');
}
return del(patterns, { force: true });
}
function cordova_copy_www() {
return gulp.src(`${DIST_DIR}**`, { base: DIST_DIR })
.pipe(gulp.dest(`${CORDOVA_DIR}www/`));
}
function cordova_locales_www(cb) {
fs.renameSync(`${CORDOVA_DIR}www/_locales`, `${CORDOVA_DIR}www/i18n`);
gulp.src(`${CORDOVA_DIR}www/js/localization.js`)
.pipe(replace('/_locales', './i18n'))
.pipe(gulp.dest(`${CORDOVA_DIR}www/js`));
cb();
}
function cordova_resources() {
return gulp.src('assets/android/**')
.pipe(gulp.dest(`${CORDOVA_DIR}resources/android/`));
}
function cordova_include_www() {
return gulp.src(`${CORDOVA_DIR}www/main.html`)
.pipe(replace('<!-- CORDOVA_INCLUDE js/cordova_chromeapi.js -->', '<script type="text/javascript" src="./js/cordova_chromeapi.js"></script>'))
.pipe(replace('<!-- CORDOVA_INCLUDE js/cordova_startup.js -->', '<script type="text/javascript" src="./js/cordova_startup.js"></script>'))
.pipe(replace('<!-- CORDOVA_INCLUDE cordova.js -->', '<script type="text/javascript" src="cordova.js"></script>'))
.pipe(gulp.dest(`${CORDOVA_DIR}www`));
}
function cordova_packagejson() {
return gulp.src(`${CORDOVA_DIR}package.json`)
.pipe(jeditor({
'name': pkg.name,
'description': pkg.description,
'version': pkg.version,
'author': pkg.author,
'license': pkg.license,
}))
.pipe(gulp.dest(CORDOVA_DIR));
}
function cordova_configxml() {
return gulp.src([`${CORDOVA_DIR}config.xml`])
.pipe(xmlTransformer([
{ path: '//xmlns:name', text: pkg.productName },
{ path: '//xmlns:description', text: pkg.description },
{ path: '//xmlns:author', text: pkg.author },
], 'http://www.w3.org/ns/widgets'))
.pipe(xmlTransformer([
{ path: '.', attr: { 'version': pkg.version } },
]))
.pipe(gulp.dest(CORDOVA_DIR));
}
function cordova_depedencies() {
process.chdir('cordova');
return gulp.src(['./package.json', './yarn.lock'])
.pipe(gulp.dest('./'))
.pipe(yarn({
production: true,
}));
}
function cordova_platforms() {
return cordova.platform('add', ['android']);
}
function cordova_debug() {
cordova.run();
}
function cordova_build(cb) {
cordova.build({
'platforms': ['android'],
'options': {
release: true,
buildConfig: 'build.json',
},
}).then(function() {
process.chdir('../');
cb();
});
console.log('APK will be generated at cordova/platforms/android/app/build/outputs/apk/release/app-release.apk');
}
async function cordova_release() {
const filename = await getReleaseFilename('android', 'apk');
console.log(`Release APK : release/${filename}`);
return gulp.src(`${CORDOVA_DIR}platforms/android/app/build/outputs/apk/release/app-release.apk`)
.pipe(rename(filename))
.pipe(gulp.dest(RELEASE_DIR));
}

View File

@ -92,6 +92,9 @@
"analyticsOptOut": {
"message": "Opt out of the anonymised collection of statistics data"
},
"cordovaForceComputerUI": {
"message": "Use computers interface instead of phones interface"
},
"language_changed": {
"message": "Language change saved"
},
@ -298,6 +301,9 @@
"tabHelp": {
"message": "Documentation & Support"
},
"tabOptions": {
"message": "Options"
},
"tabSetup": {
"message": "Setup"
@ -5746,5 +5752,68 @@
"gpsSbasNone": {
"message": "None",
"description": "One of the options selectable for the GPS SBAS system"
},
"dialogFileNameTitle": {
"message": "File name"
},
"dialogFileNameDescription": {
"message": "The file will be saved in the '{{folder}}' folder in your internal storage."
},
"dialogFileAlreadyExistsTitle": {
"message": "This file already exists!"
},
"dialogFileAlreadyExistsDescription": {
"message": "Overwrite ?"
},
"cordovaCheckingWebview": {
"message": "Checking webview applications ..."
},
"cordovaIncompatibleWebview": {
"message": "Incompatible webview"
},
"cordovaWebviewTroubleshootingMsg": {
"message": "You must update your device's webview in order to use the configurator."
},
"cordovaWebviewTroubleshootingMsg2": {
"message": "The tool below is intended to help you to install a new webview or to update an already installed webview."
},
"cordovaAvailableWebviews": {
"message": "Available webview applications on your device"
},
"cordovaWebviewInstall": {
"message": "Installing the <b>{{app}}</b> app can resolve this compatibility issue."
},
"cordovaWebviewInstallBtn": {
"message": "Install from the Google Play Store"
},
"cordovaWebviewUninstall": {
"message": "Uninstalling the <b>{{app}}</b> app can resolve this compatibility issue. If you are not able to uninstall it, try to disable it from the settings app."
},
"cordovaWebviewUninstallBtn1": {
"message": "Uninstall from the Google Play Store"
},
"cordovaWebviewUninstallBtn2": {
"message": "Uninstall / disable from the settings"
},
"cordovaWebviewUpdate": {
"message": "Updating the <b>{{app}}</b> app can resolve this compatibility issue."
},
"cordovaWebviewUpdateBtn": {
"message": "Update from the Google Play Store"
},
"cordovaWebviewEnable": {
"message": "Go into the tab of informations about your device in the settings and tap 10 times on the build version number to enable 'Developper options'. After that, search and go in the developper options and select <b>{{app}}</b> as webview provider."
},
"cordovaWebviewEnableBtn": {
"message": "Open settings"
},
"cordovaWebviewIncompatible": {
"message": "Your device seems to be not compatible. Try to search other ways to update your webview"
},
"cordovaNoWebview": {
"message": "No webview application installed / enabled"
},
"cordovaWebviewUsed": {
"message": "used"
}
}

View File

@ -1,5 +1,6 @@
{
"name": "betaflight-configurator",
"productName": "Betaflight Configurator",
"description": "Crossplatform configuration tool for Betaflight flight control system.",
"version": "10.8.0",
"main": "main.html",
@ -42,6 +43,7 @@
"node": "10.x"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.13.0",
"bluebird": "^3.7.2",
"djv": "^2.1.3-alpha.0",
"i18next": "^18.0.1",
@ -50,6 +52,7 @@
"jbox": "1.0.8",
"jquery": "3.5.0",
"jquery-textcomplete": "^1.8.5",
"jquery-touchswipe": "^1.6.19",
"jquery-ui-npm": "1.12.0",
"lru_map": "^0.3.3",
"marked": "^0.8.0",
@ -62,6 +65,7 @@
"devDependencies": {
"chai": "^4.2.0",
"command-exists": "^1.2.8",
"cordova-lib": "^9.0.1",
"del": "^5.0.0",
"follow-redirects": "^1.10.0",
"fs-extra": "^8.1.0",
@ -69,7 +73,10 @@
"gulp-concat": "~2.6.1",
"gulp-debian": "~0.1.8",
"gulp-git": "^2.10.0",
"gulp-json-editor": "^2.5.4",
"gulp-rename": "^2.0.0",
"gulp-replace": "^1.0.0",
"gulp-xml-transformer": "^3.0.0",
"gulp-yarn": "^2.0.0",
"gulp-zip": "^5.0.0",
"karma": "^4.0.1",

View File

@ -298,15 +298,15 @@ button {
}
.tab-failsafe .pro1 {
background-image: url(../../images/icons/cf_failsafe_procedure1-dark.svg);
background-image: url(../images/icons/cf_failsafe_procedure1-dark.svg);
}
.tab-failsafe .pro2 {
background-image: url(../../images/icons/cf_failsafe_procedure2-dark.svg);
background-image: url(../images/icons/cf_failsafe_procedure2-dark.svg);
}
.tab-failsafe .pro4 {
background-image: url(../../images/icons/cf_failsafe_procedure4-dark.svg);
background-image: url(../images/icons/cf_failsafe_procedure4-dark.svg);
}
@ -381,7 +381,7 @@ progress[value]::-webkit-progress-bar {
}
.tab-landing .logowrapper img {
content:url(/images/cf_logo_black.svg);
content:url(../images/cf_logo_black.svg);
}
.tab-landing .content_mid .text3 .wrap2 {
@ -494,7 +494,7 @@ progress[value]::-webkit-progress-bar {
}
.tab-osd .preview {
background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)), url(../../images/osd-bg-1.jpg);
background: linear-gradient(rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.2)), url(../images/osd-bg-1.jpg);
background-size: cover;
}
@ -523,7 +523,7 @@ progress[value]::-webkit-progress-bar {
.tab-pid_tuning .profile .helpicon,
.tab-pid_tuning .rate_profile .helpicon,
.tab-pid_tuning .pid_titlebar .helpicon {
background-image: url(../../images/icons/cf_icon_info_grey.svg);
background-image: url(../images/icons/cf_icon_info_grey.svg);
opacity: 0.4;
}
.tab-pid_tuning .profile .helpicon:hover,

File diff suppressed because it is too large Load Diff

102
src/css/main_cordova.css Normal file
View File

@ -0,0 +1,102 @@
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body, #loading, #webview_troubleshooting {
width: 100%;
height: 100%;
}
body {
display: flex;
flex-direction: column;
font-family: 'Open Sans', 'Segoe UI', Tahoma, sans-serif;
font-size: 12px;
color: #303030;
background-color: #3d3f3e;
}
#headerbar {
display: flex;
align-items: center;
justify-content: center;
height: 56px;
padding: 0 20px;
background: rgba(0, 0, 0, 0.15);
}
#headerbar img {
height: 20px;
}
#loading {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: #ffffff;
}
#loading p {
font-weight: bold;
margin-top: 20px;
}
#webview_troubleshooting {
display: none;
background: #ffffff;
padding: 20px;
}
#webview_apps {
list-style: inside;
}
#webview_step_btn1, #webview_step_btn2 {
margin-top: 10px;
}
#webview_step_btn2 {
display: none;
}
.box {
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
margin-bottom: 20px;
background-color: #f9f9f9;
overflow: hidden;
}
.box .box_titlebar {
width: 100%;
background-color: #828885;
color: #ffffff;
font-size: 13px;
height: 27px;
line-height: 27px;
font-weight: 600;
padding: 0 10px;
}
.box .box_titlebar.warning {
background-color: #ffbb00;
}
.box .box_body {
padding: 10px;
}
.divider {
margin: 10px 0 9px 0;
border-top: 1px solid #ccc;
}
.btn {
padding: 5px;
text-align: center;
background-color: #ffbb00;
border-radius: 4px;
border: 1px solid #dba718;
color: #ffffff;
font-weight: 600;
font-size: 12px;
line-height: 13px;
transition: all ease 0.2s;
}
.btn:hover {
background-color: #ffcc3f;
text-shadow: 0 1px rgba(255, 255, 255, 0.25);
}
.btn:focus {
outline: none;
background-color: #ffcc3f;
box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.35);
}

View File

@ -108,3 +108,13 @@
.tab-adjustments .adjustment .functionSwitchChannel {
width: 5%;
}
@media all and (max-width: 575px) {
.tab-adjustments .overflow {
overflow: auto;
}
.tab-adjustments .range {
min-width: 300px;
}
}

View File

@ -30,13 +30,11 @@
}
.tab-auxiliary .mode.off .info {
background: #cb4747;
background: #828885;
color: white;
}
.tab-auxiliary .mode.off:nth-child(odd) .info {
background: #cb4747;
background: #828885;
}
@ -54,18 +52,17 @@
.tab-auxiliary .modes {
width: 100%;
border-spacing: 0px;
}
.tab-auxiliary .mode {
background-color: #f9f9f9;
vertical-align: top;
border-bottom: 1px solid #000000;
display: flex;
}
.tab-auxiliary .mode .name {
min-height: 80px;
padding: 5px 0px;
padding: 5px 0;
}
.tab-auxiliary .mode .info {
@ -76,7 +73,7 @@
background-color: #e4e4e4;
border-bottom: 5px solid white;
color: grey;
min-width: 100px;
min-width: 140px;
}
.tab-auxiliary .mode .info .name {
@ -86,7 +83,7 @@
.tab-auxiliary .mode .info .buttons {
position: absolute;
bottom: 0px;
bottom: 0;
width: 100%;
}
@ -103,16 +100,17 @@
}
.tab-auxiliary .ranges {
margin: 10px;
padding-right: 0px;
padding-right: 0;
border-bottom: 5px solid white;
width: 90%;
max-width: calc(100% - 140px);
}
.tab-auxiliary .range {
position: relative;
height: 70px;
padding-top: 15px;
padding-left: 0px;
padding-left: 0;
border-top: 1px solid #fff;
border-bottom: 1px solid var(--subtleAccent);
background-color: #ececec;
@ -131,25 +129,25 @@
}
.tab-auxiliary .range:first-child {
border-top: 0px;
border-top: 0;
}
.tab-auxiliary .range:last-child {
border-bottom: 0px;
border-bottom: 0;
}
.tab-auxiliary .link:first-child {
border-top: 0px;
border-top: 0;
}
.tab-auxiliary .link:last-child {
border-bottom: 0px;
border-bottom: 0;
}
.tab-auxiliary .range>.buttons {
position: absolute;
top: 0px;
right: 0px;
top: 0;
right: 0;
}
.tab-auxiliary .range>.buttons .a {
@ -252,7 +250,7 @@
}
.tab-auxiliary .fixed_band {
bottom: 0px;
bottom: 0;
}
.tab-auxiliary .save_btn a {
@ -261,11 +259,67 @@
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
.tab-auxiliary .fixed_band {
margin: 0px;
width: calc(100% - -30px);
margin-left: -15px;
margin: 0 0 0 -15px;
}
.tab-auxiliary .fixed_band .save_btn a {
margin-right: 15px;
}
}
@media all and (max-width: 575px) {
.tab-auxiliary .mode {
flex-wrap: wrap;
}
.tab-auxiliary .mode .info {
width: 100%;
border-bottom: 0;
}
.tab-auxiliary .mode .info .name {
text-align: left;
padding-left: 10px;
min-height: auto;
}
.tab-auxiliary .mode .info .buttons {
right: 0;
width: auto;
display: flex;
}
.tab-auxiliary .mode .ranges {
width: 100%;
max-width: 100%;
}
.tab-auxiliary .range {
display: flex;
height: auto;
flex-wrap: wrap;
}
.tab-auxiliary .mode .range .channelInfo {
display: flex;
margin: 0 10px;
width: 100%;
flex-wrap: wrap;
}
.tab-auxiliary .limits {
width: 100%;
justify-content: space-between;
display: flex;
}
.tab-auxiliary .range .channel-slider {
width: 100%;
margin: 10px 10px 45px 10px;
}
.tab-auxiliary .delete a {
margin-top: 15px;
margin-right: 10px;
position: absolute;
float: none;
top: 0;
right: 0;
}
.tab-auxiliary .link {
height: auto;
display: flex;
padding-bottom: 10px;
}
}

View File

@ -7,21 +7,21 @@
}
.tab-cli p {
padding: 0px;
border: 0px dotted var(--subtleAccent);
padding: 0;
border: 0 dotted var(--subtleAccent);
}
.tab-cli .backdrop {
border: 1px solid var(--subtleAccent);
background-color: rgba(0, 0, 0, 0.75);
margin-top: 0px;
margin-top: 0;
height: calc(100% - 90px); /* - (p, textarea) */
background-image: url("../../images/light-wide-1.svg");
background-repeat: no-repeat;
background-position: 50% 80%;
background-size: 600px;
border-radius: 5px;
box-shadow: inset 0px 0px 20px rgba(0, 0, 0, 0.80);
box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.80);
width: 100%;
}
@ -137,3 +137,9 @@
font-weight: bold;
}
/* End AutoComplete */
@media all and (max-width: 575px) {
.tab-cli .backdrop {
background-size: 100%;
}
}

View File

@ -1,12 +1,42 @@
.tab-configuration .ui-grid-col {
margin-bottom: 0;
}
.tab-configuration .mixerPreview {
max-width: 230px;
background-color: #eeeeee;
text-align: center;
float: left;
border-radius: 5px;
margin-top: 5px;
}
.tab-configuration .mixerPreview img {
width: 90%;
height: 90%;
padding: 5%;
}
.tab-configuration select.batterymetertype {
margin-right: 5px;
float: left;
width: 150px;
}
.tab-configuration input,
.tab-configuration select {
border: 1px solid var(--subtleAccent);
width: 230px;
height: 20px;
float: left;
margin-right: 15px;
border-radius: 3px;
}
.tab-configuration table {
margin-bottom: 0px;
margin-bottom: 0;
width: 100%;
float: left;
}
.tab-configuration table, .tab-configuration table th, .tab-configuration table td {
padding: 0px;
padding-left: 0px;
padding: 0;
text-align: left;
}
@ -40,17 +70,6 @@
border-bottom: 1px solid var(--subtleAccent);
}
.tab-configuration .leftWrapper {
float: left;
width: calc(50% - 20px);
}
.tab-configuration .rightWrapper {
float: left;
width: calc(50% - 0px);
margin: 0 0 10px 20px;
}
.tab-configuration .mixerList {
width: 100%;
height: 20px;
@ -62,7 +81,7 @@
border-collapse: collapse;
margin-bottom: 5px;
margin-top: -5px;
padding: 0px;
padding: 0;
}
.tab-configuration dl.features dt {
@ -96,12 +115,12 @@
.tab-configuration .number .disabled {
width: 48px;
padding: 0px 5px;
padding: 0 5px;
background-color: #ececec;
}
.tab-configuration .number span {
margin-left: 0px;
margin-left: 0;
}
.tab-configuration .gps .line {
@ -128,7 +147,7 @@
}
.tab-configuration .current .checkbox {
margin-top: 0px;
margin-top: 0;
float: left;
}
@ -138,7 +157,7 @@
}
.tab-configuration .current .checkbox div input {
margin: 0px;
margin: 0;
float: left;
}
@ -153,17 +172,17 @@
}
.tab-configuration .disarm .checkbox div {
margin-bottom: 0px;
margin-top: 0px;
margin-bottom: 0;
margin-top: 0;
}
.tab-configuration .disarm .checkbox div input {
margin: 0px;
margin: 0;
float: left;
}
.tab-configuration .disarm .checkbox span {
margin-left: 0px;
margin-left: 0;
}
.tab-configuration .freelabel {
@ -176,12 +195,12 @@
}
.tab-configuration span {
margin: 0px;
margin: 0;
}
.tab-configuration .disarm .checkbox {
float: left;
padding-left: 0px;
padding-left: 0;
margin-top: -5px;
padding-bottom: 5px;
border-bottom: 1px solid var(--subtleAccent);
@ -210,14 +229,14 @@
.tab-configuration .number,
.tab-configuration .select
{
{
margin-bottom: 5px;
clear: left;
padding-bottom: 5px;
border-bottom: 1px solid var(--subtleAccent);
width: 100%;
float: left;
}
}
.tab-configuration .board_align_inputs,
.tab-configuration .gyro_alignment_inputs {
@ -254,12 +273,12 @@
.tab-configuration .number:last-child,
.tab-configuration .select:last-child {
border-bottom: none;
padding-bottom: 0px;
margin-bottom: 0px;
padding-bottom: 0;
margin-bottom: 0;
}
.tab-configuration .gui_box_titlebar {
margin-bottom: 0px;
margin-bottom: 0;
}
.tab-configuration .numberspacer {
@ -279,8 +298,8 @@
.tab-configuration .rssi td {
border-bottom: none;
padding-bottom: 0px;
margin-bottom: 0px;
padding-bottom: 0;
margin-bottom: 0;
}
.tab-configuration .rssi .gui_box, .tab-configuration .system .gui_box {
@ -312,12 +331,6 @@
width: 30px;
}
.tab-configuration select.batterymetertype {
margin-right: 5px;
float: left;
width: 150px;
}
.tab-configuration .currentmetertype {
float: left;
width: 150px;
@ -340,17 +353,7 @@
}
.tab-configuration .serialRXBox, .spiRxBox {
padding-top: 0px;
}
.tab-configuration input,
.tab-configuration select {
border: 1px solid var(--subtleAccent);
width: 230px;
height: 20px;
float: left;
margin-right: 15px;
border-radius: 3px;
padding-top: 0;
}
@ -361,24 +364,9 @@
.tab-configuration .beeper-configuration tr:last-child td,
.tab-configuration .dshotBeaconConditions tr:last-child td,
.tab-configuration .other tr:last-child td {
border-bottom: 0px;
padding-bottom: 0px;
margin-bottom: 0px;
}
.tab-configuration .mixerPreview {
max-width: 230px;
background-color: #eeeeee;
text-align: center;
float: left;
border-radius: 5px;
margin-top: 5px;
}
.tab-configuration .mixerPreview img {
width: 90%;
height: 90%;
padding: 5%;
border-bottom: 0;
padding-bottom: 0;
margin-bottom: 0;
}
.tab-configuration .gui_box {
@ -466,23 +454,10 @@
margin-top: 10px;
}
.tab-configuration .note.note_adjust {
margin-left: 5px;
margin-right: 5px;
}
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
.tab-configuration .gui_box span {
line-height: 17px;
}
.tab-configuration .leftWrapper {
width: calc(50% - 15px);
}
.tab-configuration .rightWrapper {
float: left;
width: calc(50% - 0px);
margin: 0 0 10px 15px;
}
.tab-configuration .rssi .gui_box, .tab-configuration .system .gui_box {
float: left;
}
@ -499,3 +474,36 @@
float: left;
}
}
@media all and (max-width: 575px) {
.tab-configuration .mixerPreview {
max-width: none;
}
.tab-configuration select.escprotocol {
width: 100%;
margin-right: 0;
}
.tab-configuration .rssi .gui_box, .tab-configuration .system .gui_box {
min-height: auto;
}
.tab-configuration .current td:nth-child(2) {
width: auto;
}
.tab-configuration .voltage td:nth-child(2) {
width: auto;
}
.tab-configuration .rssi td:nth-child(2) {
width: auto;
}
.tab-configuration .rxFailsafe td:nth-child(2) {
width: auto;
}
.tab-configuration .gps td:nth-child(2) {
width: auto;
}
select.features.rxMode, select.serialRX, .dshotbeacon > td > div.select > div, .dshotbeacon select.dshotBeeperBeaconTone {
width: 100%;
}
.tab-configuration .mixer .gui_box, .tab-configuration .motorstop .gui_box {
min-height: auto;
}
}

View File

@ -254,8 +254,7 @@
width: 100%;
border-bottom: 1px solid var(--subtleAccent);
float: left;
padding: 0px;
padding-bottom: 6px;
padding: 0 0 6px;
margin-bottom: 3px;
}
@ -265,7 +264,7 @@
.tab-failsafe .featuresNew td:last-child {
width: calc(100% - 125px);
margin-right: 0px;
margin-right: 0;
}
.tab-failsafe .featuresNew td {

View File

@ -1,11 +1,6 @@
.tab-help .twothird {
width: calc(67% - 15px);
margin-right: 15px;
}
.tab-help .gui_box {
min-height: 500px;
margin-bottom: 0px;
margin-bottom: 0;
}
.tab-help ul {
@ -18,7 +13,7 @@
padding-bottom: 5px;
background-image: url(../../images/arrow.svg);
background-repeat: no-repeat;
background-position: 0px 8px;
background-position: 0 8px;
background-size: 12px;
}
@ -34,3 +29,11 @@
.tab-help .subline {
margin-bottom: 5px;
}
/** (phones) **/
@media all and (max-width: 575px) {
.tab-help .gui_box {
min-height: auto;
margin-bottom: 15px;
}
}

View File

@ -14,21 +14,20 @@
.tab-landing .content_top {
height: 140px;
background: #fff;
padding: 20px;
background-image: url(../../images/pattern.png);
background: #fff url(../../images/pattern.png);
background-size: 300px;
}
.tab-landing .content_mid {
background-color: var(--accent);
overflow: hidden;
padding: 0 15px;
}
.tab-landing .content_foot {
clear: both;
padding: 20px;
padding-bottom: 5px;
padding: 20px 20px 5px;
}
/* hero block */
@ -60,16 +59,8 @@
}
/* text columns */
.tab-landing .content_mid .column .wrap {
padding: 15px;
padding-bottom: 0px;
padding-top: 0px;
}
.tab-landing .content_mid .column .wrap2 {
padding: 10px;
padding-bottom: 10px;
padding-top: 10px;
}
.tab-landing .content_mid h2 {
@ -83,18 +74,6 @@
}
.tab-landing .content_mid .text1 .wrap {
margin-left: 0px;
}
.tab-landing .content_mid .text1 {
width: 37%;
}
.tab-landing .content_mid .text2 {
width: 40%;
}
.tab-landing .content_mid .text2 ul {
margin-top: 2px;
}
@ -106,17 +85,10 @@
margin-left: 30px;
}
.tab-landing .content_mid .text3 {
width: 23%;
}
.tab-landing .content_mid .text3 .wrap2 {
border: 1px solid var(--subtleAccent);
border-radius: 5px;
background: white;
margin-right: 20px;
margin-left: 10px;
margin-top: 5px;
min-height: 187px;
font-size: 11px;
}
@ -127,11 +99,7 @@
}
.tab-landing .content_mid_bottom {
padding: 15px;
padding-top: 0px;
padding-bottom: 0px;
overflow: hidden;
float: left;
padding: 0 15px;
}
.tab-landing .content_mid_bottom .logo {
@ -140,7 +108,7 @@
}
.tab-landing .content_mid_bottom .text4 {
margin-top: 0px;
margin-top: 0;
margin-left: 5px;
display: inline-block;
}
@ -163,3 +131,10 @@
content: ", ";
font-weight: normal;
}
/** (phones) **/
@media all and (max-width: 575px) {
.tab-landing .logowrapper, .tab-landing .logowrapper img {
width: auto;
}
}

View File

@ -442,3 +442,9 @@
z-index: 100;
border: 1px dotted white;
}
@media all and (max-width: 575px) {
.tab-led-strip .controls {
width: 100%;
}
}

View File

@ -50,7 +50,7 @@
.tab-logging .fixed_band {
width: 100%;
bottom: 0px;
bottom: 0;
}
.tab-logging .save_btn .back {
@ -67,3 +67,13 @@
height: 22px;
}
}
@media all and (max-width: 575px) {
.tab-logging .properties dd {
width: 100%;
height: auto;
}
.tab-logging .properties {
width: auto;
}
}

View File

@ -1,7 +1,7 @@
.tab-motors .modelAndGraph {
float: left;
width: 100%;
margin-bottom: 0px;
margin-bottom: 0;
}
.tab-motors .spacer {
@ -30,7 +30,7 @@
.tab-motors .plot_control {
float: right;
width: 160px;
margin: 0px;
margin: 0;
background-color: #ECECEC;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
@ -56,7 +56,7 @@
color: #000;
font-size: 10px;
line-height: 17px;
text-shadow: 0px 1px rgba(255, 255, 255, 0.25);
text-shadow: 0 1px rgba(255, 255, 255, 0.25);
text-transform: uppercase;
letter-spacing: 0.03em;
display: block;
@ -172,7 +172,7 @@
}
.tab-motors .motorblock {
margin-bottom: 0px;
margin-bottom: 0;
background-color: #ECECEC;
/*background-image: -webkit-linear-gradient(top, transparent, rgba(0, 0, 0, 0.15));*/
}
@ -291,7 +291,7 @@
}
.tab-motors .motor_testing .sliders input:first-child {
margin-left: 0px;
margin-left: 0;
}
.tab-motors .motor_testing .values {
@ -309,7 +309,7 @@
.tab-motors .motor_testing .values li:first-child,
.tab-motors .motor_testing .telemetry li:first-child {
margin-left: 0px;
margin-left: 0;
}
.tab-motors .motor_testing .values li,
@ -342,3 +342,86 @@
.tab-motors .motor_testing .notice .motorsEnableTestMode {
margin-left: 10px;
}
@media all and (max-width: 575px) {
.tab-motors .modelAndGraph {
display: flex;
flex-wrap: wrap;
}
.tab-motors .mixerPreview {
order: 1;
width: calc(100% - 160px);
}
.tab-motors .mixerPreview img {
width: calc(100% - 20px);
}
.tab-motors #graph {
width: 100%;
order: 3;
}
.tab-motors .plot_control {
order: 2;
}
.tab-motors .power_info {
order: 4;
width: 100%;
margin-top: 10px;
}
.tab-motors .motorblock {
margin-bottom: 15px;
}
.tab-motors .motorblock > .spacer {
display: flex;
flex-wrap: wrap;
}
.tab-motors .left.motors {
width: 100%;
order: 1;
}
.tab-motors .right.servos {
width: 100%;
order: 3;
margin-top: 15px;
}
.tab-motors .motor_testing {
width: 100%;
display: flex;
flex-wrap: wrap;
order: 2;
}
.tab-motors .motor_testing .notice {
width: 100%;
margin-top: 15px;
}
.tab-motors .titles li, .tab-motors .m-block {
width: calc((100% - 80px) / 9);
}
.tab-motors .titles li:last-child, .tab-motors .m-block:last-child {
margin-right: 0;
}
.tab-motors .motor_testing .left {
width: 100%;
}
.tab-motors .servos .m-block, .tab-motors .servos .titles li {
width: calc((100% - 70px) / 8);
}
.tab-motors .servos .m-block:last-child, .tab-motors .servos .titles li:last-child {
margin-left: 0;
}
.tab-motors .motor_testing .sliders {
margin-left: 2px;
margin-right: -2px;
}
.tab-motors .motor_testing .sliders input {
width: calc((100% - 108px) / 9);
}
.tab-motors .motor_testing .values li, .tab-motors .motor_testing .telemetry li {
width: calc((100% - 80px) / 9);
}
.tab-motors .motor_testing .values li:last-child {
margin-left: 4px;
}
.tab-motors .motor_testing .telemetry li {
font-size: 6px;
}
}

View File

@ -139,6 +139,13 @@
margin-bottom: 0.5em;
}
@media all and (max-width: 575px) {
.tab-onboard_logging dialog {
width: calc(100% - 2em);
border-radius: unset;
}
}
.dataflash-confirm-erase .dataflash-erase-progress {
height: 125px;
display: none;
@ -150,10 +157,7 @@
}
.tab-onboard_logging .save-flash .helpicon {
margin-left: 7px;
margin-right: 0px;
margin-top: 4px;
margin-bottom: 0px;
margin: 4px 0 0 7px;
display: inline-block;
float: unset;
}
@ -290,7 +294,7 @@
border: 1px solid #5bbb1b;
}
.tab-onboard_logging .sdcard-icon {
box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.35);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
width: 90px;
height: 90px;
background-image: url(../../images/icons/cf_icon_sdcard.svg);
@ -303,3 +307,9 @@
border-radius: 45px;
}
@media all and (max-width: 575px) {
.tab-onboard_logging .blackboxRate select, .tab-onboard_logging .blackboxDebugMode select, .tab-onboard_logging .blackboxDevice select {
width: 120px;
}
}

16
src/css/tabs/options.css Normal file
View File

@ -0,0 +1,16 @@
.tab-options .freelabel {
margin-left: 10px;
position: relative;
}
.tab-options .switchery {
float: left;
}
.tab-options .margin-bottom {
margin-bottom: 10px;
}
.tab-options select {
background: var(--boxBackground);
color: var(--defaultText);
border: 1px solid var(--subtleAccent);
border-radius: 3px;
}

View File

@ -7,7 +7,7 @@
position: absolute;
width: 100%;
height: 26px;
top: 0px;
top: 0;
left: 0;
text-align: center;
line-height: 24px;
@ -57,7 +57,7 @@
.info .progress::-webkit-progress-bar {
background-color: #4f4f4f;
border-radius: 4px;
box-shadow: inset 0px 0px 5px #2f2f2f;
box-shadow: inset 0 0 5px #2f2f2f;
}
.info .progress::-webkit-progress-value {
@ -86,9 +86,8 @@
}
.tab-osd ul li {
list-style: initial;
list-style-type: circle;
margin-left: 30px;
list-style: circle;
margin-left: 30px;
}
.tab-osd .options {
@ -129,7 +128,7 @@
.tab-osd .options .description {
position: relative;
left: 0px;
left: 0;
font-style: italic;
color: #818181;
}
@ -310,8 +309,7 @@
#font-logo-preview-container {
background:rgba(0, 255, 0, 0.4);
margin-bottom: 10px;
width: 45%;
float: left;
box-sizing: border-box;
}
#font-logo-preview {
@ -321,11 +319,8 @@
}
#font-logo-info {
width: 45%;
margin-left: 18px;
font-size: 125%;
line-height: 150%;
float: left;
}
#font-logo-info h3 {
@ -414,7 +409,7 @@ button {
line-height: 23px;
height: 23px;
box-sizing: border-box;
padding-right: 0px;
padding-right: 0;
}
.tab-osd .switchable-field label {
@ -443,7 +438,7 @@ button {
.tab-osd .switchable-field:last-child {
border-bottom: 0px;
border-bottom: 0;
}
.tab-osd input,
@ -458,11 +453,13 @@ button {
width: 360px;
float: left;
position: sticky;
top: 0px;
top: 0;
margin-left: calc((100% - 362px) / 2);
/* please don't copy the generic background image from another project
* and replace the one that @nathantsoi took :)
*/
/* please don't copy the generic background image from another project
* and replace the one that @nathantsoi took :)
*/
background: url(../../images/osd-bg-1.jpg);
background-size: cover;
border-bottom-left-radius: 3px;
@ -479,7 +476,7 @@ button {
.tab-osd .alarms label:last-child {
border-bottom: none;
padding-bottom: 0px
padding-bottom: 0
}
.tab-osd .alarms input {
@ -510,3 +507,56 @@ button {
height: calc(100% - 30px);
}
}
.tab-osd .grid-col.col4:first-child, .tab-osd .grid-col.col4:last-child {
width: calc((100% - 390px) / 2);
}
.tab-osd .grid-row {
margin-bottom: 40px;
}
.tab-osd .grid-col.col4 {
width: auto;
}
@media all and (max-width: 575px) {
.tab-osd .osd-preview {
order: 1;
}
.tab-osd .osd-feature {
order: 2;
}
.tab-osd .osd-profile {
order: 3;
}
.tab-osd .preview.requires-osd-feature {
width: 100%;
max-width: 363px;
margin-left: 0;
}
.tab-osd .osd-feature, .tab-osd .osd-profile {
max-width: 100%;
}
#fontmanagercontent {
max-width: 100%;
}
.content_wrapper.font-preview {
padding: 15px 0;
}
#fontmanagercontent .grid-row {
margin-bottom: 15px;
}
.fontpresets_wrapper {
display: block;
position: relative;
right: 0;
top: 0;
margin-bottom: 15px;
}
}
@media all and (max-width: 575px) and (min-width: 390px) {
.tab-osd .preview.requires-osd-feature {
margin-left: calc((100% - 363px) / 2);
}
}

View File

@ -17,7 +17,7 @@
}
.tab-pid_tuning .cf th:last-child {
border-right: 0px;
border-right: 0;
border-top-right-radius: 3px;
}
@ -27,8 +27,8 @@
.tab-pid_tuning .cf td:last-child {
border-bottom-right-radius: 3px;
border-right: 0px;
padding-bottom: 0px;
border-right: 0;
padding-bottom: 0;
}
.tab-pid_tuning .cf input {
@ -69,7 +69,7 @@
.tab-pid_tuning table {
float: left;
margin: 0px;
margin: 0;
border-collapse: collapse;
width: 100%;
table-layout: fixed;
@ -90,12 +90,12 @@
.tab-pid_tuning table, .tab-pid_tuning table td {
padding: 1px;
border-bottom: 0px solid var(--subtleAccent);
border-bottom: 0 solid var(--subtleAccent);
}
.tab-pid_tuning table th {
padding: 0px;
border: 0px;
padding: 0;
border: 0;
height: 10px;
font-weight: normal;
text-overflow: ellipsis;
@ -124,7 +124,7 @@
}
.tab-pid_tuning table tr td:last-child {
border-right: 0px solid var(--subtleAccent);
border-right: 0 solid var(--subtleAccent);
}
.tab-pid_tuning #pid_optional table th {
@ -219,8 +219,7 @@
}
.tab-pid_tuning table td {
padding: 1px;
padding-left: 5px;
padding: 1px 1px 1px 5px;
border-right: 1px solid var(--subtleAccent);
}
@ -266,22 +265,20 @@
.tab-pid_tuning .tab-container {
border-bottom: 3px solid var(--accent);
border-right-width: 0px;
border-right-width: 0;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
height: 29px;
justify-content: start;
width: 100%;
}
.tab-pid_tuning .tab-container > div {
display: flex;
justify-content: center;
align-items: center;
background-color: #2e2e2e;
padding: 0 12px;
padding: 6px 12px;
border-right: 1px solid white;
box-sizing: border-box;
text-align: center;
}
.tab-pid_tuning .tab-container > div:first-child {
@ -294,7 +291,6 @@
.tab-pid_tuning .tab-container > div a {
display: block;
white-space: nowrap;
color: #999999;
}
@ -318,8 +314,7 @@
color: var(--quietText);
height: 19px;
font-weight: normal;
padding: 2px;
padding-left: 6px;
padding: 2px 2px 2px 6px;
border-top-left-radius: 3px;
border-top-right-radius: 3px;
}
@ -335,7 +330,7 @@
.tab-pid_tuning .fixed_band {
position: absolute;
width: 100%;
bottom: 0px;
bottom: 0;
}
.fancy.header {
@ -358,12 +353,10 @@
height: 18px;
background-color: #D6D6D6;
float: left;
margin: 0px;
padding: 0px;
margin: 0;
text-align: left;
padding-left: 5px;
line-height: 13px;
padding-top: 5px;
padding: 5px 0 0 5px;
font-size: 12px;
border-bottom: 1px solid var(--subtleAccent);
color: #828282;
@ -381,7 +374,7 @@
}
.tab-pid_tuning .pid_mode .helpicon {
margin-top: 0px;
margin-top: 0;
}
.tab-pid_tuning .pid_titlebar {
@ -393,11 +386,11 @@
}
.tab-pid_tuning .pid_titlebar.pid_titlebar_extended {
border-radius: 0px;
border-radius: 0;
}
.tab-pid_tuning .cf .throttleCurvePreview {
padding: 0px;
padding: 0;
}
.pid_roll {
@ -419,15 +412,9 @@
.show {
width:130px;
float:right;
margin-right:3px;
}
.show a {
margin-left: 10px;
width: calc(100% - 10px);
}
.tab-pid_tuning .helpicon {
margin-top: 1px;
}
@ -439,7 +426,7 @@
.tab-pid_tuning .number .helpicon {
margin-top: 3px;
margin-right: 0px;
margin-right: 0;
}
.tab-pid_tuning .gui_box_titlebar .helpicon {
@ -448,7 +435,7 @@
}
.tab-pid_tuning .spacer_left {
padding-left: 0px;
padding-left: 0;
float: right;
width: calc(100% - 20px)
}
@ -470,7 +457,7 @@
.tab-pid_tuning .number:last-child {
padding-bottom: 5px;
border-bottom: 0px;
border-bottom: 0;
}
.tab-pid_tuning .number input {
@ -495,18 +482,16 @@
.tab-pid_tuning .resetbt {
width: 140px;
float: right;
margin-right: 10px;
}
.tab-pid_tuning .copyprofilebtn {
width: 150px;
float: right;
margin-right:10px;
}
.tab-pid_tuning .copyrateprofilebtn {
width: 150px;
float: right;
margin-right:10px;
}
@ -520,7 +505,7 @@
}
.tab-pid_tuning .leftzero {
padding-left: 0px;
padding-left: 0;
}
.tab-pid_tuning .roll {
@ -626,7 +611,7 @@
.tab-pid_tuning .pidTuning tr {
width: 100%;
border-bottom: 1px solid var(--subtleAccent);
padding: 0px;
padding: 0;
}
.tab-pid_tuning .pidTuning td:first-child {
@ -644,16 +629,16 @@
}
.tab-pid_tuning .new_rates td:first-child {
border-bottom-left-radius: 0px;
border-bottom-left-radius: 0;
padding-left: 10px;
}
.tab-pid_tuning .new_rates td:last-child {
border-bottom-right-radius: 0px;
border-bottom-right-radius: 0;
}
.tab-pid_tuning .rc_curve .cf tr td {
padding: 0px;
padding: 0;
}
.tab-pid_tuning .rc_curve_bg {
@ -694,7 +679,7 @@
border: 1px solid var(--subtleAccent);
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
border-top: 0px solid var(--subtleAccent);
border-top: 0 solid var(--subtleAccent);
background: #f9f9f9;
}
@ -718,6 +703,13 @@
width: 120px;
}
@media all and (max-width: 575px) {
.tab-pid_tuning dialog {
width: calc(100% - 2em);
border-radius: unset;
}
}
.tab-pid_tuning .tuningSlider {
-webkit-appearance: none;
width: calc(100% - 14px);
@ -935,3 +927,98 @@
.tab-pid_tuning .float-left {
float: left;
}
.tab-pid_tuning .content_wrapper_header {
display: flex;
}
.tab-pid_tuning .content_wrapper_header_btns {
margin-left: auto;
}
@media all and (max-width: 575px) {
.tab-pid_tuning .content_wrapper_header {
flex-wrap: wrap;
}
.tab-pid_tuning .profile, .tab-pid_tuning .rate_profile,
.tab-pid_tuning .copyprofilebtn, .tab-pid_tuning .copyrateprofilebtn,
.tab-pid_tuning .resetbt, .tab-pid_tuning .show {
width: calc(50% - 5px);
}
.tab-pid_tuning .rate_profile {
margin-left: 5px;
}
.tab-pid_tuning .rate_profile, .tab-pid_tuning .controller,
.tab-pid_tuning .copyrateprofilebtn, .tab-pid_tuning .show {
margin-right: 0;
}
.tab-pid_tuning .controller {
width: 100%;
}
.tab-pid_tuning .content_wrapper_header_btns {
display: flex;
flex-wrap: wrap;
}
.tab-pid_tuning .tab-container > div {
width: calc(100% / 3);
}
.tab-pid_tuning .subtab-pid .cf_column, .tab-pid_tuning .subtab-rates .cf_column {
min-width: 100%;
width: 100%;
}
.tab-pid_tuning .spacer_left {
width: 100%;
}
.subtab-filter .two_columns {
flex-wrap: wrap;
}
.subtab-filter .two_columns .two_columns_first {
margin-right: 0;
}
.subtab-filter .two_columns .two_columns_second {
margin-left: 0;
}
.tab-pid_tuning .sliderHeaders {
height: 18px;
background-color: #D6D6D6;
line-height: 13px;
font-size: 12px;
border-bottom: 1px solid var(--subtleAccent);
color: #828282;
font-weight: normal;
background-image: linear-gradient(315deg, rgba(255, 255, 255, .2) 10%, transparent 10%, transparent 20%,
rgba(255, 255, 255, .2) 20%, rgba(255, 255, 255, .2) 30%, transparent 30%, transparent 40%,
rgba(255, 255, 255, .2) 40%, rgba(255, 255, 255, .2) 50%, transparent 50%, transparent 60%,
rgba(255, 255, 255, .2) 60%, rgba(255, 255, 255, .2) 70%, transparent 70%, transparent 80%,
rgba(255, 255, 255, .2) 80%, rgba(255, 255, 255, .2) 90%, transparent 90%, transparent 100%,
rgba(255, 255, 255, .2) 100%, transparent);
}
.tab-pid_tuning .sliderHeaders span {
color: #828282;
}
.tab-pid_tuning .sliderLabels tr.sliderHeaders td:first-child {
text-align: left;
}
.tab-pid_tuning .tuningPIDSliders .pid_titlebar th:last-child, .tab-pid_tuning .tuningFilterSliders .pid_titlebar th:last-child {
width: 20%;
}
.tab-pid_tuning .tuningPIDSliders .pid_titlebar th:nth-child(2), .tab-pid_tuning .tuningFilterSliders .pid_titlebar th:nth-child(2) {
width: 20%;
}
}

View File

@ -13,9 +13,9 @@
}
.tab-ports table, .tab-ports table th, .tab-ports table td {
border-left: 0px;
border-right: 0px;
border-top: 0px;
border-left: 0;
border-right: 0;
border-top: 0;
}
.tab-ports table tr td:first-child {
@ -37,9 +37,9 @@
.tab-ports table thead tr:first-child {
font-size: 12px;
height: 25px;
border-top: 0px;
border-right: 0px;
border-left: 0px;
border-top: 0;
border-right: 0;
border-left: 0;
}
.tab-ports .function input {
@ -99,12 +99,12 @@
.tab-ports .ports thead td:first-child {
text-align: left;
border-top-left-radius: 5px;
border-left: 0px;
border-left: 0;
}
.tab-ports .ports thead td:last-child {
border-top-right-radius: 5px;
border-right: 0px;
border-right: 0;
}
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
@ -113,3 +113,45 @@
height: 22px;
}
}
@media all and (max-width: 575px) {
.tab-ports .config {
text-align: left;
border-top-left-radius: 5px;
border-left: 0;
}
.tab-ports table td {
padding: 0;
}
.tab-ports .ports select {
margin: 0;
width: 100%;
border: none;
height: 25px;
border-radius: unset;
}
.tab-ports .portIdentifier td {
height: 18px;
background-color: #D6D6D6;
padding: 2px 5px;
font-size: 12px;
color: #828282;
font-weight: normal;
background-image: linear-gradient(315deg, rgba(255, 255, 255, .2) 10%, transparent 10%, transparent 20%,
rgba(255, 255, 255, .2) 20%, rgba(255, 255, 255, .2) 30%, transparent 30%, transparent 40%,
rgba(255, 255, 255, .2) 40%, rgba(255, 255, 255, .2) 50%, transparent 50%, transparent 60%,
rgba(255, 255, 255, .2) 60%, rgba(255, 255, 255, .2) 70%, transparent 70%, transparent 80%,
rgba(255, 255, 255, .2) 80%, rgba(255, 255, 255, .2) 90%, transparent 90%, transparent 100%,
rgba(255, 255, 255, .2) 100%, transparent);
}
.tab-ports .ports select[name=function-peripherals], .tab-ports .ports select[name=function-telemetry],
.tab-ports .ports select[name=function-sensors] {
border-bottom: 1px solid var(--subtleAccent);
}
.tab-ports .ports thead td {
font-size: 8px;
width: calc(100% / 5);
word-break: break-word;
white-space: unset;
}
}

View File

@ -2,15 +2,8 @@
display: none;
}
.tab-power .leftWrapper {
float: left;
width:calc(50% - 20px)
}
.tab-power .rightWrapper {
float: left;
width: calc(50% - 0px);
margin: 0 0 10px 20px;
.tab-power .ui-grid-col {
margin-bottom: 0;
}
.tab-power td.configuration {
@ -19,7 +12,7 @@
}
.tab-power .battery-state .configuration {
border-bottom: 0px;
border-bottom: 0;
}
.tab-power td.value {
@ -49,7 +42,7 @@
.tab-power .number,
.tab-power .select
{
{
margin-bottom: 5px;
clear: left;
padding-bottom: 5px;
@ -69,8 +62,8 @@
.tab-power .number:last-child,
.tab-power .select:last-child {
border-bottom: none;
padding-bottom: 0px;
margin-bottom: 0px;
padding-bottom: 0;
margin-bottom: 0;
}
.tab-power .require-support {

View File

@ -13,8 +13,6 @@
}
.tab-receiver .bars {
float: left;
width: calc(50% - 20px);
font-weight: bold;
}
@ -136,16 +134,10 @@
background-color: #14407a;
}
.tab-receiver .fc_column {
float: right;
width: 50%;
margin-left: 20px;
}
.tab-receiver .tunings {
float: right;
position: relative;
margin: 0px 0px 10px 0;
margin: 0 0 10px 0;
width: 100%;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
@ -153,9 +145,8 @@
.tab-receiver .tunings .head {
height: 15px;
padding: 4px;
text-align: left;
padding-left: 6px;
padding: 4px 4px 4px 6px;
font-weight: normal;
background: #828885;
color: white;
@ -168,9 +159,8 @@
}
.tab-receiver .tunings table, .tab-receiver .tunings table th, .tab-receiver .tunings table td {
padding: 4px;
text-align: left;
padding-left: 6px;
padding: 4px 4px 4px 6px;
}
.tab-receiver .tunings table th {
@ -186,7 +176,7 @@
.tab-receiver .tunings table th:last-child {
border-top-right-radius: 3px;
border-right: 0px;
border-right: 0;
}
.tab-receiver .tunings table td {
@ -200,7 +190,7 @@
.tab-receiver .tunings table td:last-child {
border-bottom-right-radius: 3px;
border-right: 0px;
border-right: 0;
}
.tab-receiver .tunings table input {
@ -231,7 +221,7 @@
.tab-receiver .rssi_channel_wrapper {
float: right;
margin: 0px 0px 10px 0;
margin: 0 0 10px 0;
border-left: 0;
width: 30%;
box-sizing: border-box;
@ -244,7 +234,7 @@
.tab-receiver .rcmap_wrapper {
float: right;
position: relative;
margin: 0px 0px 10px 0;
margin: 0 0 10px 0;
width: 70%;
box-sizing: border-box;
border-top-left-radius: 5px;
@ -293,11 +283,9 @@
width: calc(100% - 36px);
height: 20px;
z-index: 2;
border-radius: 0px;
border: 1px solid var(--subtleAccent);
margin: 4px;
border-top-left-radius: 3px;
border-bottom-left-radius: 3px;
border-radius: 3px 0 0 3px;
}
.tab-receiver select {
@ -333,7 +321,7 @@
}
.tab-receiver .rcSmoothing table .helpicon {
margin-top: 0px;
margin-top: 0;
}
.tab-receiver .rcSmoothing td:first-child {
@ -478,3 +466,9 @@
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
@media all and (max-width: 575px) {
.tab-receiver .bars {
margin-bottom: 10px;
}
}

View File

@ -21,9 +21,8 @@
float: right;
width: 160px;
/* border: 1px solid silver; */
height: 100%;
height: 160px;
margin: 0px;
margin: 0;
background-color: #ECECEC;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
@ -170,3 +169,26 @@
.tab-sensors .legend .item:nth-child(4) {
fill: #4DA74D;
}
@media all and (max-width: 575px) {
.tab-sensors .plot_control {
width: 130px;
}
.tab-sensors .plot_control dt {
width: 60px;
}
.tab-sensors .plot_control dd {
width: 50px;
}
.tab-sensors .plot_control dd select {
width: 100%;
}
.tab-sensors .plot_control .x, .tab-sensors .plot_control .y, .tab-sensors .plot_control .z {
height: 18px;
box-sizing: border-box;
}
.tab-sensors svg {
width: calc(100% - 130px);
margin-left: 0;
}
}

View File

@ -1,5 +1,5 @@
.tab-servos .title {
margin-top: 0px;
margin-top: 0;
line-height: 30px;
text-align: center;
font-weight: bold;
@ -18,9 +18,9 @@
}
.tab-servos table, .tab-servos table th, .tab-servos table td {
border-left: 0px;
border-right: 0px;
border-top: 0px;
border-left: 0;
border-right: 0;
border-top: 0;
}
.tab-servos input[type="number"]::-webkit-inner-spin-button {
@ -130,7 +130,7 @@
.tab-servos .live {
float: left;
margin-top: 0px;
margin-top: 0;
}
.tab-servos .live span {
@ -175,3 +175,16 @@
.tab-servos .short {
width: 40px;
}
.tab-servos .table_overflow {
overflow: auto;
}
@media all and (max-width: 575px) {
.tab-servos table th {
min-width: 30px;
}
.tab-servos .min, .tab-servos .max, .tab-servos .middle {
min-width: 60px;
}
}

View File

@ -1,45 +1,60 @@
.tab_setup .model-and-info {
float: left;
.tab-setup .ui-grid-col {
margin-bottom: 0;
}
.tab_setup .default_btn {
.tab-setup .content_wrapper {
position: initial;
}
.tab-setup .default_btn {
margin-bottom: 10px;
}
.tab-setup .cell_setup {
border-bottom: solid 1px var(--subtleAccent);
padding-bottom: 8px;
padding-top: 7px;
}
#accel_calib_running, #mag_calib_running {
display: none;
width: 100%;
position: relative;
margin-bottom: 0;
margin-top: 0;
float: left;
padding: 5px 0 5px 0;
text-align: center;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ffbb00;
color: #ffbb00;
font-weight: bold;
font-size: 12px;
line-height: 13px;
transition: all ease 0.2s;
text-decoration:none;
}
.tab-setup .data-loading-setup {
width: 100%;
height: 100%;
}
.tab-setup .modelwrapper {
clear: both;
margin-bottom: 5px;
}
.tab-setup .model-and-info {
position: relative;
height: 400px;
margin-bottom: 10px;
}
.tab-setup #interactive_block {
position: absolute;
width: calc(75% - 30px);
height: calc(100% - 245px);
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #f9f9f9;
border-radius: 5px;
border: 1px solid #e4e4e4;
margin-bottom: 10px;
}
.attitude_info {
position: absolute;
top: 10px;
left: 10px;
width: 120px;
margin: 0px 0px 0px 0px;
font-weight: normal;
color: var(--mutedText);
}
.attitude_info dl {
width: 100%;
}
.attitude_info dt {
width: 50%;
float: left;
}
.attitude_info dd {
width: 50%;
float: left;
}
.tab-setup #interactive_block a.reset {
position: absolute;
display: block;
@ -56,11 +71,9 @@
background-color: #ececec;
z-index: 100;
}
.tab-setup #interactive_block a.reset:hover {
background-color: #dedcdc;
}
.tab-setup #canvas_wrapper {
position: absolute;
width: 100%;
@ -69,11 +82,48 @@
left: 0;
border-radius: 5px;
}
#canvas {
width: 100% !important;
height: 100% !important;
}
.attitude_info {
position: absolute;
top: 10px;
left: 10px;
width: 120px;
margin: 0 0 0 0;
font-weight: normal;
color: var(--mutedText);
}
.attitude_info dl {
width: 100%;
}
.attitude_info dt {
width: 50%;
float: left;
}
.attitude_info dd {
width: 50%;
float: left;
}
.instrumentsbox {
margin-bottom: 0;
}
@media all and (max-width: 575px) {
.tab-setup .cell_setup {
border-bottom: none;
padding-bottom: 15px;
padding-top: 0;
}
.tab-setup .default_btn {
margin-bottom: 5px;
}
.tab-setup .model-and-info {
height: 200px;
}
}
.block.info .fields {
padding: 5px 5px 3px 5px;
@ -120,42 +170,6 @@
bottom: 20px;
}
.cell_setup {
border-bottom: solid 1px var(--subtleAccent);
padding-bottom: 8px;
padding-top: 7px;
}
.tab_setup .content_wrapper {
position: initial;
}
.initialstyle {
position: initial;
}
.buttonarea {
min-height: 100px;
width: 20%;
}
.halfbuttons {
width: calc(100% - 10px);
}
.setupinfo {
width: 80%;
}
.modelwrapper {
clear: both;
margin-bottom: 5px;
}
.instrumentsbox {
margin-bottom: 0px;
}
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
.block.instrument .attitude {
width: 50px !important;
@ -165,62 +179,6 @@
width: 50px;
height: 50px;
}
.tab-setup #interactive_block {
position: absolute;
width: calc(75% - 20px);
height: calc(100% - 218px);
}
}
#accel_calib_running {
display: none;
width: 100%;
position: relative;
margin-bottom: 0px;
margin-top: 0px;
float: left;
padding: 5px 0px 5px 0px;
text-align: center;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ffbb00;
color: #ffbb00;
font-weight: bold;
font-size: 12px;
line-height: 13px;
transition: all ease 0.2s;
text-decoration:none;
}
#mag_calib_running {
display: none;
width: 100%;
position: relative;
margin-bottom: 0px;
margin-top: 0px;
float: left;
padding: 5px 0px 5px 0px;
text-align: center;
background-color: #fff;
border-radius: 4px;
border: 1px solid #ffbb00;
color: #ffbb00;
font-weight: bold;
font-size: 12px;
line-height: 13px;
transition: all ease 0.2s;
text-decoration:none;
}
.data-loading-setup {
width: 100%;
height: 100%;
}
.tab-setup .regular-button {
@ -232,13 +190,11 @@
border: 1px solid #dba718;
color: #000;
font-size: 12px;
text-shadow: 0px 1px rgba(255, 255, 255, 0.25);
text-shadow: 0 1px rgba(255, 255, 255, 0.25);
display: inline-block;
cursor: pointer;
transition: all ease 0.2s;
padding: 0px;
padding-left: 9px;
padding-right: 9px;
padding: 0 9px;
line-height: 28px;
}
.tab-setup .regular-button:hover {
@ -248,7 +204,7 @@
.tab-setup .regular-button:active {
background-color: #ffcc3e;
transition: all ease 0.0s;
box-shadow: inset 0px 1px 5px rgba(0, 0, 0, 0.35);
box-shadow: inset 0 1px 5px rgba(0, 0, 0, 0.35);
}
.tab-setup .regular-button.disabled {
cursor: default;
@ -274,8 +230,13 @@
margin-bottom: 0.5em;
}
@media all and (max-width: 575px) {
.tab-setup dialog {
width: calc(100% - 2em);
border-radius: unset;
}
}
.disarm-flag {
padding-left: 5px;
}
}

View File

@ -1,6 +1,6 @@
#tab-static {
background-color: inherit;
background-image: url(/images/osd-bg-1.jpg);
background-image: url(../../images/osd-bg-1.jpg);
background-attachment: fixed;
background-size: cover;
background-position: bottom right;

View File

@ -114,7 +114,7 @@
.tab-vtx .table_vtx_bands td, .tab-vtx .table_vtx_powerlevels td {
padding: 0px 1px;
padding: 0 1px;
text-align: center;
}
@ -144,3 +144,22 @@
#tab-vtx-templates {
display: none;
}
@media all and (max-width: 575px) {
.tab-vtx .columnsWrapper {
flex-wrap: wrap;
}
.tab-vtx .columnsWrapper .leftColumn {
width: 100%;
}
.tab-vtx .columnsWrapper .rightColumn {
width: 100%;
flex-basis: auto;
}
.tab-vtx .leftWrapper {
width: 100%;
overflow: auto;
}
}

View File

@ -0,0 +1,133 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg4057"
sodipodi:docname="light-wide-2-compact.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
x="0px"
y="0px"
viewBox="-21 39.4 167.7 18.6"
xml:space="preserve"
width="167.7"
height="18.6"><metadata
id="metadata3781"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs3779" />
<style
type="text/css"
id="style3748">
.st0{fill:#FFBB00;}
.st1{fill:#FFFFFF;}
</style>
<sodipodi:namedview
inkscape:window-maximized="1"
inkscape:pageopacity="0.0"
inkscape:current-layer="g3776"
inkscape:showpageshadow="false"
inkscape:window-y="-8"
inkscape:window-height="837"
inkscape:pageshadow="2"
fit-margin-bottom="0"
inkscape:window-x="-8"
fit-margin-right="0"
inkscape:window-width="1600"
inkscape:document-units="px"
id="base"
borderopacity="1.0"
bordercolor="#666666"
fit-margin-left="0"
inkscape:cx="75.420679"
inkscape:zoom="3.959798"
showgrid="true"
inkscape:cy="-2.46571"
fit-margin-top="0"
borderlayer="false"
showborder="true"
showguides="false"
pagecolor="#ffffff">
<inkscape:grid
type="xygrid"
id="grid4093"
originy="-961.9602"
originx="-40.900311" />
</sodipodi:namedview>
<g
id="g3776"
transform="translate(-30.859,-43.699999)">
<g
id="g3772"
transform="translate(-40.041,21.699999)">
<path
class="st0"
d="m 56.2,61.9 h 9.7 c 4.7,0 4.7,2.6 4.1,4.4 -0.6,1.8 -1.8,2.8 -3.4,3.5 1.4,0.5 2.4,1.8 1.5,4.4 -1.3,3.6 -5,5.4 -8.1,5.4 H 49.9 Z m 0.7,13.5 h 3.2 c 1.1,0 2.3,-0.3 2.7,-1.7 0.4,-1 0,-1.6 -1.3,-1.6 h -3.4 z m 2.3,-6.6 h 2.9 c 1.1,0 2,-0.3 2.4,-1.5 0.3,-0.9 -0.3,-1.2 -1.4,-1.2 h -2.9 z"
id="path3752"
inkscape:connector-curvature="0"
style="fill:#ffbb00" />
<path
class="st0"
d="M 74.9,61.9 H 89.6 L 88,66.4 h -9.3 l -0.8,2.2 h 8.4 l -1.5,4.2 H 76.4 L 75.7,75 h 9.5 l -1.6,4.5 h -15 z"
id="path3754"
inkscape:connector-curvature="0"
style="fill:#ffbb00" />
<path
class="st0"
d="m 94.7,66.4 h -5 l 1.6,-4.5 h 15.4 l -1.6,4.5 h -5 l -4.7,13.2 h -5.5 z"
id="path3756"
inkscape:connector-curvature="0"
style="fill:#ffbb00" />
<path
class="st0"
d="m 111.8,61.9 h 5.3 l 0.2,17.7 h -5.6 l 0.2,-2.5 h -5.6 l -1.7,2.5 h -5.5 z m 0.3,11.4 0.3,-5.5 v 0 l -3.7,5.5 z"
id="path3758"
inkscape:connector-curvature="0"
style="fill:#ffbb00" />
<path
class="st1"
d="m 125.1,61.9 h 13.7 l -1.6,4.5 H 129 l -0.8,2.2 h 7.1 l -1.5,4.2 h -7.1 l -2.4,6.8 h -5.5 z"
id="path3760"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
class="st1"
d="m 140.9,61.9 h 5.5 L 141.7,75 h 7.9 l -1.6,4.5 h -13.3 z"
id="path3762"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
class="st1"
d="m 156.2,61.9 h 5.5 l -6.3,17.7 h -5.5 z"
id="path3764"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
class="st1"
d="m 172,77.8 c -1.8,1.6 -3.9,2.2 -5.8,2.2 -5.2,0 -7,-4.1 -5.2,-9.1 2.4,-6.8 8.1,-9.5 12.1,-9.5 4.5,0 6.5,2.5 5.8,6.6 h -5.2 c 0.3,-1.3 -0.5,-2.2 -1.8,-2.2 -3.8,0 -5,4 -5.5,5.2 -0.6,1.7 -0.9,4.6 2.4,4.6 1.3,0 2.8,-0.6 3.5,-2 h -2.4 l 1.3,-3.8 h 7.3 l -3.5,9.8 h -3.5 z"
id="path3766"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
class="st1"
d="m 184.3,61.9 h 5.5 l -2.2,6.2 h 5.1 l 2.2,-6.2 h 5.5 l -6.3,17.7 h -5.5 l 2.5,-7 H 186 l -2.5,7 H 178 Z"
id="path3768"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
<path
class="st1"
d="m 205.6,66.4 h -5 l 1.6,-4.5 h 15.4 l -1.6,4.5 h -5 l -4.7,13.2 h -5.5 z"
id="path3770"
inkscape:connector-curvature="0"
style="fill:#ffffff" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -36,7 +36,7 @@ Clipboard._configureClipboardAsNwJs = function(nwGui) {
if (onSuccess) {
onSuccess(text);
}
}
};
this.readText = function(onSuccess, onError) {
@ -54,8 +54,8 @@ Clipboard._configureClipboardAsNwJs = function(nwGui) {
if (onSuccess) {
onSuccess(text);
}
}
}
};
};
Clipboard._configureClipboardAsChrome = function() {
@ -69,15 +69,33 @@ Clipboard._configureClipboardAsChrome = function() {
navigator.clipboard.writeText(text)
.then(onSuccess)
.catch(onError);
}
};
this.readText = function(onSuccess, onError) {
navigator.clipboard.readText()
.then(onSuccess)
.catch(onError);
}
};
}
};
Clipboard._configureClipboardAsCordova = function() {
console.log('Cordova Clipboard available');
this.available = true;
this.readAvailable = true;
this.writeAvailable = true;
this.writeText = function(text, onSuccess, onError) {
cordova.plugins.clipboard.copy(text, onSuccess, onError);
};
this.readText = function(onSuccess, onError) {
cordova.plugins.clipboard.paste(onSuccess, onError);
};
};
Clipboard._configureClipboardAsOther = function() {
@ -89,12 +107,12 @@ Clipboard._configureClipboardAsOther = function() {
this.writeText = function(text, onSuccess, onError) {
onError('Clipboard not available');
}
};
this.readText = function(onSuccess, onError) {
onError('Clipboard not available');
}
}
};
};
switch (GUI.Mode) {
@ -106,6 +124,10 @@ case GUI_Modes.ChromeApp:
Clipboard._configureClipboardAsChrome();
break;
case GUI_Modes.Cordova:
Clipboard._configureClipboardAsCordova();
break;
default:
Clipboard._configureClipboardAsOther();
}

View File

@ -172,9 +172,10 @@ Features.prototype.generateElements = function (featuresElements) {
+ self._features[i].name
+ '" title="'
+ self._features[i].name
+ '" type="checkbox"/></td>'
+ '" type="checkbox"/></td><td><div>'
+ featureName
+ '<td><span i18n="feature' + self._features[i].name + '"></span>'
+ '</div><span class="xs" i18n="feature' + self._features[i].name + '"></span></td>'
+ '<td><span class="sm-min" i18n="feature' + self._features[i].name + '"></span>'
+ feature_tip_html + '</td></tr>');
var feature_e = newElement.find('input.feature');

View File

@ -318,7 +318,8 @@ function configuration_restore(callback) {
};
reader.onloadend = function (e) {
if (e.total != 0 && e.total == e.loaded) {
if ((e.total != 0 && e.total == e.loaded) || GUI.isCordova()) {
// Cordova: Ignore verification : seem to have a bug with progressEvent returned
console.log('Read SUCCESSFUL');
try { // check if string provided is a valid JSON

418
src/js/cordova_chromeapi.js vendored Normal file
View File

@ -0,0 +1,418 @@
'use strict';
const chromeCallbackWithError = function(message, callback) {
let err;
if (typeof message === 'string') {
err = { 'message' : message };
} else {
err = message;
}
if (typeof callback !== 'function') {
console.error(err.message);
return;
}
try {
if (typeof chrome.runtime !== 'undefined') {
chrome.runtime.lastError = err;
} else {
console.error(err.message);
}
callback.apply(null, Array.prototype.slice.call(arguments, 2));
} finally {
if (typeof chrome.runtime !== 'undefined') {
delete chrome.runtime.lastError;
}
}
};
const chromeCallbackWithSuccess = function(argument, callback) {
if (typeof callback === 'function') {
if (typeof argument === 'undefined') {
callback();
} else {
callback(argument);
}
}
};
const removeItemOfAnArray = async function (array, item) {
for (let i = (array.length - 1); i >= 0; i--) {
if (array[i] === item) {
return array.splice(i, 1);
}
}
return array;
};
const chromeapiSerial = {
logHeader: 'SERIAL (adapted from Cordova): ',
connection: {
connectionId: 1, // Only one connection possible
paused: false,
persistent: false,
name,
bufferSize: 4096,
receiveTimeout: 0,
sendTimeout: 0,
bitrate: 9600,
dataBits: 'eight',
parityBit: 'no',
stopBits: 'one',
ctsFlowControl: false,
},
setConnectionOptions: function(ConnectionOptions) {
if (ConnectionOptions.persistent) {
this.connection.persistent = ConnectionOptions.persistent;
}
if (ConnectionOptions.name) {
this.connection.name = ConnectionOptions.name;
}
if (ConnectionOptions.bufferSize) {
this.connection.bufferSize = ConnectionOptions.bufferSize;
}
if (ConnectionOptions.receiveTimeout) {
this.connection.receiveTimeout = ConnectionOptions.receiveTimeout;
}
if (ConnectionOptions.sendTimeout) {
this.connection.sendTimeout = ConnectionOptions.sendTimeout;
}
if (ConnectionOptions.bitrate) {
this.connection.bitrate = ConnectionOptions.bitrate;
}
if (ConnectionOptions.dataBits) {
this.connection.dataBits = ConnectionOptions.dataBits;
}
if (ConnectionOptions.parityBit) {
this.connection.parityBit = ConnectionOptions.parityBit;
}
if (ConnectionOptions.stopBits) {
this.connection.stopBits = ConnectionOptions.stopBits;
}
if (ConnectionOptions.ctsFlowControl) {
this.connection.ctsFlowControl = ConnectionOptions.ctsFlowControl;
}
},
getCordovaSerialConnectionOptions: function() {
let dataBits, stopBits, parityBit;
if (this.connection.dataBits === 'seven') {
dataBits = 7;
} else {
dataBits = 8;
}
if (this.connection.stopBits === 'two') {
stopBits = 2;
} else {
stopBits = 1;
}
if (this.connection.parityBit === 'odd') {
parityBit = 0;
} else if (this.connection.parityBit === 'even') {
parityBit = 1;
}
return {
baudRate: this.connection.bitrate,
dataBits: dataBits,
stopBits: stopBits,
parity: parityBit,
sleepOnPause: false,
};
},
// Chrome serial API methods
getDevices: async function(callback) {
const self = this;
cordova.plugins.usbevent.listDevices(function(list) {
const devices = [];
if (list.devices !== undefined) {
let count = 0;
list.devices.forEach(device => {
count++;
devices.push({
path: `${device.vendorId}/${device.productId}`,
vendorId: device.vendorId,
productId: device.productId,
displayName: `${device.vendorId}/${device.productId}`,
});
if (count === list.devices.length) {
if (callback) {
callback(devices);
}
}
});
} else {
if (callback) {
callback(devices);
}
}
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
},
connect: function(path, ConnectionOptions, callback) {
const self = this;
if (typeof ConnectionOptions !== 'undefined') {
self.setConnectionOptions(ConnectionOptions);
}
const pathSplit = path.split('/');
if (pathSplit.length === 2) {
const vid = parseInt(pathSplit[0]);
const pid = parseInt(pathSplit[1]);
console.log(`${self.logHeader}request permission (vid=${vid} / pid=${pid})`);
cordova_serial.requestPermission({vid: vid, pid: pid}, function() {
const options = self.getCordovaSerialConnectionOptions();
cordova_serial.open(options, function () {
cordova_serial.registerReadCallback(function (data) {
const info = {
connectionId: self.connection.connectionId,
data: data,
};
self.onReceive.receiveData(info);
}, function () {
console.warn(`${self.logHeader}failed to register read callback`);
});
chromeCallbackWithSuccess(self.connection, callback);
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
} else {
chromeCallbackWithError(`${self.logHeader} invalid vendor id / product id`, callback);
}
},
disconnect: function(connectionId, callback) {
const self = this;
cordova_serial.close(function () {
chromeCallbackWithSuccess(true, callback);
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback(false));
});
},
setPaused: function(connectionId, paused, callback) {
this.connection.paused = paused; // Change connectionInfo but don't pause the connection
chromeCallbackWithSuccess(undefined, callback);
},
getInfo: function(callback) {
chromeCallbackWithSuccess(this.connection, callback);
},
send: function(connectionId, data, callback) {
const string = Array.prototype.map.call(new Uint8Array(data), x => (`00${x.toString(16)}`).slice(-2)).join('');
cordova_serial.writeHex(string, function () {
chromeCallbackWithSuccess({
bytesSent: string.length >> 1,
}, callback);
}, function(error) {
const info = {
bytesSent: 0,
error: 'undefined',
};
chrome.serial.onReceiveError.receiveError(info);
chromeCallbackWithError(`SERIAL (adapted from Cordova): ${error}`, callback(info));
});
},
getControlSignals: function(connectionId, callback) {
// Not supported yet
console.warn('chrome.serial.getControlSignals not supported yet');
chromeCallbackWithSuccess({}, callback);
},
setControlSignals: function(connectionId, signals, callback) {
// Not supported yet
console.warn('chrome.serial.setControlSignals not supported yet');
chromeCallbackWithSuccess({
result: false,
}, callback);
},
// update: function() { },
// getConnections: function() { },
// flush: function() { },
// setBreak: function() { },
// clearBreak: function() { },
onReceive: {
listeners: [],
addListener: function(functionReference) {
this.listeners.push(functionReference);
},
removeListener: async function(functionReference) {
this.listeners = await removeItemOfAnArray(this.listeners, functionReference);
},
receiveData: function(data) {
if (data.data.byteLength > 0) {
for (let i = (this.listeners.length - 1); i >= 0; i--) {
this.listeners[i](data);
}
}
},
},
onReceiveError: {
listeners: [],
addListener: function(functionReference) {
this.listeners.push(functionReference);
},
removeListener: async function(functionReference) {
this.listeners = await removeItemOfAnArray(this.listeners, functionReference);
},
receiveError: function(error) {
for (let i = (this.listeners.length - 1); i >= 0; i--) {
this.listeners[i](error);
}
},
},
};
const chromeapiFilesystem = {
logHeader: 'FILESYSTEM (adapted from Cordova): ',
savedEntries: [],
getFileExtension: function(fileName) {
const re = /(?:\.([^.]+))?$/;
return re.exec(fileName)[1];
},
// Chrome fileSystem API methods
getDisplayPath: function(entry, callback) {
chromeCallbackWithSuccess(entry.fullPath, callback);
},
getWritableEntry: function(entry, callback) {
// Entry returned by chooseEntry method is writable on Android
chromeCallbackWithSuccess(entry, callback);
},
isWritableEntry: function(entry, callback) {
// Entry returned by chooseEntry method is writable on Android
chromeCallbackWithSuccess(true, callback);
},
chooseEntryOpenFile: function(options, callback) {
const self = this;
fileChooser.open(function(uri) {
window.resolveLocalFileSystemURL(uri, function(entry) {
if (options.accepts && options.accepts[0].extensions && options.accepts[0].extensions && options.accepts[0].extensions.length > 0) {
self.getDisplayPath(entry, function(fileName) {
const extension = self.getFileExtension(fileName);
if (options.accepts[0].extensions.indexOf(extension) > -1) {
chromeCallbackWithSuccess(entry, callback);
} else {
navigator.notification.alert('Invalid file extension', function() {
chromeCallbackWithError(`${self.logHeader}file opened has an incorrect extension`, callback);
}, 'Choose a file', 'Ok');
}
});
} else {
console.log('no extensions : any type of file accepted');
chromeCallbackWithSuccess(entry, callback);
}
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
},
chooseEntrySaveFile: function(options, callback) {
const self = this;
if (!options.suggestedName) {
options.suggestedName = 'newfile';
}
const extension = self.getFileExtension(options.suggestedName);
const folder = 'Betaflight configurator';
navigator.notification.prompt(i18n.getMessage('dialogFileNameDescription', {
folder: folder,
}), function(res) {
if (res.buttonIndex === 1) {
const newExtension = self.getFileExtension(res.input1);
let fileName = res.input1;
if (newExtension === undefined) {
fileName += `.${extension}`;
}
window.resolveLocalFileSystemURL(cordova.file.externalRootDirectory, function(rootEntry) {
rootEntry.getDirectory(folder, { create: true }, function(directoryEntry) {
directoryEntry.getFile(fileName, { create: false }, function(fileEntry) {
console.log(fileEntry);
navigator.notification.confirm(i18n.getMessage('dialogFileAlreadyExistsDescription'), function(resp) {
if (resp === 1) {
chromeCallbackWithSuccess(fileEntry, callback);
} else {
chromeCallbackWithError(`${self.logHeader}Canceled: file already exists`, callback);
}
}, i18n.getMessage('dialogFileAlreadyExistsTitle'), [i18n.getMessage('yes'), i18n.getMessage('cancel')]);
}, function() {
directoryEntry.getFile(fileName, { create: true }, function(fileEntry) {
chromeCallbackWithSuccess(fileEntry, callback);
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
});
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
}, function(error) {
chromeCallbackWithError(self.logHeader+error, callback);
});
} else {
chromeCallbackWithError(`${self.logHeader}Canceled: no file name`, callback);
}
}, i18n.getMessage('dialogFileNameTitle'), [i18n.getMessage('initialSetupButtonSave'), i18n.getMessage('cancel')], options.suggestedName);
},
chooseEntry: function(options, callback) {
const self = this;
if (typeof options === 'undefined' || typeof options.type === 'undefined') {
self.chooseEntryOpenFile(options, callback);
} else if (options.type === 'openDirectory') {
// not supported yet
console.warn('chrome.fileSystem.chooseEntry: options.type = openDirectory not supported yet');
chromeCallbackWithSuccess(undefined, callback);
} else if (options.type === 'openWritableFile') {
// Entry returned by chooseEntry method is writable on Android
self.chooseEntryOpenFile(options, callback);
} else if (options.type === 'saveFile') {
self.chooseEntrySaveFile(options, callback);
} else {
self.chooseEntryOpenFile(options, callback);
}
},
restoreEntry: function(id, callback) {
this.isRestorable(id, function(isRestorable) {
if (isRestorable) {
chromeCallbackWithSuccess(this.savedEntries[id], callback);
} else {
chromeCallbackWithError(`${self.logHeader}This entry can't be restored`, callback);
}
});
},
isRestorable: function(id, callback) {
if (typeof this.savedEntries[id] !== 'undefined') {
chromeCallbackWithSuccess(true, callback);
} else {
chromeCallbackWithSuccess(false, callback);
}
},
retainEntry: function(entry) {
const id = this.savedEntries.length;
if (id >= 500) {
for (let i=0 ; i<500 ; i++) {
if (i < 499) {
this.savedEntries[i] = this.savedEntries[i+1];
} else {
this.savedEntries[i] = entry;
}
}
return 499;
} else {
this.savedEntries[id] = entry;
return id;
}
},
/**requestFileSystem: function(options, callback) { },
getVolumeList: function(callback) { },*/
};
const cordovaChromeapi = {
init: function(callback) {
chrome.serial = chromeapiSerial;
chrome.fileSystem = chromeapiFilesystem;
if (callback) {
callback();
}
},
};

67
src/js/cordova_startup.js vendored Normal file
View File

@ -0,0 +1,67 @@
'use strict';
const cordovaUI = {
uiZoom: 1,
canChangeUI: true,
init: async function() {
const self = this;
const screenWidth = $(window).width();
const screenHeight = $(window).height();
let length;
let orientation;
if (screenWidth > screenHeight) {
length = screenWidth;
orientation = 'landscape';
} else {
length = screenHeight;
orientation = 'portrait';
}
if (length < 1024) {
self.uiZoom = length/1024;
}
if (screenWidth > 575 && screenHeight > 575) {
self.canChangeUI = false;
}
ConfigStorage.get('cordovaForceComputerUI', function (result) {
if (result.cordovaForceComputerUI === undefined) {
if ((orientation === 'landscape' && screenHeight <= 575)
|| (orientation === 'portrait' && screenWidth <= 575)) {
ConfigStorage.set({'cordovaForceComputerUI': false});
} else {
ConfigStorage.set({'cordovaForceComputerUI': true});
}
}
});
self.set();
},
set: function() {
const self = this;
ConfigStorage.get('cordovaForceComputerUI', function (result) {
if (result.cordovaForceComputerUI) {
window.screen.orientation.lock('landscape');
$('body').css('zoom', self.uiZoom);
} else {
window.screen.orientation.lock('portrait');
$('body').css('zoom', 1);
}
});
},
};
const cordovaApp = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
$('.open_firmware_flasher, .tab_firmware_flasher').hide();
cordovaUI.init();
navigator.splashscreen.hide();
cordovaChromeapi.init();
appReady();
},
};
cordovaApp.initialize();

View File

@ -19,6 +19,7 @@ var GUI_control = function () {
'changelog',
'firmware_flasher',
'privacy_policy',
'options',
'help'
];
this.defaultAllowedFCTabsWhenConnected = [
@ -48,33 +49,51 @@ var GUI_control = function () {
this.allowedTabs = this.defaultAllowedTabsWhenDisconnected;
// check which operating system is user running
if (navigator.appVersion.indexOf("Win") != -1) this.operating_system = "Windows";
else if (navigator.appVersion.indexOf("Mac") != -1) this.operating_system = "MacOS";
else if (navigator.appVersion.indexOf("CrOS") != -1) this.operating_system = "ChromeOS";
else if (navigator.appVersion.indexOf("Linux") != -1) this.operating_system = "Linux";
else if (navigator.appVersion.indexOf("X11") != -1) this.operating_system = "UNIX";
else this.operating_system = "Unknown";
this.operating_system = GUI_checkOperatingSystem();
// Check the method of execution
this.nwGui = null;
try {
this.nwGui = require('nw.gui');
this.Mode = GUI_Modes.NWJS;
this.nwGui = require('nw.gui');
this.Mode = GUI_Modes.NWJS;
} catch (ex) {
if (window.chrome && chrome.storage && chrome.storage.local) {
this.Mode = GUI_Modes.ChromeApp;
} else {
this.Mode = GUI_Modes.Other;
}
if (typeof cordovaApp !== 'undefined') {
this.Mode = GUI_Modes.Cordova;
} else {
if (window.chrome && chrome.storage && chrome.storage.local) {
this.Mode = GUI_Modes.ChromeApp;
} else {
this.Mode = GUI_Modes.Other;
}
}
}
};
const GUI_Modes = {
NWJS: "NW.js",
ChromeApp: "Chrome",
Cordova: "Cordova",
Other: "Other"
};
function GUI_checkOperatingSystem() {
if (navigator.appVersion.indexOf("Win") !== -1) {
return "Windows";
} else if (navigator.appVersion.indexOf("Mac") !== -1) {
return "MacOS";
} else if (navigator.appVersion.indexOf("CrOS") !== -1) {
return "ChromeOS";
} else if (navigator.appVersion.indexOf("Android") !== -1) {
return "Android";
} else if (navigator.appVersion.indexOf("Linux") !== -1) {
return "Linux";
} else if (navigator.appVersion.indexOf("X11") !== -1) {
return "UNIX";
} else {
return "Unknown";
}
}
// Timer managing methods
// name = string
@ -363,13 +382,16 @@ GUI_control.prototype.selectDefaultTabWhenConnected = function() {
};
GUI_control.prototype.isChromeApp = function () {
return this.Mode == GUI_Modes.ChromeApp;
return this.Mode === GUI_Modes.ChromeApp;
};
GUI_control.prototype.isNWJS = function () {
return this.Mode == GUI_Modes.NWJS;
return this.Mode === GUI_Modes.NWJS;
};
GUI_control.prototype.isCordova = function () {
return this.Mode === GUI_Modes.Cordova;
};
GUI_control.prototype.isOther = function () {
return this.Mode == GUI_Modes.Other;
return this.Mode === GUI_Modes.Other;
};

View File

@ -51,10 +51,12 @@ i18n.init = function(cb) {
};
i18n.changeLanguage = function(languageSelected) {
ConfigStorage.set({'userLanguageSelect': languageSelected});
i18next.changeLanguage(getValidLocale(languageSelected));
i18n.selectedLanguage = languageSelected;
GUI.log(i18n.getMessage('language_changed'));
if (typeof ConfigStorage !== 'undefined') {
ConfigStorage.set({'userLanguageSelect': languageSelected});
}
i18next.changeLanguage(getValidLocale(languageSelected));
i18n.selectedLanguage = languageSelected;
GUI.log(i18n.getMessage('language_changed'));
};
i18n.getMessage = function(messageID, parameters) {
@ -159,17 +161,22 @@ i18n.localizePage = function(forceReTranslate) {
* returns the current locale to the callback
*/
function getStoredUserLocale(cb) {
ConfigStorage.get('userLanguageSelect', function (result) {
let userLanguage = 'DEFAULT';
if (result.userLanguageSelect) {
userLanguage = result.userLanguageSelect;
}
i18n.selectedLanguage = userLanguage;
if (typeof ConfigStorage !== 'undefined') {
ConfigStorage.get('userLanguageSelect', function (result) {
let userLanguage = 'DEFAULT';
if (result.userLanguageSelect) {
userLanguage = result.userLanguageSelect;
}
i18n.selectedLanguage = userLanguage;
userLanguage = getValidLocale(userLanguage);
userLanguage = getValidLocale(userLanguage);
cb(userLanguage);
});
} else {
const userLanguage = getValidLocale('DEFAULT');
cb(userLanguage);
});
}
}
function getValidLocale(userLocale) {

View File

@ -4,6 +4,12 @@ window.googleAnalytics = analytics;
window.analytics = null;
$(document).ready(function () {
if (typeof cordovaApp === 'undefined') {
appReady();
}
});
function appReady() {
$.getJSON('version.json', function(data) {
CONFIGURATOR.version = data.version;
CONFIGURATOR.gitChangesetId = data.gitChangesetId;
@ -29,7 +35,7 @@ $(document).ready(function () {
initializeSerialBackend();
});
});
});
}
function checkSetupAnalytics(callback) {
if (!analytics) {
@ -143,13 +149,17 @@ function closeSerial() {
}
function closeHandler() {
this.hide();
if (!GUI.isCordova()) {
this.hide();
}
analytics.sendEvent(analytics.EVENT_CATEGORIES.APPLICATION, 'AppClose', { sessionControl: 'end' });
closeSerial();
this.close(true);
if (!GUI.isCordova()) {
this.close(true);
}
}
//Process to execute to real start the app
@ -171,14 +181,16 @@ function startProcess() {
GUI.nwGui.Shell.openExternal(url);
});
nwWindow.on('close', closeHandler);
} else if (!GUI.isOther()) {
} else if (GUI.isChromeApp()) {
chrome.app.window.onClosed.addListener(closeHandler);
// This event does not actually get fired:
chrome.runtime.onSuspend.addListener(closeHandler);
} else if (GUI.isCordova()) {
window.addEventListener('beforeunload', closeHandler);
}
$('.connect_b a.connect').removeClass('disabled');
$('#logo .version').text(CONFIGURATOR.version);
$('#logo .version, #tab_logoversion .version').text(CONFIGURATOR.version);
updateStatusBarVersion();
updateTopBarVersion();
@ -202,6 +214,10 @@ function startProcess() {
);
});
if (GUI.isCordova()) {
UI_PHONES.init();
}
const 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
@ -274,6 +290,9 @@ function startProcess() {
case 'privacy_policy':
TABS.staticTab.initialize('privacy_policy', content_ready);
break;
case 'options':
TABS.options.initialize(content_ready);
break;
case 'firmware_flasher':
TABS.firmware_flasher.initialize(content_ready);
break;
@ -354,117 +373,6 @@ function startProcess() {
$('#tabs ul.mode-disconnected li a:first').click();
// options
$('a#options').click(function () {
const el = $(this);
if (!el.hasClass('active')) {
el.addClass('active');
el.after('<div id="options-window"></div>');
$('div#options-window').load('./tabs/options.html', function () {
// translate to user-selected language
i18n.localizePage();
ConfigStorage.get('permanentExpertMode', function (result) {
if (result.permanentExpertMode) {
$('div.permanentExpertMode input').prop('checked', true);
}
$('div.permanentExpertMode input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'permanentExpertMode': checked});
$('input[name="expertModeCheckbox"]').prop('checked', checked).change();
}).change();
});
ConfigStorage.get('rememberLastTab', function (result) {
$('div.rememberLastTab input')
.prop('checked', !!result.rememberLastTab)
.change(function() { ConfigStorage.set({rememberLastTab: $(this).is(':checked')}); })
.change();
});
if (GUI.operating_system !== 'ChromeOS') {
ConfigStorage.get('checkForConfiguratorUnstableVersions', function (result) {
if (result.checkForConfiguratorUnstableVersions) {
$('div.checkForConfiguratorUnstableVersions input').prop('checked', true);
}
$('div.checkForConfiguratorUnstableVersions input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'checkForConfiguratorUnstableVersions': checked});
checkForConfiguratorUpdates();
});
});
} else {
$('div.checkForConfiguratorUnstableVersions').hide();
}
ConfigStorage.get('analyticsOptOut', function (result) {
if (result.analyticsOptOut) {
$('div.analyticsOptOut input').prop('checked', true);
}
$('div.analyticsOptOut input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'analyticsOptOut': checked});
checkSetupAnalytics(function (analyticsService) {
if (checked) {
analyticsService.sendEvent(analyticsService.EVENT_CATEGORIES.APPLICATION, 'OptOut');
}
analyticsService.setOptOut(checked);
if (!checked) {
analyticsService.sendEvent(analyticsService.EVENT_CATEGORIES.APPLICATION, 'OptIn');
}
});
}).change();
});
$('div.cliAutoComplete input')
.prop('checked', CliAutoComplete.configEnabled)
.change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'cliAutoComplete': checked});
CliAutoComplete.setEnabled(checked);
}).change();
$('#darkThemeSelect')
.val(DarkTheme.configEnabled)
.change(function () {
const value = parseInt($(this).val());
ConfigStorage.set({'darkTheme': value});
setDarkTheme(value);
}).change();
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 () {
const element = $(this);
@ -535,22 +443,19 @@ function startProcess() {
$("#showlog").on('click', function () {
let state = $(this).data('state');
if (state) {
$("#log").animate({height: 27}, 200, function () {
setTimeout(function() {
const command_log = $('div#log');
command_log.scrollTop($('div.wrapper', command_log).height());
});
}, 200);
$("#log").removeClass('active');
$("#content").removeClass('logopen');
$(".tab_container").removeClass('logopen');
$("#tab-content-container").removeClass('logopen');
$("#scrollicon").removeClass('active');
ConfigStorage.set({'logopen': false});
state = false;
} else {
$("#log").animate({height: 111}, 200);
$("#log").addClass('active');
$("#content").addClass('logopen');
$(".tab_container").addClass('logopen');
$("#tab-content-container").addClass('logopen');
$("#scrollicon").addClass('active');
ConfigStorage.set({'logopen': true});
@ -567,11 +472,12 @@ function startProcess() {
});
ConfigStorage.get('permanentExpertMode', function (result) {
const experModeCheckbox = 'input[name="expertModeCheckbox"]';
if (result.permanentExpertMode) {
$('input[name="expertModeCheckbox"]').prop('checked', true);
$(experModeCheckbox).prop('checked', true);
}
$('input[name="expertModeCheckbox"]').change(function () {
$(experModeCheckbox).change(function () {
const checked = $(this).is(':checked');
checkSetupAnalytics(function (analyticsService) {
analyticsService.setDimension(analyticsService.DIMENSIONS.CONFIGURATOR_EXPERT_MODE, checked ? 'On' : 'Off');
@ -819,7 +725,7 @@ function updateTopBarVersion(firmwareVersion, firmwareId, hardwareId) {
const versionText = `${configuratorVersion}<br />${firmwareVersionAndId}<br />${targetVersion}`;
$('#logo .logo_text').html(versionText);
$('#logo .logo_text, #tab_logoversion .version').html(versionText);
}
function updateStatusBarVersion(firmwareVersion, firmwareId, hardwareId) {

251
src/js/main_cordova.js Normal file
View File

@ -0,0 +1,251 @@
'use strict';
const REQUIRED_WEBVIEW_VERSION = 72;
const WEBVIEW = {
chromeVersion: '',
majorChromeVersion: 0,
appsId: {
androidWebview: 'com.android.webview',
googleWebview: 'com.google.android.webview',
chrome: 'com.android.chrome',
},
apps: {
'com.android.webview': { },
'com.google.android.webview': {
name: 'Android System WebView',
displayName: 'Google Android Webview',
},
'com.android.chrome': {
name: 'Google Chrome',
displayName: 'Chrome',
},
},
matchingVersion: 0,
usedApp: null,
uptodateApps: [],
htmlElements: {
webview_step_msg: '#webview_step_msg',
webview_step_btn1: '#webview_step_btn1',
webview_step_btn2: '#webview_step_btn2',
},
advices: {
installGoogleAndroidWebview: function(callback) {
$(WEBVIEW.htmlElements.webview_step_msg).html(i18n.getMessage('cordovaWebviewInstall', {
app: WEBVIEW.apps[WEBVIEW.appsId.googleWebview].name,
}));
$('#webview_step_btn1').text(i18n.getMessage('cordovaWebviewInstallBtn'))
.attr('app_id', WEBVIEW.appsId.googleWebview);
callback();
},
updateGoogleAndroidWebview: function(callback) {
$(WEBVIEW.htmlElements.webview_step_msg).html(i18n.getMessage('cordovaWebviewUpdate', {
app: WEBVIEW.apps[WEBVIEW.appsId.googleWebview].name,
}));
$(WEBVIEW.htmlElements.webview_step_btn1).text(i18n.getMessage('cordovaWebviewUpdateBtn'))
.attr('app_id', WEBVIEW.appsId.googleWebview);
callback();
},
updateAndroidChrome: function(callback) {
$(WEBVIEW.htmlElements.webview_step_msg).html(i18n.getMessage('cordovaWebviewUpdate', {
app: WEBVIEW.apps[WEBVIEW.appsId.chrome].name,
}));
$(WEBVIEW.htmlElements.webview_step_btn1).text(i18n.getMessage('cordovaWebviewUpdateBtn'))
.attr('app_id', WEBVIEW.appsId.chrome);
callback();
},
uninstallGoogleAndroidWebview: function(callback) {
$(WEBVIEW.htmlElements.webview_step_msg).html(i18n.getMessage('cordovaWebviewUninstall', {
app: WEBVIEW.apps[WEBVIEW.appsId.googleWebview].name,
}));
$(WEBVIEW.htmlElements.webview_step_btn1).text(i18n.getMessage('cordovaWebviewUninstallBtn1'))
.attr('app_id', WEBVIEW.appsId.googleWebview);
$(WEBVIEW.htmlElements.webview_step_btn2).text(i18n.getMessage('cordovaWebviewUninstallBtn2'))
.attr('app_id', WEBVIEW.appsId.googleWebview)
.show();
callback();
},
selectWebview: function(id, callback) {
let app;
if (id === WEBVIEW.appsId.googleWebview) {
app = WEBVIEW.apps[WEBVIEW.appsId.googleWebview].displayName;
} else if (id === WEBVIEW.appsId.chrome) {
app = WEBVIEW.apps[WEBVIEW.appsId.chrome].displayName;
}
$(WEBVIEW.htmlElements.webview_step_msg).html(i18n.getMessage('cordovaWebviewEnable', {
app: app,
}));
$(WEBVIEW.htmlElements.webview_step_btn1).hide();
$(WEBVIEW.htmlElements.webview_step_btn2).text(i18n.getMessage('cordovaWebviewEnableBtn')).show();
callback();
},
},
getAdvice1: function(callback) {
const self = this;
if (self.usedApp === WEBVIEW.appsId.googleWebview) {
self.advices.updateGoogleAndroidWebview(callback);
} else if (self.usedApp === WEBVIEW.appsId.chrome) {
self.advices.updateAndroidChrome(callback);
}
},
getAdvice2: function(callback) {
const self = this;
if (self.uptodateApps.length > 0) {
self.advices.selectWebview(callback);
} else {
if ((self.apps[WEBVIEW.appsId.googleWebview].installed && self.apps[WEBVIEW.appsId.googleWebview].enabled)
&& (self.apps[WEBVIEW.appsId.chrome].installed && self.apps[WEBVIEW.appsId.chrome].enabled)) {
self.advices.uninstallGoogleAndroidWebview(callback);
} else if (!(self.apps[WEBVIEW.appsId.googleWebview].installed && self.apps[WEBVIEW.appsId.googleWebview].enabled)
&& !(self.apps[WEBVIEW.appsId.chrome].installed && self.apps[WEBVIEW.appsId.chrome].enabled)) {
self.advices.installGoogleAndroidWebview(callback);
} else {
self.getAdvice3(callback);
}
}
},
getAdvice3: function(callback) {
const self = this;
if (self.apps[WEBVIEW.appsId.googleWebview].installed && self.apps[WEBVIEW.appsId.googleWebview].enabled
&& !self.apps[WEBVIEW.appsId.googleWebview].uptodate) {
self.advices.updateGoogleAndroidWebview(callback);
} else if (self.apps[WEBVIEW.appsId.chrome].installed && self.apps[WEBVIEW.appsId.chrome].enabled
&& !self.apps[WEBVIEW.appsId.chrome].uptodate) {
self.advices.updateAndroidChrome(callback);
}
},
getAdvice: function(callback) {
const self = this;
if (self.usedApp && self.usedApp !== WEBVIEW.appsId.androidWebview) {
this.getAdvice1(callback);
} else {
this.getAdvice2(callback);
}
},
tryToFindUsedApp: function(callback) {
const self = this;
const appsId = Object.keys(self.apps);
for (let i=0; i<appsId.length; i++) {
const id = appsId[i];
if (self.matchingVersion === 1 && self.apps[id].used === 'could') {
self.apps[id].used = 'yes';
self.usedApp = id;
$(`li[app_id='${id}']`).append(` (<span style="color: green">${i18n.getMessage('cordovaWebviewUsed')}</span>)`);
}
if (i === appsId.length-1) {
callback();
}
}
},
checkInstalledApps: function(callback) {
const self = this;
const appsId = Object.keys(self.apps);
let installedApps = 0;
function checkAvailability(id, i) {
appAvailability.check(id, function(info) {
appInstalled(info, id, i);
}, function() {
appNotInstalled(id, i);
});
}
function end(i) {
if (i === appsId.length-1) {
if (installedApps === 0) {
$('#webview_apps').append('<li i18n="cordovaNoWebview" style="color: red"></li>');
}
i18n.localizePage();
console.log('callback');
callback();
}
}
function appInstalled(info, id, i) {
installedApps++;
self.apps[id].installed = true;
self.apps[id].enabled = info.enabled;
self.apps[id].version = info.version;
self.apps[id].majorVersion = parseInt(info.version.split('.')[0]);
if (self.chromeVersion === self.apps[id].version) {
self.apps[id].used = 'could';
self.matchingVersion++;
} else {
self.apps[id].used = 'no';
}
let color;
if (self.apps[id].majorVersion >= REQUIRED_WEBVIEW_VERSION) {
color = 'green';
self.apps[id].uptodate = true;
self.uptodateApps.push(id);
} else {
color = 'red';
self.apps[id].uptodate = false;
}
let app = `<li app_id="${id}">${id} (<span style="color: ${color}">${self.apps[id].version}</span>)`;
if (!self.apps[id].enabled) {
app += ' (<span i18n="portsTelemetryDisabled"></span>)';
}
app += '</li>';
$('#webview_apps').append(app);
end(i);
}
function appNotInstalled(id, i) {
self.apps[id].installed = false;
end(i);
}
for (let i=0; i<appsId.length; i++) {
const id = appsId[i];
checkAvailability(id, i);
}
},
exec: function() {
const self = this;
$('#webview_troubleshooting').hide();
$('#loading').show();
self.chromeVersion = window.navigator.appVersion.replace(/.*Chrome\/([0-9.]*).*/, "$1");
self.majorChromeVersion = self.chromeVersion.split('.')[0];
if (self.majorChromeVersion >= REQUIRED_WEBVIEW_VERSION) {
navigator.splashscreen.show();
document.location.href = 'main.html';
} else {
navigator.splashscreen.hide();
self.checkInstalledApps(function() {
self.tryToFindUsedApp(function() {
self.getAdvice(function() {
$('#loading').hide();
$('#webview_troubleshooting').show();
});
});
});
}
},
};
const cordovaApp = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
i18n.init(function() {
i18n.localizePage();
WEBVIEW.exec();
});
},
};
cordovaApp.initialize();
$(WEBVIEW.htmlElements.webview_step_btn1).on('click', function() {
const appId = $(WEBVIEW.htmlElements.webview_step_btn1).attr('app_id');
cordova.plugins.market.open(appId);
});
$(WEBVIEW.htmlElements.webview_step_btn2).on('click', function() {
if ($(WEBVIEW.htmlElements.webview_step_btn2).attr('app_id') !== undefined) {
const appId = $(WEBVIEW.htmlElements.webview_step_btn2).attr('app_id');
window.cordova.plugins.settings.open(['application_details', false, appId]);
} else {
window.cordova.plugins.settings.open('settings');
}
});

View File

@ -146,6 +146,8 @@ Model.prototype.resize = function () {
};
Model.prototype.dispose = function () {
this.renderer.forceContextLoss();
this.renderer.dispose();
if (this.canUseWebGLRenderer()) {
this.renderer.forceContextLoss();
this.renderer.dispose();
}
};

87
src/js/phones_ui.js Normal file
View File

@ -0,0 +1,87 @@
'use strict';
const UI_PHONES = {
background: '#background',
tabContainer: '.tab_container',
tabContentContainer: '#tab-content-container',
headerbar: '.headerbar',
init: function() {
const self = this;
$('#menu_btn').click(function() {
self.openSideMenu();
});
$(this.background).click(function() {
self.closeSideMenu();
});
$('#tabs a').click(function() {
if ($('.tab_container').hasClass('reveal')) {
self.closeSideMenu();
}
});
$('#reveal_btn').click(function() {
self.expandHeader();
});
$(`${this.background}, ${this.tabContainer}`).swipe( {
swipeLeft: function() {
self.closeSideMenu();
},
});
$('#side_menu_swipe').swipe( {
swipeRight: function() {
self.openSideMenu();
},
});
},
initToolbar: function() {
$('.toolbar_expand_btn').click(this.expandToolbar);
},
openSideMenu: function() {
$(this.background).fadeIn(300);
$(this.tabContainer).addClass('reveal');
},
closeSideMenu: function() {
$(this.background).fadeOut(300);
$(this.tabContainer).removeClass('reveal');
},
expandHeader: function() {
const self = this;
let expand, headerExpanded, reveal;
if (GUI.connected_to) {
expand = 'expand2';
headerExpanded = 'header_expanded2';
reveal = '.header-wrapper';
} else {
expand = 'expand';
headerExpanded = 'headerExpanded';
reveal = '#port-picker';
}
if ($(self.headerbar).hasClass(expand)) {
$(reveal).removeClass('reveal');
setTimeout(function() {
$(self.tabContentContainer).removeClass(headerExpanded);
$(self.headerbar).removeClass(expand);
}, 100);
} else {
$(self.tabContentContainer).addClass(headerExpanded);
$(self.headerbar).addClass(expand);
setTimeout(function() {
$(reveal).addClass('reveal');
}, 100);
}
},
expandToolbar: function() {
const toolbar = $('.content_toolbar.xs-compressed');
if (toolbar.length > 0) {
if ($('.content_toolbar.xs-compressed').hasClass('expanded')) {
toolbar.removeClass('expanded');
} else {
toolbar.addClass('expanded');
}
}
},
reset: function() {
$(this.tabContentContainer).removeClass('header_expanded2 header_expanded');
$('#port-picker, .header-wrapper').removeClass('reveal');
$(this.headerbar).removeClass('expand2 expand');
},
};

View File

@ -40,7 +40,7 @@ PortHandler.check = function () {
if (GUI.connected_to) {
for (var i = 0; i < removed_ports.length; i++) {
if (removed_ports[i] == GUI.connected_to) {
$('div#port-picker a.connect').click();
$('div#header_btns a.connect').click();
}
}
}
@ -116,7 +116,7 @@ PortHandler.check = function () {
// we need firmware flasher protection over here
if (GUI.active_tab != 'firmware_flasher') {
GUI.timeout_add('auto-connect_timeout', function () {
$('div#port-picker a.connect').click();
$('div#header_btns a.connect').click();
}, 100); // timeout so bus have time to initialize after being detected by the system
}
}
@ -164,7 +164,6 @@ PortHandler.check_usb_devices = function (callback) {
}
self.dfu_available = false;
}
if(callback) callback(self.dfu_available);
if (!$('option:selected', portPickerElement).data().isDFU) {

View File

@ -68,7 +68,7 @@ function initializeSerialBackend() {
// lock port select & baud while we are connecting / connected
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true);
$('div.connect_controls a.connect_state').text(i18n.getMessage('connecting'));
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
serial.connect(portName, {bitrate: selected_baud}, onOpen);
@ -107,7 +107,7 @@ function initializeSerialBackend() {
// auto-connect
ConfigStorage.get('auto_connect', function (result) {
if (result.auto_connect === 'undefined' || result.auto_connect) {
if (result.auto_connect === undefined || result.auto_connect) {
// default or enabled by user
GUI.auto_connect = true;
@ -147,6 +147,10 @@ function initializeSerialBackend() {
}
function finishClose(finishedCallback) {
if (GUI.isCordova()) {
UI_PHONES.reset();
}
var wasConnected = CONFIGURATOR.connectionValid;
analytics.sendEvent(analytics.EVENT_CATEGORIES.FLIGHT_CONTROLLER, 'Disconnected');
@ -183,7 +187,7 @@ function finishClose(finishedCallback) {
// reset connect / disconnect button
$('div.connect_controls a.connect').removeClass('active');
$('div.connect_controls a.connect_state').text(i18n.getMessage('connect'));
$('div.connect_controls div.connect_state').text(i18n.getMessage('connect'));
// reset active sensor indicators
sensor_status(0);
@ -309,7 +313,7 @@ function onOpen(openInfo) {
}
function abortConnect() {
$('div#connectbutton a.connect_state').text(i18n.getMessage('connect'));
$('div#connectbutton div.connect_state').text(i18n.getMessage('connect'));
$('div#connectbutton a.connect').removeClass('active');
// unlock port select & baud
@ -409,6 +413,7 @@ function checkReportProblems() {
});
problemDialog.showModal();
$('#dialogReportProblems').scrollTop(0);
}
processUid();
@ -456,6 +461,10 @@ function finishOpen() {
GUI.allowedTabs.splice(GUI.allowedTabs.indexOf('led_strip'), 1);
}
if (GUI.isCordova()) {
UI_PHONES.reset();
}
onConnect();
GUI.selectDefaultTabWhenConnected();
@ -474,7 +483,7 @@ function onConnect() {
$('div#flashbutton a.flash').removeClass('active');
}
GUI.timeout_remove('connecting'); // kill connecting timer
$('div#connectbutton a.connect_state').text(i18n.getMessage('disconnect')).addClass('active');
$('div#connectbutton div.connect_state').text(i18n.getMessage('disconnect')).addClass('active');
$('div#connectbutton a.connect').addClass('active');
$('#tabs ul.mode-disconnected').hide();

View File

@ -176,9 +176,13 @@ TABS.auxiliary.initialize = function (callback) {
$(elementName + ' .channel-slider').Link('lower').to($(elementName + ' .lowerLimitValue'));
$(elementName + ' .channel-slider').Link('upper').to($(elementName + ' .upperLimitValue'));
let sliderValues = [900, 1000, 1200, 1400, 1500, 1600, 1800, 2000, 2100];
if ($(window).width() < 575) {
sliderValues = [1000, 1200, 1400, 1600, 1800, 2000];
}
$(rangeElement).find(".pips-channel-range").noUiSlider_pips({
mode: 'values',
values: [900, 1000, 1200, 1400, 1500, 1600, 1800, 2000, 2100],
values: sliderValues,
density: 4,
stepped: true
});
@ -250,7 +254,7 @@ TABS.auxiliary.initialize = function (callback) {
configureRangeTemplate(auxChannelCount);
configureLinkTemplate();
var modeTableBodyElement = $('.tab-auxiliary .modes tbody')
const modeTableBodyElement = $('.tab-auxiliary .modes');
for (var modeIndex = 0; modeIndex < AUX_CONFIG.length; modeIndex++) {
var modeId = AUX_CONFIG_IDS[modeIndex];

View File

@ -111,6 +111,8 @@ TABS.cli.initialize = function (callback) {
// translate to user-selected language
i18n.localizePage();
TABS.cli.adaptPhones();
CONFIGURATOR.cliActive = true;
var textarea = $('.tab-cli textarea[name="commands"]');
@ -320,6 +322,17 @@ TABS.cli.initialize = function (callback) {
});
};
TABS.cli.adaptPhones = function() {
if ($(window).width() < 575) {
const backdropHeight = $('.note').height() + 22 + 38;
$('.backdrop').css('height', `calc(100% - ${backdropHeight}px)`);
}
if (GUI.isCordova()) {
UI_PHONES.initToolbar();
}
};
TABS.cli.history = {
history: [],
index: 0

View File

@ -593,6 +593,11 @@ TABS.led_strip.initialize = function (callback, scrollPosition) {
updateBulkCmd();
if ($(window).width() < 575) {
const gridZoom = $('.tab_title').width() / 496;
$('.mainGrid, .gridSections').css('zoom', gridZoom);
}
GUI.content_ready(callback);
}

143
src/js/tabs/options.js Normal file
View File

@ -0,0 +1,143 @@
'use strict';
TABS.options = {};
TABS.options.initialize = function (callback) {
if (GUI.active_tab !== 'options') {
GUI.active_tab = 'options';
}
$('#content').load("./tabs/options.html", function () {
i18n.localizePage();
TABS.options.initPermanentExpertMode();
TABS.options.initRememberLastTab();
TABS.options.initCheckForConfiguratorUnstableVersions();
TABS.options.initAnalyticsOptOut();
TABS.options.initCliAutoComplete();
TABS.options.initCordovaForceComputerUI();
TABS.options.initDarkTheme();
GUI.content_ready(callback);
});
};
TABS.options.cleanup = function (callback) {
if (callback) {
callback();
}
};
TABS.options.initPermanentExpertMode = function () {
ConfigStorage.get('permanentExpertMode', function (result) {
if (result.permanentExpertMode) {
$('div.permanentExpertMode input').prop('checked', true);
}
$('div.permanentExpertMode input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'permanentExpertMode': checked});
$('input[name="expertModeCheckbox"]').prop('checked', checked).change();
}).change();
});
};
TABS.options.initRememberLastTab = function () {
ConfigStorage.get('rememberLastTab', function (result) {
$('div.rememberLastTab input')
.prop('checked', !!result.rememberLastTab)
.change(function() { ConfigStorage.set({rememberLastTab: $(this).is(':checked')}); })
.change();
});
};
TABS.options.initCheckForConfiguratorUnstableVersions = function () {
if (GUI.operating_system !== 'ChromeOS') {
ConfigStorage.get('checkForConfiguratorUnstableVersions', function (result) {
if (result.checkForConfiguratorUnstableVersions) {
$('div.checkForConfiguratorUnstableVersions input').prop('checked', true);
}
$('div.checkForConfiguratorUnstableVersions input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'checkForConfiguratorUnstableVersions': checked});
checkForConfiguratorUpdates();
});
});
} else {
$('div.checkForConfiguratorUnstableVersions').hide();
}
};
TABS.options.initAnalyticsOptOut = function () {
ConfigStorage.get('analyticsOptOut', function (result) {
if (result.analyticsOptOut) {
$('div.analyticsOptOut input').prop('checked', true);
}
$('div.analyticsOptOut input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'analyticsOptOut': checked});
checkSetupAnalytics(function (analyticsService) {
if (checked) {
analyticsService.sendEvent(analyticsService.EVENT_CATEGORIES.APPLICATION, 'OptOut');
}
analyticsService.setOptOut(checked);
if (!checked) {
analyticsService.sendEvent(analyticsService.EVENT_CATEGORIES.APPLICATION, 'OptIn');
}
});
}).change();
});
};
TABS.options.initCliAutoComplete = function () {
$('div.cliAutoComplete input')
.prop('checked', CliAutoComplete.configEnabled)
.change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'cliAutoComplete': checked});
CliAutoComplete.setEnabled(checked);
}).change();
};
TABS.options.initCordovaForceComputerUI = function () {
if (GUI.isCordova() && cordovaUI.canChangeUI) {
ConfigStorage.get('cordovaForceComputerUI', function (result) {
if (result.cordovaForceComputerUI) {
$('div.cordovaForceComputerUI input').prop('checked', true);
}
$('div.cordovaForceComputerUI input').change(function () {
const checked = $(this).is(':checked');
ConfigStorage.set({'cordovaForceComputerUI': checked});
if (typeof cordovaUI.set === 'function') {
cordovaUI.set();
}
});
});
} else {
$('div.cordovaForceComputerUI').hide();
}
};
TABS.options.initDarkTheme = function () {
$('#darkThemeSelect')
.val(DarkTheme.configEnabled)
.change(function () {
const value = parseInt($(this).val());
ConfigStorage.set({'darkTheme': value});
setDarkTheme(value);
}).change();
};

View File

@ -2200,6 +2200,12 @@ TABS.osd.initialize = function (callback) {
// translate to user-selected language
i18n.localizePage();
if ($(window).width() < 390) {
const previewZoom = ($(window).width() - 30) / 360;
$('.display-layout .preview').css('zoom', previewZoom);
}
// Open modal window
OSD.GUI.fontManager = new jBox('Modal', {
width: 750,

View File

@ -2586,28 +2586,28 @@ TABS.pid_tuning.changeRatesTypeLogo = function() {
switch(self.currentRatesType) {
case self.RATES_TYPE.RACEFLIGHT:
ratesLogoElement.attr("src", "../images/rate_logos/raceflight.svg");
ratesLogoElement.attr("src", "./images/rate_logos/raceflight.svg");
break;
case self.RATES_TYPE.KISS:
ratesLogoElement.attr("src", "../images/rate_logos/kiss.svg");
ratesLogoElement.attr("src", "./images/rate_logos/kiss.svg");
break;
case self.RATES_TYPE.ACTUAL:
ratesLogoElement.attr("src", "../images/rate_logos/actual.svg");
ratesLogoElement.attr("src", "./images/rate_logos/actual.svg");
break;
case self.RATES_TYPE.QUICKRATES:
ratesLogoElement.attr("src", "../images/rate_logos/quickrates.svg");
ratesLogoElement.attr("src", "./images/rate_logos/quickrates.svg");
break;
// add future rates types here
default: // BetaFlight
ratesLogoElement.attr("src", "../images/rate_logos/betaflight.svg");
ratesLogoElement.attr("src", "./images/rate_logos/betaflight.svg");
break;
}

View File

@ -184,9 +184,11 @@ TABS.ports.initialize = function (callback, scrollPosition) {
let lastVtxControlSelected;
var ports_e = $('.tab-ports .ports');
const portIdentifierTemplateE = $('#tab-ports-templates .portIdentifier');
var port_configuration_template_e = $('#tab-ports-templates .portConfiguration');
for (var portIndex = 0; portIndex < SERIAL_CONFIG.ports.length; portIndex++) {
const portIdentifierE = portIdentifierTemplateE.clone();
var port_configuration_e = port_configuration_template_e.clone();
var serialPort = SERIAL_CONFIG.ports[portIndex];
@ -216,6 +218,7 @@ TABS.ports.initialize = function (callback, scrollPosition) {
var blackbox_baudrate_e = port_configuration_e.find('select.blackbox_baudrate');
blackbox_baudrate_e.val(blackboxBaudrate);
portIdentifierE.find('.identifier').text(portIdentifierToNameMapping[serialPort.identifier]);
port_configuration_e.find('.identifier').text(portIdentifierToNameMapping[serialPort.identifier]);
port_configuration_e.data('index', portIndex);
@ -288,6 +291,7 @@ TABS.ports.initialize = function (callback, scrollPosition) {
}
}
ports_e.find('tbody').append(portIdentifierE);
ports_e.find('tbody').append(port_configuration_e);
}

View File

@ -41,6 +41,10 @@ TABS.vtx.initialize = function (callback) {
// translate to user-selected language
i18n.localizePage();
if (GUI.isCordova()) {
UI_PHONES.initToolbar();
}
self.updating = false;
GUI.content_ready(callback);
}
@ -112,8 +116,9 @@ TABS.vtx.initialize = function (callback) {
// Load schema
const urlVtxSchema = chrome.runtime.getURL(`resources/jsonschema/vtxconfig_schema-${vtxConfig.version}.json`);
if (GUI.Mode === GUI_Modes.ChromeApp) {
if (GUI.Mode === GUI_Modes.ChromeApp || GUI.isCordova()) {
// FIXME the ChromeOs don't let us use a Schema Validator because almost all of them use eval, and/or use require
// On android : Fetch API cannot load : URL scheme "file" is not supported
callback_valid();
} else {
fetch(urlVtxSchema)

View File

@ -33,12 +33,16 @@
<link type="text/css" rel="stylesheet" href="./css/tabs/power.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/tabs/transponder.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/tabs/privacy_policy.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/tabs/options.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/opensans_webfontkit/fonts.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/dropdown-lists/css/style_lists.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./js/libraries/switchery/switchery.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./node_modules/@fortawesome/fontawesome-free/css/all.css" media="all"/>
<link type="text/css" rel="stylesheet" href="./css/dark-theme.css" media="all" disabled/>
<!-- CORDOVA_INCLUDE js/cordova_chromeapi.js -->
<!-- CORDOVA_INCLUDE js/cordova_startup.js -->
<script type="text/javascript" src="./node_modules/lru_map/lru.js"></script>
<script type="text/javascript" src="./node_modules/i18next/i18next.min.js"></script>
<script type="text/javascript" src="./node_modules/i18next-xhr-backend/i18nextXHRBackend.min.js"></script>
@ -117,6 +121,7 @@
<script type="text/javascript" src="./js/FirmwareCache.js"></script>
<script type="text/javascript" src="./js/tabs/firmware_flasher.js"></script>
<script type="text/javascript" src="./js/tabs/failsafe.js"></script>
<script type="text/javascript" src="./js/tabs/options.js"></script>
<script type="text/javascript" src="./js/LogoManager.js"></script>
<script type="text/javascript" src="./js/tabs/osd.js"></script>
<script type="text/javascript" src="./js/tabs/vtx.js"></script>
@ -127,30 +132,30 @@
<script type="text/javascript" src="./js/DarkTheme.js"></script>
<script type="text/javascript" src="./js/ConfigInserter.js"></script>
<script type="text/javascript" src="./js/TuningSliders.js"></script>
<script type="text/javascript" src="./js/phones_ui.js"></script>
<script type="text/javascript" src="./node_modules/jquery-touchswipe/jquery.touchSwipe.min.js"></script>
<title i18n="windowTitle"></title>
</head>
<body>
<div id="main-wrapper">
<div id="background"></div>
<div id="side_menu_swipe"></div>
<div class="headerbar">
<div id="menu_btn">
<em class="fas fa-bars"></em>
</div>
<div id="logo">
<div class="logo_text">
CONFIGURATOR
<div class="version"></div>
</div>
</div>
<a id="options" href="#" i18n_title="options_title"></a>
<div id="port-picker">
<div class="connect_controls" id="connectbutton">
<div class="connect_b">
<a class="connect disabled" href="#"></a>
</div>
<a class="connect_state" i18n="connect"></a>
</div>
<div class="open_firmware_flasher" id="flashbutton">
<div class="firmware_b">
<a class="flash disabled" href="#"></a>
</div>
<a class="flash_state" i18n="flashTab"></a>
<div id="port-override-option">
<label for="port-override">
<span i18n="portOverrideText">Port:</span>
<input id="port-override" type="text" value="/dev/rfcomm0"/>
</label>
</div>
<div id="portsinput">
<div class="dropdown dropdown-dark">
@ -176,32 +181,27 @@
<option value="1200">1200</option>
</select>
</div>
<div id="port-override-option">
<label for="port-override"><span i18n="portOverrideText">Port:</span> <input id="port-override" type="text"
value="/dev/rfcomm0"/></label>
</div>
<div id="autoConnectSwitch">
<label><input class="auto_connect togglesmall" type="checkbox"/><span
class="auto_connect" i18n="autoConnect"></span></label>
class="auto_connect" i18n="autoConnect"></span></label>
</div>
</div>
</div>
<div class="header-wrapper">
<div id="dataflash_wrapper_global">
<div class="noflash_global" align="center" i18n="sensorDataFlashNotFound"></div>
<ul class="dataflash-contents_global">
<li class="dataflash-free_global">
<div class="legend" i18n="sensorDataFlashFreeSpace"></div>
</li>
</ul>
<div id="expertMode" align="center">
<label>
<input name="expertModeCheckbox" class="togglesmall" type="checkbox"/>
<span i18n="expertMode"></span>
</label>
<div id="quad-status_wrapper">
<div class="battery-icon">
<div class="quad-status-contents">
<div class="battery-status"></div>
</div>
</div>
<div class="battery-legend">Battery voltage</div>
<div class="bottomStatusIcons">
<div class="armedicon cf_tip" i18n_title="mainHelpArmed"></div>
<div class="failsafeicon cf_tip" i18n_title="mainHelpFailsafe"></div>
<div class="linkicon cf_tip" i18n_title="mainHelpLink"></div>
</div>
</div>
<div id="sensor-status" class="sensor_state mode-connected">
<div id="sensor-status" class="sensor_state mode-connected">
<ul>
<li class="gyro" i18n_title="sensorStatusGyro">
<div class="gyroicon" i18n="sensorStatusGyroShort"></div>
@ -223,22 +223,39 @@
</li>
</ul>
</div>
<div id="quad-status_wrapper">
<div class="battery-icon">
<div class="quad-status-contents">
<div class="battery-status"></div>
</div>
</div>
<div class="battery-legend">Battery voltage</div>
<div class="bottomStatusIcons">
<div class="armedicon cf_tip" i18n_title="mainHelpArmed"></div>
<div class="failsafeicon cf_tip" i18n_title="mainHelpFailsafe"></div>
<div class="linkicon cf_tip" i18n_title="mainHelpLink"></div>
<div id="dataflash_wrapper_global">
<div class="noflash_global" align="center" i18n="sensorDataFlashNotFound"></div>
<ul class="dataflash-contents_global">
<li class="dataflash-free_global">
<div class="legend" i18n="sensorDataFlashFreeSpace"></div>
</li>
</ul>
<div id="expertMode" align="center">
<label>
<input name="expertModeCheckbox" class="togglesmall" type="checkbox"/>
<span i18n="expertMode"></span>
</label>
</div>
</div>
</div>
<div id="header_btns">
<div class="open_firmware_flasher" id="flashbutton">
<div class="firmware_b">
<a class="flash disabled" href="#"></a>
</div>
<div class="flash_state" i18n="flashTab"></div>
</div>
<div class="connect_controls" id="connectbutton">
<div class="connect_b">
<a class="connect disabled" href="#"></a>
</div>
<div class="connect_state" i18n="connect"></div>
</div>
</div>
<div id="reveal_btn">
<em class="fas fa-ellipsis-v"></em>
</div>
</div>
<div class="clear-both"></div>
<div id="log">
<div class="logswitch">
<a href="#" id="showlog" i18n="logActionShow"></a>
@ -246,67 +263,76 @@
<div id="scrollicon"></div>
<div class="wrapper"></div>
</div>
<div class="tab_container">
<div id="tabs">
<ul class="mode-disconnected">
<li class="tab_landing" id="tab_landing"><a href="#" i18n="tabLanding" class="tabicon ic_welcome" i18n_title="tabLanding"></a>
</li>
<li class="tab_changelog"><a href="#" class="tabicon ic_help" i18n="tabChangelog"></a></li>
<li class="tab_privacy_policy"><a href="#" class="tabicon ic_help" i18n="tabPrivacyPolicy"></a></li>
<li class="tab_help" id="tab_help"><a href="#" i18n="tabHelp" class="tabicon ic_help"
i18n_title="tabHelp"></a></li>
<li class="tab_firmware_flasher" id="tabFirmware"><a href="#" i18n="tabFirmwareFlasher" class="tabicon ic_flasher"
i18n_title="tabFirmwareFlasher"></a></li>
</ul>
<ul class="mode-connected">
<li class="tab_setup"><a href="#" i18n="tabSetup" class="tabicon ic_setup" i18n_title="tabSetup"></a></li>
<li class="tab_setup_osd"><a href="#" i18n="tabSetupOSD" class="tabicon ic_setup" i18n_title="tabSetupOSD"></a></li>
<div id="tab-content-container">
<div class="tab_container">
<div id="tab_logoversion">
<div class="logo_text">
<div class="version"></div>
</div>
</div>
<div id="tabs">
<ul class="mode-disconnected">
<li class="tab_landing" id="tab_landing"><a href="#" i18n="tabLanding" class="tabicon ic_welcome" i18n_title="tabLanding"></a>
</li>
<li class="tab_changelog"><a href="#" class="tabicon ic_help" i18n="tabChangelog"></a></li>
<li class="tab_privacy_policy"><a href="#" class="tabicon ic_help" i18n="tabPrivacyPolicy"></a></li>
<li class="tab_help" id="tab_help"><a href="#" i18n="tabHelp" class="tabicon ic_help"
i18n_title="tabHelp"></a></li>
<li class="tab_options" id="tab_options"><a href="#" i18n="tabOptions" class="tabicon ic_config" i18n_title="tabOptions"></a>
</li>
<li class="tab_firmware_flasher" id="tabFirmware"><a href="#" i18n="tabFirmwareFlasher" class="tabicon ic_flasher"
i18n_title="tabFirmwareFlasher"></a></li>
</ul>
<ul class="mode-connected">
<li class="tab_setup"><a href="#" i18n="tabSetup" class="tabicon ic_setup" i18n_title="tabSetup"></a></li>
<li class="tab_setup_osd"><a href="#" i18n="tabSetupOSD" class="tabicon ic_setup" i18n_title="tabSetupOSD"></a></li>
<li class="tab_ports"><a href="#" i18n="tabPorts" class="tabicon ic_ports" i18n_title="tabPorts"></a></li>
<li class="tab_configuration"><a href="#" i18n="tabConfiguration" class="tabicon ic_config"
i18n_title="tabConfiguration"></a></li>
<li class="tab_power"><a href="#" i18n="tabPower" class="tabicon ic_power"
i18n_title="tabPower"></a></li>
<li class="tab_failsafe"><a href="#" i18n="tabFailsafe" class="tabicon ic_failsafe"
i18n_title="tabFailsafe"></a></li>
<li class="tab_pid_tuning"><a href="#" i18n="tabPidTuning" class="tabicon ic_pid"
i18n_title="tabPidTuning"></a></li>
<li class="tab_receiver"><a href="#" i18n="tabReceiver" class="tabicon ic_rx" i18n_title="tabReceiver"></a></li>
<li class="tab_auxiliary"><a href="#" i18n="tabAuxiliary" class="tabicon ic_modes" i18n_title="tabAuxiliary"></a>
</li>
<li class="tab_adjustments"><a href="#" i18n="tabAdjustments" class="tabicon ic_adjust"
i18n_title="tabAdjustments"></a></li>
<li class="tab_servos"><a href="#" i18n="tabServos" class="tabicon ic_servo" i18n_title="tabServos"></a></li>
<li class="tab_gps"><a href="#" i18n="tabGPS" class="tabicon ic_gps" i18n_title="tabGPS"></a></li>
<li class="tab_motors"><a href="#" i18n="tabMotorTesting" class="tabicon ic_motor" i18n_title="tabMotorTesting"></a>
</li>
<li class="tab_osd"><a href="#" i18n="tabOsd" class="tabicon ic_osd" i18n_title="tabOsd"></a></li>
<li class="tab_vtx"><a href="#" i18n="tabVtx" class="tabicon ic_vtx" i18n_title="tabVtx"></a></li>
<li class="tab_transponder"><a href="#" i18n="tabTransponder" class="tabicon ic_transponder"
i18n_title="tabTransponder"></a></li>
<li class="tab_led_strip"><a href="#" i18n="tabLedStrip" class="tabicon ic_led" i18n_title="tabLedStrip"></a>
</li>
<li class="tab_sensors"><a href="#" i18n="tabRawSensorData" class="tabicon ic_sensors"
i18n_title="tabRawSensorData"></a></li>
<li class="tab_logging"><a href="#" i18n="tabLogging" class="tabicon ic_log"
i18n_title="tabLogging"></a></li>
<li class="tab_onboard_logging"><a href="#" i18n="tabOnboardLogging" class="tabicon ic_data"
i18n_title="tabOnboardLogging"></a></li>
<!-- spare icons
<li class=""><a href="#"class="tabicon ic_mission">Mission (spare icon)</a></li>
<li class=""><a href="#"class="tabicon ic_advanced">Advanced (spare icon)</a></li>
<li class=""><a href="#"class="tabicon ic_wizzard">Wizzard (spare icon)</a></li>
-->
</ul>
<ul class="mode-connected mode-connected-cli">
<li class="tab_cli">
<a href="#" i18n="tabCLI" class="tabicon ic_cli" i18n_title="tabCLI"></a>
</li>
</ul>
<li class="tab_ports"><a href="#" i18n="tabPorts" class="tabicon ic_ports" i18n_title="tabPorts"></a></li>
<li class="tab_configuration"><a href="#" i18n="tabConfiguration" class="tabicon ic_config"
i18n_title="tabConfiguration"></a></li>
<li class="tab_power"><a href="#" i18n="tabPower" class="tabicon ic_power"
i18n_title="tabPower"></a></li>
<li class="tab_failsafe"><a href="#" i18n="tabFailsafe" class="tabicon ic_failsafe"
i18n_title="tabFailsafe"></a></li>
<li class="tab_pid_tuning"><a href="#" i18n="tabPidTuning" class="tabicon ic_pid"
i18n_title="tabPidTuning"></a></li>
<li class="tab_receiver"><a href="#" i18n="tabReceiver" class="tabicon ic_rx" i18n_title="tabReceiver"></a></li>
<li class="tab_auxiliary"><a href="#" i18n="tabAuxiliary" class="tabicon ic_modes" i18n_title="tabAuxiliary"></a>
</li>
<li class="tab_adjustments"><a href="#" i18n="tabAdjustments" class="tabicon ic_adjust"
i18n_title="tabAdjustments"></a></li>
<li class="tab_servos"><a href="#" i18n="tabServos" class="tabicon ic_servo" i18n_title="tabServos"></a></li>
<li class="tab_gps"><a href="#" i18n="tabGPS" class="tabicon ic_gps" i18n_title="tabGPS"></a></li>
<li class="tab_motors"><a href="#" i18n="tabMotorTesting" class="tabicon ic_motor" i18n_title="tabMotorTesting"></a>
</li>
<li class="tab_osd"><a href="#" i18n="tabOsd" class="tabicon ic_osd" i18n_title="tabOsd"></a></li>
<li class="tab_vtx"><a href="#" i18n="tabVtx" class="tabicon ic_vtx" i18n_title="tabVtx"></a></li>
<li class="tab_transponder"><a href="#" i18n="tabTransponder" class="tabicon ic_transponder"
i18n_title="tabTransponder"></a></li>
<li class="tab_led_strip"><a href="#" i18n="tabLedStrip" class="tabicon ic_led" i18n_title="tabLedStrip"></a>
</li>
<li class="tab_sensors"><a href="#" i18n="tabRawSensorData" class="tabicon ic_sensors"
i18n_title="tabRawSensorData"></a></li>
<li class="tab_logging"><a href="#" i18n="tabLogging" class="tabicon ic_log"
i18n_title="tabLogging"></a></li>
<li class="tab_onboard_logging"><a href="#" i18n="tabOnboardLogging" class="tabicon ic_data"
i18n_title="tabOnboardLogging"></a></li>
<!-- spare icons
<li class=""><a href="#"class="tabicon ic_mission">Mission (spare icon)</a></li>
<li class=""><a href="#"class="tabicon ic_advanced">Advanced (spare icon)</a></li>
<li class=""><a href="#"class="tabicon ic_wizzard">Wizzard (spare icon)</a></li>
-->
</ul>
<ul class="mode-connected mode-connected-cli">
<li class="tab_cli">
<a href="#" i18n="tabCLI" class="tabicon ic_cli" i18n_title="tabCLI"></a>
</li>
</ul>
</div>
<div class="clear-both"></div>
</div>
<div class="clear-both"></div>
<div id="content"></div>
</div>
<div id="content"></div>
<div id="status-bar">
<div>
<span i18n="statusbar_port_utilization"></span> <span class="port_usage_down">D: 0%</span> <span
@ -401,5 +427,6 @@
</div>
</dialog>
<!-- CORDOVA_INCLUDE cordova.js -->
</body>
</html>

48
src/main_cordova.html Normal file
View File

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Betaflight configurator</title>
<link type="text/css" rel="stylesheet" href="./css/main_cordova.css"/>
<link type="text/css" rel="stylesheet" href="./node_modules/@fortawesome/fontawesome-free/css/all.css" media="all"/>
</head>
<body>
<div id="headerbar">
<img src="images/light-wide-2-compact.svg" alt="" />
</div>
<div id="loading">
<img src="images/loading-spin.svg" alt="" />
<p i18n="cordovaCheckingWebview"></p>
</div>
<div id="webview_troubleshooting">
<div class="box">
<div class="box_titlebar warning">
<em class="fas fa-exclamation-triangle"></em> <span i18n="cordovaIncompatibleWebview"></span>
</div>
<div class="box_body">
<p i18n="cordovaWebviewTroubleshootingMsg"></p>
<p i18n="cordovaWebviewTroubleshootingMsg2"></p>
<div class="divider"></div>
<p id="webview_step_msg"></p>
<button id="webview_step_btn1" class="btn" type="button"></button>
<button id="webview_step_btn2" class="btn" type="button"></button>
</div>
</div>
<div class="box">
<div class="box_titlebar">
<em class="fas fa-info-circle"></em> <span i18n="cordovaAvailableWebviews"></span>
</div>
<div class="box_body">
<ul id="webview_apps"></ul>
</div>
</div>
</div>
<script type="text/javascript" src="./node_modules/jquery/dist/jquery.min.js"></script>
<script type="text/javascript" src="./node_modules/i18next/i18next.min.js"></script>
<script type="text/javascript" src="./node_modules/i18next-xhr-backend/i18nextXHRBackend.min.js"></script>
<script type="text/javascript" src="./js/localization.js"></script>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="./js/main_cordova.js"></script>
</body>
</html>

View File

@ -14,20 +14,22 @@
</ul>
</div>
<table class="adjustments">
<thead>
<div class="overflow">
<table class="adjustments">
<thead>
<tr>
<td class="column-enable" i18n="adjustmentsColumnEnable"></td>
<td i18n="adjustmentsColumnWhenChannel"></td>
<td i18n="adjustmentsColumnIsInRange"></td>
<td i18n="adjustmentsColumnIsInRange" class="range"></td>
<td i18n="adjustmentsColumnThenApplyFunction"></td>
<td class="adjustmentSlotHeader" i18n="adjustmentsColumnUsingSlot"></td>
<td i18n="adjustmentsColumnViaChannel"></td>
</tr>
</thead>
<tbody>
</tbody>
</table>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="content_toolbar">
<div class="btn save_btn">

View File

@ -15,10 +15,7 @@
</form>
</div>
<table class="modes">
<tbody>
</tbody>
</table>
<div class="modes"></div>
</div>
<div class="content_toolbar">
<div class="btn save_btn">
@ -27,20 +24,24 @@
</div>
</div>
<div id="tab-auxiliary-templates">
<table class="modes">
<tbody>
<tr class="mode">
<td class="info">
<p class="name"></p>
<div class="buttons">
<a class="addLink" href="#" i18n="auxiliaryAddLink"></a>
<a class="addRange" href="#" i18n="auxiliaryAddRange"></a>
</div>
</td>
<td class="ranges"></td>
</tr>
</tbody>
</table>
<div class="modes">
<div class="mode">
<div class="info">
<p class="name"></p>
<div class="buttons">
<a class="addLink sm-min" href="#" i18n="auxiliaryAddLink"></a>
<a class="addRange sm-min" href="#" i18n="auxiliaryAddRange"></a>
<a class="addLink xs" href="#">
<em class="fas fa-link"></em>
</a>
<a class="addRange xs" href="#">
<em class="fas fa-plus"></em>
</a>
</div>
</div>
<div class="ranges"></div>
</div>
</div>
<div class="range">
<div class="channelInfo">
<div class="channelName">

View File

@ -1,4 +1,4 @@
<div class="tab-cli">
<div class="tab-cli toolbar_fixed_bottom">
<div class="content_wrapper">
<div class="note">
<p i18n="cliInfo"></p>
@ -11,15 +11,25 @@
</div>
<textarea name="commands" i18n_placeholder="cliInputPlaceholder" rows="1" cols="0"></textarea>
</div>
<div class="content_toolbar">
<div class="btn save_btn pull-right">
<div class="content_toolbar xs-compressed">
<div class="btn save_btn">
<a class="save" href="#" i18n="cliSaveToFileBtn"></a>
</div>
<div class="btn save_btn">
<a class="load" href="#" i18n="cliLoadFromFileBtn"></a>
</div>
<div class="btn save_btn">
<a class="clear" href="#" i18n="cliClearOutputHistoryBtn"></a>
</div>
<div class="btn save_btn">
<a class="copy" href="#" i18n="cliCopyToClipboardBtn"></a>
</div>
</div>
<div class="toolbar_expand_btn" nbrow="2">
<em class="fas fa-ellipsis-h"></em>
</div>
<!-- Snippet preview dialog -->
<div id="snippetpreviewcontent" style="display: none">
<div class="note">

File diff suppressed because it is too large Load Diff

View File

@ -7,190 +7,192 @@
<div class="note">
<p i18n="failsafeFeaturesHelpNew"></p>
</div>
<div class="leftWrapper">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafePulsrangeTitle"></div>
<div class="helpicon cf_tip" i18n_title="failsafePulsrangeHelp"></div>
</div>
<div class="spacer_box">
<div class="number">
<label> <input type="number" name="rx_min_usec" min="750" max="2250" /> <span
i18n="failsafeRxMinUsecItem"></span>
</label>
<div class="grid-row">
<div class="grid-col col6">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafePulsrangeTitle"></div>
<div class="helpicon cf_tip" i18n_title="failsafePulsrangeHelp"></div>
</div>
<div class="number">
<label> <input type="number" name="rx_max_usec" min="750" max="2250" /> <span
i18n="failsafeRxMaxUsecItem"></span>
</label>
<div class="spacer_box">
<div class="number">
<label> <input type="number" name="rx_min_usec" min="750" max="2250" /> <span
i18n="failsafeRxMinUsecItem"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="rx_max_usec" min="750" max="2250" /> <span
i18n="failsafeRxMaxUsecItem"></span>
</label>
</div>
</div>
</div>
<div class="gui_box grey stage1">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafeChannelFallbackSettingsTitle"></div>
<div class="helpicon cf_tip" i18n_title="failsafeChannelFallbackSettingsHelp"></div>
</div>
<div class="spacer_box">
<div class="activechannellist">
<!-- list generated here -->
</div>
</div>
</div>
</div>
<div class="gui_box grey stage1">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafeChannelFallbackSettingsTitle"></div>
<div class="helpicon cf_tip" i18n_title="failsafeChannelFallbackSettingsHelp"></div>
</div>
<div class="spacer_box">
<div class="activechannellist">
<!-- list generated here -->
<div class="grid-col col6">
<div class="gui_box grey failsafe_switch">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafeSwitchTitle"></div>
</div>
<div class="spacer_box">
<div class="number">
<label>
<select class="switchMode" name="failsafe_switch_mode">
<option value="0" i18n="failsafeSwitchOptionStage1"></option>
<option value="2" i18n="failsafeSwitchOptionStage2"></option>
<option value="1" i18n="failsafeSwitchOptionKill"></option>
</select>
<span i18n="failsafeSwitchModeItem"></span>
<div class="helpicon cf_tip" i18n_title="failsafeSwitchModeHelp"></div>
</label>
</div>
</div>
</div>
</div>
</div>
<div class="rightWrapper">
<div class="gui_box grey failsafe_switch">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafeSwitchTitle"></div>
</div>
<div class="spacer_box">
<div class="number">
<label>
<select class="switchMode" name="failsafe_switch_mode">
<option value="0" i18n="failsafeSwitchOptionStage1"></option>
<option value="2" i18n="failsafeSwitchOptionStage2"></option>
<option value="1" i18n="failsafeSwitchOptionKill"></option>
</select>
<span i18n="failsafeSwitchModeItem"></span>
<div class="helpicon cf_tip" i18n_title="failsafeSwitchModeHelp"></div>
</label>
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafeStageTwoSettingsTitle"></div>
</div>
</div>
</div>
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="failsafeStageTwoSettingsTitle"></div>
</div>
<div class="spacer_box">
<table>
<tbody class="featuresNew rxFailsafe">
<div class="spacer_box">
<table>
<tbody class="featuresNew rxFailsafe">
<!-- table generated here -->
</tbody>
</table>
<div class="checkbox stage2 kill_switch">
<div class="numberspacer" >
<input type="checkbox" name="failsafe_kill_switch" class="toggle" id="failsafe_kill_switch" />
</div>
<label for="failsafe_kill_switch"><span i18n="failsafeKillSwitchItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeKillSwitchHelp"></div>
</div>
<div class="number stage2">
<label> <input type="number" name="failsafe_delay" min="0" max="200" /> <span
i18n="failsafeDelayItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeDelayHelp"></div>
</div>
<div class="number stage2">
<label> <input type="number" name="failsafe_throttle_low_delay" min="0" max="300" /> <span
i18n="failsafeThrottleLowItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeThrottleLowHelp"></div>
</div>
<!-- radio buttons -->
<div class="subline stage2" i18n="failsafeSubTitle1"></div>
<div class="radioarea pro1 stage2">
<div class="radiobuttons"><input class="procedure" id="drop" name="group1" type="radio"/>
<label for="drop" i18n="failsafeProcedureItemSelect2"></label>
</div>
</div>
<div class="radioarea pro2 stage2">
<div class="radiobuttons"><input class="procedure" id="land" name="group1" type="radio" checked/>
<label for="land" i18n="failsafeProcedureItemSelect1"></label>
</div>
<div class="proceduresettings">
<div class="number">
<label> <input type="number" name="failsafe_throttle" min="0" max="2000" /> <span
i18n="failsafeThrottleItem"></span>
</label>
</tbody>
</table>
<div class="checkbox stage2 kill_switch">
<div class="numberspacer" >
<input type="checkbox" name="failsafe_kill_switch" class="toggle" id="failsafe_kill_switch" />
</div>
<div class="number">
<label> <input type="number" name="failsafe_off_delay" min="0" max="200" /> <span
i18n="failsafeOffDelayItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeOffDelayHelp"></div>
<label for="failsafe_kill_switch"><span i18n="failsafeKillSwitchItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeKillSwitchHelp"></div>
</div>
<div class="number stage2">
<label> <input type="number" name="failsafe_delay" min="0" max="200" /> <span
i18n="failsafeDelayItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeDelayHelp"></div>
</div>
<div class="number stage2">
<label> <input type="number" name="failsafe_throttle_low_delay" min="0" max="300" /> <span
i18n="failsafeThrottleLowItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeThrottleLowHelp"></div>
</div>
<!-- radio buttons -->
<div class="subline stage2" i18n="failsafeSubTitle1"></div>
<div class="radioarea pro1 stage2">
<div class="radiobuttons"><input class="procedure" id="drop" name="group1" type="radio"/>
<label for="drop" i18n="failsafeProcedureItemSelect2"></label>
</div>
</div>
</div>
<div class="radioarea pro4 stage2">
<div class="radiobuttons"><input class="procedure" id="gps_rescue" name="group1" type="radio" checked/>
<label for="gps_rescue" i18n="failsafeProcedureItemSelect4"></label>
<div class="radioarea pro2 stage2">
<div class="radiobuttons"><input class="procedure" id="land" name="group1" type="radio" checked/>
<label for="land" i18n="failsafeProcedureItemSelect1"></label>
</div>
<div class="proceduresettings">
<div class="number">
<label> <input type="number" name="failsafe_throttle" min="0" max="2000" /> <span
i18n="failsafeThrottleItem"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="failsafe_off_delay" min="0" max="200" /> <span
i18n="failsafeOffDelayItem"></span>
</label>
<div class="helpicon cf_tip" i18n_title="failsafeOffDelayHelp"></div>
</div>
</div>
</div>
<div class="proceduresettings">
<div class="number">
<label> <input type="number" name="gps_rescue_angle" min="0" max="200" /> <span
i18n="failsafeGpsRescueItemAngle"></span>
</label>
<div class="radioarea pro4 stage2">
<div class="radiobuttons"><input class="procedure" id="gps_rescue" name="group1" type="radio" checked/>
<label for="gps_rescue" i18n="failsafeProcedureItemSelect4"></label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_initial_altitude" min="20" max="100" /> <span
i18n="failsafeGpsRescueItemInitialAltitude"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_descent_distance" min="30" max="500" /> <span
i18n="failsafeGpsRescueItemDescentDistance"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_ground_speed" min="0.30" max="30.00" step="0.01"/> <span
i18n="failsafeGpsRescueItemGroundSpeed"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_throttle_min" min="1000" max="2000" /> <span
i18n="failsafeGpsRescueItemThrottleMin"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_throttle_max" min="1000" max="2000" /> <span
i18n="failsafeGpsRescueItemThrottleMax"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_throttle_hover" min="1000" max="2000" /> <span
i18n="failsafeGpsRescueItemThrottleHover"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_ascend_rate" min="1.00" max="25.00" step="0.01" /> <span
i18n="failsafeGpsRescueItemAscendRate"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_descend_rate" min="1.00" max="5.00" step="0.01" /> <span
i18n="failsafeGpsRescueItemDescendRate"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_min_sats" min="5" max="50" /> <span
i18n="failsafeGpsRescueItemMinSats"></span>
</label>
</div>
<div class="number">
<label> <input type="checkbox" name="gps_rescue_allow_arming_without_fix" class="toggle" /> <span
i18n="failsafeGpsRescueItemAllowArmingWithoutFix"></span>
</label>
</div>
<div class="number">
<label>
<select class="switchMode" name="gps_rescue_altitude_mode">
<option value="0" i18n="failsafeGpsRescueItemAltitudeModeMaxAlt"></option>
<option value="1" i18n="failsafeGpsRescueItemAltitudeModeFixedAlt"></option>
<option value="2" i18n="failsafeGpsRescueItemAltitudeModeCurrentAlt"></option>
</select>
<span i18n="failsafeGpsRescueItemAltitudeMode"></span>
</label>
</div>
<div class="number">
<label>
<select class="switchMode" name="gps_rescue_sanity_checks">
<option value="0" i18n="failsafeGpsRescueItemSanityChecksOff"></option>
<option value="1" i18n="failsafeGpsRescueItemSanityChecksOn"></option>
<option value="2" i18n="failsafeGpsRescueItemSanityChecksFSOnly"></option>
</select>
<span i18n="failsafeGpsRescueItemSanityChecks"></span>
</label>
<div class="proceduresettings">
<div class="number">
<label> <input type="number" name="gps_rescue_angle" min="0" max="200" /> <span
i18n="failsafeGpsRescueItemAngle"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_initial_altitude" min="20" max="100" /> <span
i18n="failsafeGpsRescueItemInitialAltitude"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_descent_distance" min="30" max="500" /> <span
i18n="failsafeGpsRescueItemDescentDistance"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_ground_speed" min="0.30" max="30.00" step="0.01"/> <span
i18n="failsafeGpsRescueItemGroundSpeed"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_throttle_min" min="1000" max="2000" /> <span
i18n="failsafeGpsRescueItemThrottleMin"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_throttle_max" min="1000" max="2000" /> <span
i18n="failsafeGpsRescueItemThrottleMax"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_throttle_hover" min="1000" max="2000" /> <span
i18n="failsafeGpsRescueItemThrottleHover"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_ascend_rate" min="1.00" max="25.00" step="0.01" /> <span
i18n="failsafeGpsRescueItemAscendRate"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_descend_rate" min="1.00" max="5.00" step="0.01" /> <span
i18n="failsafeGpsRescueItemDescendRate"></span>
</label>
</div>
<div class="number">
<label> <input type="number" name="gps_rescue_min_sats" min="5" max="50" /> <span
i18n="failsafeGpsRescueItemMinSats"></span>
</label>
</div>
<div class="number">
<label> <input type="checkbox" name="gps_rescue_allow_arming_without_fix" class="toggle" /> <span
i18n="failsafeGpsRescueItemAllowArmingWithoutFix"></span>
</label>
</div>
<div class="number">
<label>
<select class="switchMode" name="gps_rescue_altitude_mode">
<option value="0" i18n="failsafeGpsRescueItemAltitudeModeMaxAlt"></option>
<option value="1" i18n="failsafeGpsRescueItemAltitudeModeFixedAlt"></option>
<option value="2" i18n="failsafeGpsRescueItemAltitudeModeCurrentAlt"></option>
</select>
<span i18n="failsafeGpsRescueItemAltitudeMode"></span>
</label>
</div>
<div class="number">
<label>
<select class="switchMode" name="gps_rescue_sanity_checks">
<option value="0" i18n="failsafeGpsRescueItemSanityChecksOff"></option>
<option value="1" i18n="failsafeGpsRescueItemSanityChecksOn"></option>
<option value="2" i18n="failsafeGpsRescueItemSanityChecksFSOnly"></option>
</select>
<span i18n="failsafeGpsRescueItemSanityChecks"></span>
</label>
</div>
</div>
</div>
</div>

View File

@ -6,8 +6,8 @@
</div>
<div class="cf_column fourth">
<div class="spacer_right">
<div class="grid-row">
<div class="grid-col col3">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="gpsHead"></div>
@ -46,10 +46,8 @@
</div>
</div>
</div>
</div>
<div class="cf_column fourth">
<div class="spacer_right">
<div class="gui_box grey" style="margin-bottom: -5px;">
<div class="grid-col col3">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="gpsSignalStrHead"></div>
</div>
@ -144,26 +142,26 @@
</div>
</div>
</div>
</div>
<div class="cf_column half">
<div class="gui_box grey gps_map">
<div class="gui_box_titlebar" style="margin-bottom: 0px;">
<div class="grid-col col6">
<div class="gui_box grey gps_map">
<div class="gui_box_titlebar" style="margin-bottom: 0px;">
<div class="spacer_box_title" i18n="gpsMapHead"></div>
</div>
<div id="connect" i18n="gpsMapMessage1">
<div class="default_btn" style="width:50px; margin-left:auto; margin-right:auto; float:none;"><a id="check">retry</a></div>
</div>
<div id="waiting" >
<div class="info" i18n="gpsMapMessage2"></span>
</div>
</div>
<div id="loadmap">
<webview id="map" class="map" src="tabs/map.html" partition="persist:map"></webview>
<div class="controls">
<a href="#" id="zoom_in">+</a>
<a href="#" id="zoom_out"></a>
</div>
</div>
<div id="connect" i18n="gpsMapMessage1">
<div class="default_btn" style="width:50px; margin-left:auto; margin-right:auto; float:none;"><a id="check">retry</a></div>
</div>
<div id="waiting" >
<div class="info" i18n="gpsMapMessage2"></span>
</div>
</div>
<div id="loadmap">
<webview id="map" class="map" src="tabs/map.html" partition="persist:map"></webview>
<div class="controls">
<a href="#" id="zoom_in">+</a>
<a href="#" id="zoom_out"></a>
</div>
</div>
</div>
</div>
</div>

View File

@ -1,6 +1,6 @@
<div class="tab-help">
<div class="content_wrapper">
<div class="cf_column twothird">
<div class="content_wrapper grid-row">
<div class="grid-col col8">
<div class="gui_box">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="defaultDocumentationHead"></div>
@ -14,7 +14,7 @@
</div>
</div>
</div>
<div class="cf_column third_right">
<div class="grid-col col4">
<div class="gui_box">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="defaultSupportHead"></div>

View File

@ -2,24 +2,25 @@
<div class="content_wrapper">
<div class="content_top">
<div class="logowrapper" align="center">
<img src="../images/cf_logo_white.svg" alt="" />
<img src="./images/cf_logo_white.svg" alt="" />
<div class="" i18n="defaultWelcomeIntro" align="center"></div>
</div>
</div>
<div class="content_mid">
<div class="column third_left text1">
<div class="content_mid grid-row">
<div class="column third_left text1 grid-col col4">
<div class="wrap">
<h2 i18n="defaultWelcomeHead"></h2>
<div i18n="defaultWelcomeText"></div>
</div>
</div>
<div class="column third_center text2">
<div class="column third_center text2 grid-col col5">
<div class="wrap">
<h2 i18n="defaultContributingHead"></h2>
<div i18n="defaultContributingText"></div>
</div>
</div>
<div class="column third_right text3">
<div class="column third_right text3 grid-col col3">
<div class="wrap2">
<h3 i18n="defaultDonateHead"></h3>
<div i18n="defaultDonateText"></div>

View File

@ -184,9 +184,10 @@
<input id="motorsEnableTestMode" type="checkbox" class="togglesmall"/>
<span class="motorsEnableTestMode" i18n="motorsEnableControl"></span>
</div>
<div class="cler-both"></div>
<div class="clear-both"></div>
</div>
</div>
</div>
<div class="clear-both"></div>
</div>
</div>

View File

@ -1,4 +1,4 @@
<div class="tab-onboard_logging toolbar_fixed_bottom">
<div class="tab-onboard_logging">
<div class="content_wrapper">
<div class="tab_title" i18n="tabOnboardLogging"></div>
<div class="cf_doc_version_bt">
@ -114,43 +114,44 @@
</div>
</div>
<div class="spacer_box">
<div class="sdcard">
<div class="sdcard-icon"></div>
<div class="sdcard-status"></div>
</div>
<div class="sdcard">
<div class="sdcard-icon"></div>
<div class="sdcard-status"></div>
</div>
<p i18n="sdcardNote"></p>
<p i18n="sdcardNote"></p>
<div class="require-sdcard-ready">
<ul class="sdcard-contents">
<li class="sdcard-other">
<div class="legend"></div>
</li>
<li class="sdcard-free">
<div class="legend"></div>
</li>
</ul>
</div>
<div class="require-sdcard-ready">
<ul class="sdcard-contents">
<li class="sdcard-other">
<div class="legend"></div>
</li>
<li class="sdcard-free">
<div class="legend"></div>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="gui_box grey require-msc-supported">
<div class="gui_box_titlebar" align="left">
<div class="spacer_box_title" i18n="onboardLoggingMsc">
</div>
</div>
<div class="spacer_box">
<div class="require-msc-supported">
<p i18n="onboardLoggingMscNote"></p>
<div>
<a class="require-msc-ready regular-button onboardLoggingRebootMsc" href="#" i18n="onboardLoggingRebootMscText"></a>
</div>
</div>
<p class="require-msc-not-ready" i18n="onboardLoggingMscNotReady"></p>
</div>
</div>
</div>
<div class="gui_box grey require-msc-supported">
<div class="gui_box_titlebar" align="left">
<div class="spacer_box_title" i18n="onboardLoggingMsc">
</div>
</div>
<div class="spacer_box">
<div class="require-msc-supported">
<p i18n="onboardLoggingMscNote"></p>
<div>
<a class="require-msc-ready regular-button onboardLoggingRebootMsc" href="#" i18n="onboardLoggingRebootMscText"></a>
</div>
</div>
<p class="require-msc-not-ready" i18n="onboardLoggingMscNotReady"></p>
</div>
</div>
<div class="clear-both"></div>
</div>
</div>

View File

@ -1,23 +1,55 @@
<div class="permanentExpertMode">
<label><input type="checkbox" /><span i18n="permanentExpertMode"></span></label>
</div>
<div class="checkForConfiguratorUnstableVersions">
<label><input type="checkbox" /><span i18n="checkForConfiguratorUnstableVersions"></span></label>
</div>
<div class="rememberLastTab">
<label><input type="checkbox" /><span i18n="rememberLastTab"></span></label>
</div>
<div class="analyticsOptOut">
<label><input type="checkbox" /><span i18n="analyticsOptOut"></span></label>
</div>
<div class="cliAutoComplete">
<label><input type="checkbox" /><span i18n="cliAutoComplete"></span></label>
</div>
<div class="darkTheme">
<select id="darkThemeSelect">
<option value="0" i18n="on"></option>
<option value="1" i18n="off"></option>
<option value="2" i18n="auto"></option>
</select>
<span i18n="darkTheme"></span>
<div class="tab-options">
<div class="content_wrapper">
<div class="gui_box">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="tabOptions"></div>
</div>
<div class="spacer">
<div class="permanentExpertMode margin-bottom">
<div>
<input type="checkbox" class="toggle" />
</div>
<span class="freelabel" i18n="permanentExpertMode"></span>
</div>
<div class="checkForConfiguratorUnstableVersions margin-bottom">
<div>
<input type="checkbox" class="toggle" />
</div>
<span class="freelabel" i18n="checkForConfiguratorUnstableVersions"></span>
</div>
<div class="rememberLastTab margin-bottom">
<div>
<input type="checkbox" class="toggle" />
</div>
<span class="freelabel" i18n="rememberLastTab"></span>
</div>
<div class="analyticsOptOut margin-bottom">
<div>
<input type="checkbox" class="toggle" />
</div>
<span class="freelabel" i18n="analyticsOptOut"></span>
</div>
<div class="cliAutoComplete margin-bottom">
<div>
<input type="checkbox" class="toggle" />
</div>
<span class="freelabel" i18n="cliAutoComplete"></span>
</div>
<div class="cordovaForceComputerUI margin-bottom">
<div>
<input type="checkbox" class="toggle" />
</div>
<span class="freelabel" i18n="cordovaForceComputerUI"></span>
</div>
<div class="darkTheme margin-bottom">
<select id="darkThemeSelect">
<option value="0" i18n="on"></option>
<option value="1" i18n="off"></option>
<option value="2" i18n="auto"></option>
</select>
<span i18n="darkTheme"></span>
</div>
</div>
</div>
</div>
</div>

View File

@ -17,8 +17,8 @@
<div style="margin-bottom: 10px;">
<p class="note" i18n="osdSetupPreviewHelp"></p>
</div>
<div class="cf_column third_left elements requires-osd-feature">
<div class="spacer_right">
<div class="grid-row">
<div class="grid-col col4 elements requires-osd-feature osd-feature">
<div class="gui_box grey">
<div class="gui_box_titlebar" style="margin-bottom: 0px;">
<div class="spacer_box_title">
@ -33,13 +33,11 @@
</div>
</div>
</div>
</div>
<div class="cf_column twothird">
<div class="grid-col col4 osd-preview">
<div class="gui_box grey preview requires-osd-feature">
<div class="gui_box grey preview requires-osd-feature">
<div class="gui_box_titlebar image">
<div class="spacer_box_title">
<div class="gui_box_titlebar image">
<div class="spacer_box_title">
<span class="cf_tip" i18n_title="osdSetupPreviewForTitle">
<label id="osdprofile-selector-label" i18n="osdSetupPreviewSelectProfileTitle"></label>
<select class="osdprofile-selector">
@ -49,24 +47,25 @@
<!-- Populated at runtime -->
</select>
</span>
</div>
</div>
<div class="display-layout">
<div class="col right">
<div class="preview">
</div>
</div>
</div>
<div class="gui_box_bottombar">
<div class="spacer_box_title">
<span i18n="osdSetupPreviewTitle"></span>
<div class="display-layout">
<div class="col right">
<div class="preview">
</div>
</div>
</div>
</div>
<div class="gui_box_bottombar">
<div class="spacer_box_title">
<span i18n="osdSetupPreviewTitle"></span>
</div>
</div>
</div>
</div>
<div class="cf_column third_right" style="width: calc(100% - 377px);">
<div class="grid-col col4 osd-profile">
<div class="gui_box osdprofile-selected-container grey">
<div class="gui_box_titlebar cf_tip">
<div class="spacer_box_title" i18n="osdSetupSelectedProfileTitle"></div>
@ -113,7 +112,7 @@
<div class="gui_box grey warnings-container requires-osd-feature" style="display:none;">
<div class="gui_box_titlebar cf_tip" style="margin-bottom: 0px;">
<div class="spacer_box_title">
<div class="spacer_box_title" i18n="osdSetupWarningsTitle"></div>
<div class="spacer_box_title" i18n="osdSetupWarningsTitle"></div>
</div>
</div>
<div class="spacer_box">
@ -165,20 +164,21 @@
</div>
<!-- Boot logo setup -->
<h1 class="tab_title" i18n="osdSetupCustomLogoTitle"></h1>
<div id="font-logo-preview-container" class="content_wrapper">
<div id="font-logo-preview">
<!-- this will be resized at runtime -->
<div class="grid-row">
<div id="font-logo-preview-container" class="content_wrapper grid-col col6">
<div id="font-logo-preview">
<!-- this will be resized at runtime -->
</div>
</div>
<div id="font-logo-info grid-col col6">
<h3 i18n="osdSetupCustomLogoInfoTitle"></h3>
<ul>
<li id="font-logo-info-size" i18n="osdSetupCustomLogoInfoImageSize"></li>
<li id="font-logo-info-colors" i18n="osdSetupCustomLogoInfoColorMap"></li>
</ul>
<p id="font-logo-info-upload-hint" i18n="osdSetupCustomLogoInfoUploadHint"></p>
</div>
</div>
<div id="font-logo-info">
<h3 i18n="osdSetupCustomLogoInfoTitle"></h3>
<ul>
<li id="font-logo-info-size" i18n="osdSetupCustomLogoInfoImageSize"></li>
<li id="font-logo-info-colors" i18n="osdSetupCustomLogoInfoColorMap"></li>
</ul>
<p id="font-logo-info-upload-hint" i18n="osdSetupCustomLogoInfoUploadHint"></p>
</div>
<div class="clear-both"></div>
<!-- Replace logo button -->
<div class="default_btn" style="width:100%; float:left;">
<a class="replace_logo" i18n="osdSetupCustomLogoOpenImageButton"></a>

View File

@ -4,7 +4,7 @@
<div class="cf_doc_version_bt">
<a id="button-documentation" href="https://github.com/betaflight/betaflight/releases" target="_blank" rel="noopener noreferrer"></a>
</div>
<div class="cf_column">
<div class="content_wrapper_header">
<div class="profile single-field">
<div class="helpicon cf_tip topspacer" i18n_title="pidTuningProfileTip"></div>
<div class="head" i18n="pidTuningProfile"></div>
@ -32,18 +32,18 @@
</select>
</div>
</div>
<div class="cf_column right">
<div class="default_btn show showAllPids">
<a href="#" id="showAllPids" i18n="pidTuningShowAllPids"></a>
</div>
<div class="default_btn resetbt">
<a href="#" id="resetProfile" i18n="pidTuningResetProfile"></a>
<div class="content_wrapper_header_btns">
<div class="default_btn copyprofilebtn">
<a href="#" id="copyProfile" i18n="pidTuningCopyProfile"></a>
</div>
<div class="default_btn copyrateprofilebtn">
<a href="#" id="copyRateProfile" i18n="pidTuningCopyRateProfile"></a>
</div>
<div class="default_btn copyprofilebtn">
<a href="#" id="copyProfile" i18n="pidTuningCopyProfile"></a>
<div class="default_btn resetbt">
<a href="#" id="resetProfile" i18n="pidTuningResetProfile"></a>
</div>
<div class="default_btn show showAllPids">
<a href="#" id="showAllPids" i18n="pidTuningShowAllPids"></a>
</div>
</div>
</div>
@ -75,19 +75,21 @@
<th class="name"></th>
<th class="proportional">
<div class="name-helpicon-flex">
<div i18n="pidTuningProportional"></div>
<div i18n="pidTuningProportional" class="sm-min"></div>
<div class="xs">P</div>
<div class="helpicon cf_tip" i18n_title="pidTuningProportionalHelp"></div>
</div>
</th>
<th class="integral">
<div class="name-helpicon-flex">
<div i18n="pidTuningIntegral"></div>
<div i18n="pidTuningIntegral" class="sm-min"></div>
<div class="xs">I</div>
<div class="helpicon cf_tip" i18n_title="pidTuningIntegralHelp"></div>
</div>
</th>
<th class="derivative">
<div class="name-helpicon-flex">
<div class="derivativeText" i18n="pidTuningDerivative"></div>
<div i18n="pidTuningDerivative" class="derivativeText"></div>
<div class="helpicon cf_tip" i18n_title="pidTuningDerivativeHelp"></div>
</div>
</th>
@ -99,7 +101,8 @@
</th>
<th class="feedforward">
<div class="name-helpicon-flex">
<div i18n="pidTuningFeedforward"></div>
<div i18n="pidTuningFeedforward" class="sm-min"></div>
<div class="xs">FF</div>
<div class="helpicon cf_tip" i18n_title="pidTuningFeedforwardHelp"></div>
</div>
</th>
@ -169,7 +172,7 @@
<div class="gui_box grey topspacer tuningPIDSliders">
<table class="pid_titlebar">
<tr>
<th></th>
<th scope="col" class="sm-min"></th>
<th></th>
<th i18n="pidTuningSliderLow"></th>
<th i18n="pidTuningSliderDefault"></th>
@ -180,8 +183,13 @@
</tr>
</table>
<table class="sliderLabels">
<tr class="xs sliderHeaders">
<td colspan="5">
<span i18n="pidTuningMasterSlider"/>
</td>
</tr>
<tr>
<td>
<td class="sm-min">
<span i18n="pidTuningMasterSlider"></span>
</td>
<td>
@ -194,8 +202,13 @@
<div class="helpicon cf_tip" i18n_title="pidTuningMasterSliderHelp"></div>
</td>
</tr>
<tr class="xs sliderHeaders">
<td colspan="5">
<span i18n="pidTuningPDRatioSlider"></span>
</td>
</tr>
<tr>
<td>
<td class="sm-min">
<span i18n="pidTuningPDRatioSlider"></span>
</td>
<td>
@ -208,8 +221,13 @@
<div class="helpicon cf_tip" i18n_title="pidTuningPDRatioSliderHelp"></div>
</td>
</tr>
<tr class="xs sliderHeaders">
<td colspan="5">
<span i18n="pidTuningPDGainSlider"></span>
</td>
</tr>
<tr>
<td>
<td class="sm-min">
<span i18n="pidTuningPDGainSlider"></span>
</td>
<td>
@ -222,8 +240,13 @@
<div class="helpicon cf_tip" i18n_title="pidTuningPDGainSliderHelp"></div>
</td>
</tr>
<tr class="xs sliderHeaders">
<td colspan="5">
<span i18n="pidTuningResponseSlider"></span>
</td>
</tr>
<tr>
<td>
<td class="sm-min">
<span i18n="pidTuningResponseSlider"></span>
</td>
<td>
@ -966,7 +989,7 @@
<div class="gui_box grey topspacer tuningFilterSliders">
<table class="pid_titlebar">
<tr>
<th></th>
<th scope="col" class="sm-min"></th>
<th></th>
<th i18n="pidTuningSliderHighFiltering"></th>
<th i18n="pidTuningSliderDefaultFiltering"></th>
@ -977,8 +1000,13 @@
</tr>
</table>
<table class="sliderLabels">
<tr class="xs sliderHeaders">
<td colspan="5">
<span i18n="pidTuningGyroFilterSlider"></span>
</td>
</tr>
<tr>
<td>
<td class="sm-min">
<span i18n="pidTuningGyroFilterSlider"></span>
</td>
<td>
@ -991,8 +1019,13 @@
<div class="helpicon cf_tip" i18n_title="pidTuningGyroFilterSliderHelp"></div>
</td>
</tr>
<tr class="xs sliderHeaders">
<td colspan="5">
<span i18n="pidTuningDTermFilterSlider"></span>
</td>
</tr>
<tr>
<td>
<td class="sm-min">
<span i18n="pidTuningDTermFilterSlider"></span>
</td>
<td>

View File

@ -15,8 +15,8 @@
<table class="ports">
<thead>
<tr>
<td i18n="portsIdentifier"/>
<td i18n="portsConfiguration">
<td i18n="portsIdentifier" class="sm-min"/>
<td i18n="portsConfiguration" class="config">
<td i18n="portsSerialRx">
<td i18n="portsTelemetryOut">
<td i18n="portsSensorIn">
@ -43,8 +43,13 @@
<thead>
</thead>
<tbody>
<tr class="portIdentifier xs">
<td colspan="5">
<p class="identifier"></p>
</td>
</tr>
<tr class="portConfiguration">
<td class="identifierCell">
<td class="identifierCell sm-min">
<p class="identifier"></p>
</td>
<td class="functionsCell-configuration"><select class="msp_baudrate">

View File

@ -8,81 +8,67 @@
</div>
</div>
<table style="width:100%">
<tr>
<td>
<div class="leftWrapper">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerBatteryHead"></div>
</div>
<div class="spacer_box battery">
<table border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="battery-config">
<td class="configuration" rowspan="4"></td>
</tbody>
</table>
</div>
</div>
<div class="grid-row">
<div class="grid-col col6">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerBatteryHead"></div>
</div>
<div class="rightWrapper">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerStateHead"></div>
</div>
<div class="spacer_box battery">
<table border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="battery-state">
</tbody>
</table>
</div>
</div>
<div class="spacer_box battery">
<table border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="battery-config">
<td class="configuration" rowspan="4"></td>
</tbody>
</table>
</div>
</td>
</tr>
</table>
<table style="width:100%">
<tr>
<td>
<div class="leftWrapper">
<div class="gui_box grey boxVoltageConfiguration">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerVoltageHead"></div>
</div>
<div class="spacer_box">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="voltage-meters">
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="grid-col col6">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerStateHead"></div>
</div>
</td>
</tr>
</table>
<table style="width:100%">
<tr>
<td>
<div class="leftWrapper">
<div class="gui_box grey boxAmperageConfiguration">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerAmperageHead"></div>
</div>
<div class="spacer_box">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="amperage-meters">
</tbody>
</table>
</div>
</div>
<div class="spacer_box battery">
<table border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="battery-state">
</tbody>
</table>
</div>
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="grid-row">
<div class="grid-col col6">
<div class="gui_box grey boxVoltageConfiguration">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerVoltageHead"></div>
</div>
<div class="spacer_box">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="voltage-meters">
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="grid-row">
<div class="grid-col col6">
<div class="gui_box grey boxAmperageConfiguration">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="powerAmperageHead"></div>
</div>
<div class="spacer_box">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody class="amperage-meters">
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="note require-upgrade">
<p i18n="powerFirmwareUpgradeRequired"></p>
@ -103,42 +89,42 @@
<div id="tab-power-templates">
<table class="voltage-meters">
<tbody>
<tr class="voltage-meter">
<td class="label"></td>
<td class="value"></td>
<td class="configuration"></td>
</tr>
<tr class="voltage-meter">
<td class="label"></td>
<td class="value"></td>
<td class="configuration"></td>
</tr>
</tbody>
</table>
<table class="amperage-meters">
<tbody>
<tr class="amperage-meter">
<td class="label"></td>
<td class="value"></td>
<td class="configuration"></td>
</tr>
<tr class="amperage-meter">
<td class="label"></td>
<td class="value"></td>
<td class="configuration"></td>
</tr>
</tbody>
</table>
<table class="battery-state">
<tbody class="battery-state">
<tr class="connection-state">
<td i18n="powerBatteryConnected"></td>
<td class="value">?</td>
</tr>
<tr class="voltage">
<td i18n="powerBatteryVoltage"></td>
<td class="value"></td>
</tr>
<tr class="mah-drawn">
<td i18n="powerBatteryCurrentDrawn"></td>
<td class="value"></td>
</tr>
<tr class="amperage">
<td i18n="powerBatteryAmperage"></td>
<td class="value"></td>
</tr>
<tr class="connection-state">
<td i18n="powerBatteryConnected"></td>
<td class="value">?</td>
</tr>
<tr class="voltage">
<td i18n="powerBatteryVoltage"></td>
<td class="value"></td>
</tr>
<tr class="mah-drawn">
<td i18n="powerBatteryCurrentDrawn"></td>
<td class="value"></td>
</tr>
<tr class="amperage">
<td i18n="powerBatteryAmperage"></td>
<td class="value"></td>
</tr>
</tbody>
</table>

View File

@ -7,274 +7,274 @@
<div class="note">
<p i18n="receiverHelp"></p>
</div>
<div class="bars">
</div>
<div class="fc_column">
<div class="rssi_channel_wrapper grey">
<div class="head" i18n="receiverRssiChannel"></div>
<select name="rssi_channel">
<!-- list generated here -->
</select>
</div>
<div class="rcmap_wrapper grey">
<div class="head">
<span i18n="receiverChannelMap" i18n_title="receiverChannelMapTitle"></span>
</div>
<div class="hybrid_element">
<input type="text" name="rcmap" spellcheck="false" />
<select class="hybrid_helper"
name="rcmap_helper">
<option i18n="receiverChannelDefaultOption" value="AETR1234"></option>
<option value="AETR1234">FrSky / Futaba / Hitec</option>
<option value="TAER1234">Spektrum / Graupner / JR</option>
<div class="grid-row">
<div class="grid-col col6 bars"></div>
<div class="grid-col col6">
<div class="rssi_channel_wrapper grey">
<div class="head" i18n="receiverRssiChannel"></div>
<select name="rssi_channel">
<!-- list generated here -->
</select>
</div>
</div>
<div class="gui_box tunings grey">
<table class="sticks">
<tr>
<th i18n="receiverStickMin"></th>
<th i18n="receiverStickCenter"></th>
<th i18n="receiverStickMax"></th>
</tr>
<tr>
<td>
<div class="input-helpicon-flex">
<input type="number" name="stick_min" min="1000" max="1200"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpStickMin"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="stick_center" min="1401" max="1599"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpStickCenter"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="stick_max" min="1800" max="2000"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpStickMax"></div>
</div>
</td>
</tr>
</table>
</div>
<div class="gui_box tunings grey">
<table class="deadband">
<tr>
<th i18n="receiverDeadband"></th>
<th i18n="receiverYawDeadband"></th>
<th i18n="recevier3dDeadbandThrottle"></th>
</tr>
<tr>
<td>
<div class="input-helpicon-flex">
<input type="number" name="deadband" step="1" min="0" max="32"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpDeadband"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="yaw_deadband" step="1" min="0" max="100"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpYawDeadband"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="3ddeadbandthrottle" step="1" min="0" max="100"/>
<div class="helpicon cf_tip" i18n_title="receiverHelp3dDeadbandThrottle"></div>
</div>
</td>
</tr>
</table>
</div>
<div class="gui_box grey tunings topspacer rcSmoothing">
<table class="rcSmoothing-table">
<tr>
<th colspan="3" i18n="receiverRcSmoothing"></th>
</tr>
<tr class="rc-smoothing-type">
<td>
<select name="rcSmoothing-select">
<option value="0" i18n="receiverRcSmoothingInterpolation"></option>
<option value="1" i18n="receiverRcSmoothingFilter"></option>
</select>
</td>
<td colspan="2">
<div>
<label>
<span i18n="receiverRcSmoothingType"></span>
</label>
</div>
</td>
</tr>
<tr class="rc-smoothing-channels">
<td>
<select name="rcSmoothingChannels-select">
<option value="0">RP</option>
<option value="1">RPY</option>
<option value="2">RPYT</option>
<option value="3">T</option>
<option value="4">RPT</option>
</select>
</td>
<td colspan="2">
<div>
<label>
<span i18n="receiverRcSmoothingChannel"></span>
</label>
</div>
</td>
</tr>
<tr class="rcSmoothing-input-manual">
<td>
<select name="rcSmoothing-input-manual-select">
<option value="0" i18n="receiverRcSmoothingAuto"></option>
<option value="1" i18n="receiverRcSmoothingManual"></option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcInputTypeSelect"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="receiverRcSmoothingInputManual"></div>
</td>
</tr>
<tr class="rcSmoothing-input-manual">
<td class="rcSmoothing-input-cutoff"><input type="number" name="rcSmoothingInputHz-number" step="1" min="1" max="255"/></td>
<td class="rcSmoothing-input-cutoff" colspan="2">
<div>
<label>
<span i18n="receiverRcSmoothingInputHz"></span>
</label>
<div class="helpicon cf_tip" i18n_title="rcSmoothingInputCutoffHelp"></div>
</div>
</td>
</tr>
<tr class="rcSmoothing-input-type">
<td>
<select name="rcSmoothingInputType-select">
<option value="0">PT1</option>
<option value="1">BIQUAD</option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcInputType"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="rcSmoothingInputTypeHelp"></div>
</td>
</tr>
<tr class="rcSmoothing-derivative-manual">
<td>
<select name="rcSmoothing-input-derivative-select">
<option value="0" i18n="receiverRcSmoothingAuto"></option>
<option value="1" i18n="receiverRcSmoothingManual"></option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcDerivativeTypeSelect"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="receiverRcSmoothingDerivativeManual"></div>
</td>
</tr>
<tr class="rcSmoothing-derivative-manual">
<td class="rcSmoothing-derivative-cutoff"><input type="number" name="rcSmoothingDerivativeCutoff-number" step="1" min="1" max="255"/></td>
<td colspan="2" class="rcSmoothing-derivative-cutoff">
<div>
<label>
<span i18n="receiverRcSmoothingDerivativeCutoff"></span>
</label>
<div class="helpicon cf_tip" i18n_title="rcSmoothingDerivativeCutoffHelp"></div>
</div>
</td>
</tr>
<tr class="rcSmoothing-input-type">
<td>
<select name="rcSmoothingDerivativeType-select">
<option value="0" i18n="receiverRcSmoothingDerivativeTypeOff"></option>
<option value="1">PT1</option>
<option value="2">BIQUAD</option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcDerivativeType"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="rcSmoothingDerivativeTypeHelp"></div>
</td>
</tr>
<tr class="rcSmoothing-auto-smoothness">
<td>
<input type="number" name="rcSmoothingAutoSmoothness-number" step="1" min="0" max="50">
</td>
<td>
<div>
<label>
<span i18n="receiverRcSmoothingAutoSmoothness"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="receiverRcSmoothingAutoSmoothnessHelp"></div>
</td>
</tr>
<tr class="rcInterpolation">
<td>
<select name="rcInterpolation-select">
<option value="0" i18n="receiverRcInterpolationOff"></option>
<option value="1" i18n="receiverRcInterpolationDefault"></option>
<option value="2" i18n="receiverRcInterpolationAuto"></option>
<option value="3" i18n="receiverRcInterpolationManual"></option>
</select>
</td>
<td>
<div class="rcInterpolation-label">
<label>
<span i18n="receiverRcInterpolation"></span>
</label>
<div class="helpicon cf_tip" i18n_title="receiverRcInterpolationHelp"></div>
</div>
</td>
</tr>
<tr class="rcInterpolation">
<td class="rc-interpolation-manual" colspan="1"><input type="number" name="rcInterpolationInterval-number" step="1" min="1" max="50" /></td>
<td class="rc-interpolation-manual" colspan="2">
<div>
<label>
<span i18n="receiverRcInterpolationInterval"></span>
</label>
<div class="helpicon cf_tip" i18n_title="receiverRcInterpolationIntervalHelp"></div>
</div>
</td>
</tr>
</table>
</div>
<div class="gui_box grey tunings topspacer">
<table class="pid_titlebar">
<thead>
<div class="rcmap_wrapper grey">
<div class="head">
<span i18n="receiverChannelMap" i18n_title="receiverChannelMapTitle"></span>
</div>
<div class="hybrid_element">
<input type="text" name="rcmap" spellcheck="false" />
<select class="hybrid_helper"
name="rcmap_helper">
<option i18n="receiverChannelDefaultOption" value="AETR1234"></option>
<option value="AETR1234">FrSky / Futaba / Hitec</option>
<option value="TAER1234">Spektrum / Graupner / JR</option>
</select>
</div>
</div>
<div class="gui_box tunings grey">
<table class="sticks">
<tr>
<th i18n="receiverStickMin"></th>
<th i18n="receiverStickCenter"></th>
<th i18n="receiverStickMax"></th>
</tr>
<tr>
<td>
<div class="input-helpicon-flex">
<input type="number" name="stick_min" min="1000" max="1200"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpStickMin"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="stick_center" min="1401" max="1599"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpStickCenter"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="stick_max" min="1800" max="2000"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpStickMax"></div>
</div>
</td>
</tr>
</table>
</div>
<div class="gui_box tunings grey">
<table class="deadband">
<tr>
<th i18n="receiverDeadband"></th>
<th i18n="receiverYawDeadband"></th>
<th i18n="recevier3dDeadbandThrottle"></th>
</tr>
<tr>
<td>
<div class="input-helpicon-flex">
<input type="number" name="deadband" step="1" min="0" max="32"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpDeadband"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="yaw_deadband" step="1" min="0" max="100"/>
<div class="helpicon cf_tip" i18n_title="receiverHelpYawDeadband"></div>
</div>
</td>
<td>
<div class="input-helpicon-flex">
<input type="number" name="3ddeadbandthrottle" step="1" min="0" max="100"/>
<div class="helpicon cf_tip" i18n_title="receiverHelp3dDeadbandThrottle"></div>
</div>
</td>
</tr>
</table>
</div>
<div class="gui_box grey tunings topspacer rcSmoothing">
<table class="rcSmoothing-table">
<tr>
<th colspan="3" i18n="receiverRcSmoothing"></th>
</tr>
<tr class="rc-smoothing-type">
<td>
<select name="rcSmoothing-select">
<option value="0" i18n="receiverRcSmoothingInterpolation"></option>
<option value="1" i18n="receiverRcSmoothingFilter"></option>
</select>
</td>
<td colspan="2">
<div>
<label>
<span i18n="receiverRcSmoothingType"></span>
</label>
</div>
</td>
</tr>
<tr class="rc-smoothing-channels">
<td>
<select name="rcSmoothingChannels-select">
<option value="0">RP</option>
<option value="1">RPY</option>
<option value="2">RPYT</option>
<option value="3">T</option>
<option value="4">RPT</option>
</select>
</td>
<td colspan="2">
<div>
<label>
<span i18n="receiverRcSmoothingChannel"></span>
</label>
</div>
</td>
</tr>
<tr class="rcSmoothing-input-manual">
<td>
<select name="rcSmoothing-input-manual-select">
<option value="0" i18n="receiverRcSmoothingAuto"></option>
<option value="1" i18n="receiverRcSmoothingManual"></option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcInputTypeSelect"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="receiverRcSmoothingInputManual"></div>
</td>
</tr>
<tr class="rcSmoothing-input-manual">
<td class="rcSmoothing-input-cutoff"><input type="number" name="rcSmoothingInputHz-number" step="1" min="1" max="255"/></td>
<td class="rcSmoothing-input-cutoff" colspan="2">
<div>
<label>
<span i18n="receiverRcSmoothingInputHz"></span>
</label>
<div class="helpicon cf_tip" i18n_title="rcSmoothingInputCutoffHelp"></div>
</div>
</td>
</tr>
<tr class="rcSmoothing-input-type">
<td>
<select name="rcSmoothingInputType-select">
<option value="0">PT1</option>
<option value="1">BIQUAD</option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcInputType"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="rcSmoothingInputTypeHelp"></div>
</td>
</tr>
<tr class="rcSmoothing-derivative-manual">
<td>
<select name="rcSmoothing-input-derivative-select">
<option value="0" i18n="receiverRcSmoothingAuto"></option>
<option value="1" i18n="receiverRcSmoothingManual"></option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcDerivativeTypeSelect"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="receiverRcSmoothingDerivativeManual"></div>
</td>
</tr>
<tr class="rcSmoothing-derivative-manual">
<td class="rcSmoothing-derivative-cutoff"><input type="number" name="rcSmoothingDerivativeCutoff-number" step="1" min="1" max="255"/></td>
<td colspan="2" class="rcSmoothing-derivative-cutoff">
<div>
<label>
<span i18n="receiverRcSmoothingDerivativeCutoff"></span>
</label>
<div class="helpicon cf_tip" i18n_title="rcSmoothingDerivativeCutoffHelp"></div>
</div>
</td>
</tr>
<tr class="rcSmoothing-input-type">
<td>
<select name="rcSmoothingDerivativeType-select">
<option value="0" i18n="receiverRcSmoothingDerivativeTypeOff"></option>
<option value="1">PT1</option>
<option value="2">BIQUAD</option>
</select>
</td>
<td>
<div>
<label>
<span i18n="receiverRcDerivativeType"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="rcSmoothingDerivativeTypeHelp"></div>
</td>
</tr>
<tr class="rcSmoothing-auto-smoothness">
<td>
<input type="number" name="rcSmoothingAutoSmoothness-number" step="1" min="0" max="50">
</td>
<td>
<div>
<label>
<span i18n="receiverRcSmoothingAutoSmoothness"></span>
</label>
</div>
</td>
<td>
<div class="helpicon cf_tip" i18n_title="receiverRcSmoothingAutoSmoothnessHelp"></div>
</td>
</tr>
<tr class="rcInterpolation">
<td>
<select name="rcInterpolation-select">
<option value="0" i18n="receiverRcInterpolationOff"></option>
<option value="1" i18n="receiverRcInterpolationDefault"></option>
<option value="2" i18n="receiverRcInterpolationAuto"></option>
<option value="3" i18n="receiverRcInterpolationManual"></option>
</select>
</td>
<td>
<div class="rcInterpolation-label">
<label>
<span i18n="receiverRcInterpolation"></span>
</label>
<div class="helpicon cf_tip" i18n_title="receiverRcInterpolationHelp"></div>
</div>
</td>
</tr>
<tr class="rcInterpolation">
<td class="rc-interpolation-manual" colspan="1"><input type="number" name="rcInterpolationInterval-number" step="1" min="1" max="50" /></td>
<td class="rc-interpolation-manual" colspan="2">
<div>
<label>
<span i18n="receiverRcInterpolationInterval"></span>
</label>
<div class="helpicon cf_tip" i18n_title="receiverRcInterpolationIntervalHelp"></div>
</div>
</td>
</tr>
</table>
</div>
<div class="gui_box grey tunings topspacer">
<table class="pid_titlebar">
<thead>
<tr>
<th i18n="receiverModelPreview"></th>
</tr>
</thead>
<tbody>
</thead>
<tbody>
<tr>
<td class="model_preview_cell">
<div class="model_preview background_paper">
@ -282,11 +282,11 @@
</div>
</td>
</tr>
</tbody>
</table>
</tbody>
</table>
</div>
</div>
</div>
<div class="clear-both"></div>
<div class="gui_box grey">
<div class="spacer">
<select name="rx_refresh_rate" i18n_title="receiverRefreshRateTitle">

View File

@ -6,18 +6,20 @@
</div>
<div class="require-support">
<div class="title" i18n="servosChangeDirection"></div>
<table class="fields">
<tr class="main">
<th width="110px" i18n="servosName"></th>
<th i18n="servosMid"></th>
<th i18n="servosMin"></th>
<th i18n="servosMax"></th>
<th class="short">CH1</th>
<th class="short">CH2</th>
<th class="short">CH3</th>
<th class="short">CH4</th>
</tr>
</table>
<div class="table_overflow">
<table class="fields">
<tr class="main">
<th width="110px" i18n="servosName"></th>
<th i18n="servosMid"></th>
<th i18n="servosMin"></th>
<th i18n="servosMax"></th>
<th class="short">CH1</th>
<th class="short">CH2</th>
<th class="short">CH3</th>
<th class="short">CH4</th>
</tr>
</table>
</div>
<div class="live">
<input type="checkbox" class="togglemedium" /> <span i18n="servosLiveMode"></span>
</div>

View File

@ -1,99 +1,114 @@
<div class="tab-setup">
<div class="content_wrapper initialstyle">
<div class="content_wrapper">
<!-- should be the first DIV on each tab -->
<div class="cf_column full">
<div class="tab_title" i18n="tabSetup">Setup</div>
<div class="cf_doc_version_bt">
<a id="button-documentation" href="" target="_blank"></a>
</div>
<div class="cf_column fourth buttonarea">
<div class="spacer_right">
<div class="default_btn">
<div id="accel_calib_rest">
<a class="calibrateAccel" id="default_btn green" href="#"
i18n="initialSetupButtonCalibrateAccel"></a>
</div>
<div id="accel_calib_running">
<div class="data-loading-setup">
<p i18n="initialSetupButtonCalibratingText"></p>
</div>
</div>
<div class="tab_title" i18n="tabSetup">Setup</div>
<div class="cf_doc_version_bt">
<a id="button-documentation" href="" target="_blank"></a>
</div>
<div class="grid-row">
<div class="grid-col col3">
<div class="default_btn">
<div id="accel_calib_rest">
<a class="calibrateAccel" id="default_btn green" href="#" i18n="initialSetupButtonCalibrateAccel"></a>
</div>
<div class="default_btn">
<div id="mag_calib_rest">
<a class="calibrateMag" href="#" i18n="initialSetupButtonCalibrateMag"></a>
<div id="accel_calib_running">
<div class="data-loading-setup">
<p i18n="initialSetupButtonCalibratingText"></p>
</div>
<div id="mag_calib_running">
<div class="data-loading-setup">
<p i18n="initialSetupButtonCalibratingText"></p>
</div>
</div>
</div>
<div class="default_btn">
<a class="resetSettings" href="#" i18n="initialSetupButtonReset"></a>
</div>
<div class="half">
<div class="spacer_right halfbuttons">
<div class="default_btn half">
<a class="backup" href="#" i18n="initialSetupButtonBackup"></a>
</div>
</div>
</div>
<div class="half">
<div class="default_btn half">
<a class="restore" href="#" i18n="initialSetupButtonRestore"></a>
</div>
</div>
<div class="default_btn initialSetupRebootBootloader">
<a class="rebootBootloader" href="#" i18n="initialSetupButtonRebootBootloader"></a>
</div>
</div>
</div>
<div class="threefourth_right setupinfo">
<div class="grid-col col9">
<div class="cell_setup">
<span i18n="initialSetupCalibrateAccelText"></span>
</div>
</div>
</div>
<div class="grid-row">
<div class="grid-col col3">
<div class="default_btn">
<div id="mag_calib_rest">
<a class="calibrateMag" href="#" i18n="initialSetupButtonCalibrateMag"></a>
</div>
<div id="mag_calib_running">
<div class="data-loading-setup">
<p i18n="initialSetupButtonCalibratingText"></p>
</div>
</div>
</div>
</div>
<div class="grid-col col9">
<div class="cell_setup">
<span i18n="initialSetupCalibrateMagText"></span>
</div>
</div>
</div>
<div class="grid-row">
<div class="grid-col col3">
<div class="default_btn">
<a class="resetSettings" href="#" i18n="initialSetupButtonReset"></a>
</div>
</div>
<div class="grid-col col9">
<div class="cell_setup">
<span i18n="initialSetupResetText"></span>
</div>
</div>
</div>
<div class="grid-row">
<div class="grid-col col3">
<div class="grid-row">
<div class="grid-col col6">
<div class="default_btn">
<a class="backup" href="#" i18n="initialSetupButtonBackup"></a>
</div>
</div>
<div class="grid-col col6">
<div class="default_btn">
<a class="restore" href="#" i18n="initialSetupButtonRestore"></a>
</div>
</div>
</div>
</div>
<div class="grid-col col9">
<div class="cell_setup">
<span i18n="initialSetupBackupRestoreText"></span>
</div>
</div>
</div>
<div class="grid-row">
<div class="grid-col col3">
<div class="default_btn initialSetupRebootBootloader">
<a class="rebootBootloader" href="#" i18n="initialSetupButtonRebootBootloader"></a>
</div>
</div>
<div class="grid-col col9">
<div class="cell_setup initialSetupRebootBootloader">
<span i18n="initialSetupRebootBootloaderText"></span>
</div>
</div>
</div>
<div class="modelwrapper"></div>
<div class="cf_column threefourth_left">
<div class="spacer_right">
<div class="model-and-info">
<div id="interactive_block">
<div id="canvas_wrapper" class="background_paper">
<canvas id="canvas"></canvas>
<div class="attitude_info">
<dl>
<dt>Heading:</dt>
<dd class="heading">&nbsp;</dd>
<dt>Pitch:</dt>
<dd class="pitch">&nbsp;</dd>
<dt>Roll:</dt>
<dd class="roll">&nbsp;</dd>
</dl>
</div>
<div class="grid-row">
<div class="grid-col col9 model-and-info">
<div id="interactive_block">
<div id="canvas_wrapper" class="background_paper">
<canvas id="canvas"></canvas>
<div class="attitude_info">
<dl>
<dt>Heading:</dt>
<dd class="heading">&nbsp;</dd>
<dt>Pitch:</dt>
<dd class="pitch">&nbsp;</dd>
<dt>Roll:</dt>
<dd class="roll">&nbsp;</dd>
</dl>
</div>
<a class="reset" href="#" i18n="initialSetupButtonResetZaxis"></a>
</div>
<a class="reset sm-min" href="#" i18n="initialSetupButtonResetZaxis"></a>
</div>
</div>
</div>
<div class="cf_column fourth">
<div class="spacer_left">
<div class="grid-col col3">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="initialSetupInfoHead"></div>
@ -101,32 +116,30 @@
<div class="spacer_box">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody>
<tr>
<td id="arming-disable-flag" i18n="initialSetupArmingDisableFlags" class="cf_tip"></td>
<td class="arming-disable-flags"></td>
</tr>
<tr>
<td i18n="initialSetupBattery"></td>
<td class="bat-voltage">0 V</td>
</tr>
<tr>
<td i18n="initialSetupDrawn"></td>
<td class="bat-mah-drawn">0 mAh</td>
</tr>
<tr>
<td i18n="initialSetupDrawing"></td>
<td class="bat-mah-drawing">0.00 A</td>
</tr>
<tr class="noboarder">
<td i18n="initialSetupRSSI"></td>
<td class="rssi">0 %</td>
</tr>
<tr>
<td id="arming-disable-flag" i18n="initialSetupArmingDisableFlags" class="cf_tip"></td>
<td class="arming-disable-flags"></td>
</tr>
<tr>
<td i18n="initialSetupBattery"></td>
<td class="bat-voltage">0 V</td>
</tr>
<tr>
<td i18n="initialSetupDrawn"></td>
<td class="bat-mah-drawn">0 mAh</td>
</tr>
<tr>
<td i18n="initialSetupDrawing"></td>
<td class="bat-mah-drawing">0.00 A</td>
</tr>
<tr class="noboarder">
<td i18n="initialSetupRSSI"></td>
<td class="rssi">0 %</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="spacer_left">
<div class="gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" i18n="initialSetupGPSHead"></div>
@ -134,28 +147,26 @@
<div class="spacer_box">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="cf_table">
<tbody>
<tr>
<td i18n="gps3dFix"></td>
<td class="gpsFix"></td>
</tr>
<tr>
<td i18n="gpsSats"></td>
<td class="gpsSats"></td>
</tr>
<tr>
<td i18n="gpsLat"></td>
<td class="gpsLat"></td>
</tr>
<tr class="noboarder">
<td i18n="gpsLon"></td>
<td class="gpsLon"></td>
</tr>
<tr>
<td i18n="gps3dFix"></td>
<td class="gpsFix"></td>
</tr>
<tr>
<td i18n="gpsSats"></td>
<td class="gpsSats"></td>
</tr>
<tr>
<td i18n="gpsLat"></td>
<td class="gpsLat"></td>
</tr>
<tr class="noboarder">
<td i18n="gpsLon"></td>
<td class="gpsLon"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div class="spacer_left">
<div class="gui_box grey instrumentsbox" align="center">
<div class="gui_box_titlebar" align="left">
<div class="spacer_box_title" i18n="initialSetupInstrumentsHead"></div>

View File

@ -255,26 +255,31 @@
</div>
<div class="content_toolbar">
<div class="btn save_lua_btn">
<a class="save_lua" id="save_lua_button" href="#" i18n="vtxButtonSaveLua"></a>
<div id="vtxLuaFileTooltip" class="helpicon cf_tip" i18n_title="vtxLuaFileHelp"></div>
</div>
<div class="btn save_file_btn">
<a class="save_file" id="save_file_button" href="#" i18n="vtxButtonSaveFile"></a>
</div>
<div class="btn load_file_btn">
<a class="load_file" id="load_file_button" href="#" i18n="vtxButtonLoadFile"></a>
<div class="content_toolbar xs-compressed">
<div class="btn save_btn">
<a class="save" id="save_button" href="#" i18n="vtxButtonSave"></a>
</div>
<div class="btn load_cliboard_btn clipboard_available">
<a class="load_clipboard" id="load_clipboard_button" href="#" i18n="vtxButtonLoadClipboard"></a>
</div>
<div class="btn save_btn">
<a class="save" id="save_button" href="#" i18n="vtxButtonSave"></a>
<div class="btn load_file_btn">
<a class="load_file" id="load_file_button" href="#" i18n="vtxButtonLoadFile"></a>
</div>
<div class="btn save_file_btn">
<a class="save_file" id="save_file_button" href="#" i18n="vtxButtonSaveFile"></a>
</div>
<div class="btn save_lua_btn">
<a class="save_lua" id="save_lua_button" href="#" i18n="vtxButtonSaveLua"></a>
<div id="vtxLuaFileTooltip" class="helpicon cf_tip" i18n_title="vtxLuaFileHelp"></div>
</div>
</div>
<div class="toolbar_expand_btn" nbrow="2">
<em class="fas fa-ellipsis-h"></em>
</div>
</div>
<div id="tab-vtx-templates">

View File

@ -14,6 +14,7 @@ module.exports = function(config) {
'./src/js/gui.js',
'./src/js/CliAutoComplete.js',
'./src/js/tabs/cli.js',
'./src/js/phones_ui.js',
'./test/**/*.js'
],
browsers: ['ChromeHeadlessNoSandbox'],

846
yarn.lock

File diff suppressed because it is too large Load Diff