34 changed files with 568 additions and 11982 deletions
@ -1,13 +0,0 @@ |
|||
# Editor configuration, see https://editorconfig.org |
|||
root = true |
|||
|
|||
[*] |
|||
charset = utf-8 |
|||
indent_style = space |
|||
indent_size = 2 |
|||
insert_final_newline = true |
|||
trim_trailing_whitespace = true |
|||
|
|||
[*.md] |
|||
max_line_length = off |
|||
trim_trailing_whitespace = false |
@ -1,5 +0,0 @@ |
|||
{ |
|||
"projects": { |
|||
"default": "bluetooth-class" |
|||
} |
|||
} |
@ -1,8 +0,0 @@ |
|||
# Editor files |
|||
.idea |
|||
|
|||
# Build dependencies |
|||
node_modules |
|||
|
|||
# Build output |
|||
dist |
@ -1,14 +0,0 @@ |
|||
image: node:latest |
|||
|
|||
cache: |
|||
paths: |
|||
- node_modules/ |
|||
|
|||
deploy: |
|||
only: |
|||
- master |
|||
stage: deploy |
|||
script: |
|||
- npm install |
|||
- npm run build |
|||
- node_modules/.bin/firebase deploy -m "Pipeline $CI_PIPELINE_ID" --non-interactive --token $FIREBASE_CI_TOKEN |
@ -1,3 +1,3 @@ |
|||
# Bluetooth Class |
|||
|
|||
Builder for hcitool class codes |
|||
Builder for hcitool class codes. |
|||
|
@ -1,99 +1,99 @@ |
|||
{ |
|||
"bluetoothClass": "BlueTooth class", |
|||
"builtBy": "Built by", |
|||
"clickToCopy": "Click to copy", |
|||
"majorService": { |
|||
"group": "Major service", |
|||
"Information": "Information", |
|||
"Telephony": "Telephony", |
|||
"Audio": "Audio", |
|||
"Transfer": "Transfer", |
|||
"Capturing": "Capturing", |
|||
"Rendering": "Rendering", |
|||
"AccessPoint": "Access point", |
|||
"Positioning": "Positioning", |
|||
"LimitedDiscovery": "Limited discovery" |
|||
}, |
|||
"majorDevice": { |
|||
"group": "Major device", |
|||
"Uncategorized": "Uncategorized", |
|||
"Miscellaneous": "Miscellaneous", |
|||
"Toy": "Toy", |
|||
"Wearable": "Wearable", |
|||
"Imaging": "Imaging", |
|||
"Peripheral": "Peripheral", |
|||
"AudioVideo": "Media", |
|||
"AccessPoint": "Access point", |
|||
"Phone": "Phone", |
|||
"Computer": "Computer" |
|||
}, |
|||
"minorDevice": { |
|||
"group": "Minor device", |
|||
"None": "No minor devices", |
|||
"Toy": { |
|||
"Game": "Game", |
|||
"Controller": "Controller", |
|||
"Doll": "Doll", |
|||
"Vehicle": "Vehicle", |
|||
"Robot": "Robot" |
|||
}, |
|||
"Wearable": { |
|||
"Watch": "Watch", |
|||
"Pager": "Pager", |
|||
"Jacket": "Jacket", |
|||
"Helmet": "Helmet", |
|||
"Glasses": "Glasses" |
|||
}, |
|||
"Imaging": { |
|||
"Display": "Display", |
|||
"Camera": "Camera", |
|||
"Scanner": "Scanner", |
|||
"Printer": "Printer" |
|||
}, |
|||
"Peripheral": { |
|||
"Keyboard": "Keyboard", |
|||
"Pointer": "Pointer", |
|||
"Uncategorized": "Uncategorized", |
|||
"Joystick": "Joystick", |
|||
"Gamepad": "Gamepad", |
|||
"RemoteControl": "Remote control", |
|||
"Sensor": "Sensor", |
|||
"Digitizer": "Digitizer", |
|||
"CardReader": "Card reader" |
|||
}, |
|||
"AudioVideo": { |
|||
"Uncategorized": "Uncategorized", |
|||
"Headset": "Headset", |
|||
"Microphone": "Microphone", |
|||
"Loudspeaker": "Loudspeaker", |
|||
"Headphones": "Headphones", |
|||
"CarAudio": "Car audio", |
|||
"VideoCamera": "Video camera", |
|||
"Monitor": "Monitor", |
|||
"Conferencing": "Conferencing" |
|||
}, |
|||
"AccessPoint": { |
|||
"Available": "Available", |
|||
"Level1": "1-17% use", |
|||
"Level2": "17-33% use", |
|||
"Level3": "33-50% use", |
|||
"Level4": "50-67% use", |
|||
"Level5": "67-83% use", |
|||
"Level6": "83-99% use", |
|||
"Unavailable": "Unavailable" |
|||
}, |
|||
"Phone": { |
|||
"Uncategorized": "Uncategorized", |
|||
"Cell": "Cell", |
|||
"Cordless": "Cordless" |
|||
}, |
|||
"Computer": { |
|||
"Uncategorized": "Uncategorized", |
|||
"Desktop": "Desktop", |
|||
"Server": "Server", |
|||
"Laptop": "Laptop", |
|||
"PDA": "PDA", |
|||
"Watch": "Watch" |
|||
} |
|||
} |
|||
} |
|||
{ |
|||
"bluetoothClass": "BlueTooth class", |
|||
"builtBy": "Built by", |
|||
"clickToCopy": "Click to copy", |
|||
"majorService": { |
|||
"group": "Major service", |
|||
"Information": "Information", |
|||
"Telephony": "Telephony", |
|||
"Audio": "Audio", |
|||
"Transfer": "Transfer", |
|||
"Capturing": "Capturing", |
|||
"Rendering": "Rendering", |
|||
"AccessPoint": "Access point", |
|||
"Positioning": "Positioning", |
|||
"LimitedDiscovery": "Limited discovery" |
|||
}, |
|||
"majorDevice": { |
|||
"group": "Major device", |
|||
"Uncategorized": "Uncategorized", |
|||
"Miscellaneous": "Miscellaneous", |
|||
"Toy": "Toy", |
|||
"Wearable": "Wearable", |
|||
"Imaging": "Imaging", |
|||
"Peripheral": "Peripheral", |
|||
"AudioVideo": "Media", |
|||
"AccessPoint": "Access point", |
|||
"Phone": "Phone", |
|||
"Computer": "Computer" |
|||
}, |
|||
"minorDevice": { |
|||
"group": "Minor device", |
|||
"None": "No minor devices", |
|||
"Toy": { |
|||
"Game": "Game", |
|||
"Controller": "Controller", |
|||
"Doll": "Doll", |
|||
"Vehicle": "Vehicle", |
|||
"Robot": "Robot" |
|||
}, |
|||
"Wearable": { |
|||
"Watch": "Watch", |
|||
"Pager": "Pager", |
|||
"Jacket": "Jacket", |
|||
"Helmet": "Helmet", |
|||
"Glasses": "Glasses" |
|||
}, |
|||
"Imaging": { |
|||
"Display": "Display", |
|||
"Camera": "Camera", |
|||
"Scanner": "Scanner", |
|||
"Printer": "Printer" |
|||
}, |
|||
"Peripheral": { |
|||
"Keyboard": "Keyboard", |
|||
"Pointer": "Pointer", |
|||
"Uncategorized": "Uncategorized", |
|||
"Joystick": "Joystick", |
|||
"Gamepad": "Gamepad", |
|||
"RemoteControl": "Remote control", |
|||
"Sensor": "Sensor", |
|||
"Digitizer": "Digitizer", |
|||
"CardReader": "Card reader" |
|||
}, |
|||
"AudioVideo": { |
|||
"Uncategorized": "Uncategorized", |
|||
"Headset": "Headset", |
|||
"Microphone": "Microphone", |
|||
"Loudspeaker": "Loudspeaker", |
|||
"Headphones": "Headphones", |
|||
"CarAudio": "Car audio", |
|||
"VideoCamera": "Video camera", |
|||
"Monitor": "Monitor", |
|||
"Conferencing": "Conferencing" |
|||
}, |
|||
"AccessPoint": { |
|||
"Available": "Available", |
|||
"Level1": "1-17% use", |
|||
"Level2": "17-33% use", |
|||
"Level3": "33-50% use", |
|||
"Level4": "50-67% use", |
|||
"Level5": "67-83% use", |
|||
"Level6": "83-99% use", |
|||
"Unavailable": "Unavailable" |
|||
}, |
|||
"Phone": { |
|||
"Uncategorized": "Uncategorized", |
|||
"Cell": "Cell", |
|||
"Cordless": "Cordless" |
|||
}, |
|||
"Computer": { |
|||
"Uncategorized": "Uncategorized", |
|||
"Desktop": "Desktop", |
|||
"Server": "Server", |
|||
"Laptop": "Laptop", |
|||
"PDA": "PDA", |
|||
"Watch": "Watch" |
|||
} |
|||
} |
|||
} |
@ -1,99 +1,99 @@ |
|||
{ |
|||
"bluetoothClass": "Clase bluetooth", |
|||
"builtBy": "Construido por", |
|||
"clickToCopy": "Haga clic para copiar", |
|||
"majorService": { |
|||
"group": "Servicio mayor", |
|||
"Information": "Información", |
|||
"Telephony": "Telefonía", |
|||
"Audio": "Audio", |
|||
"Transfer": "Transferir", |
|||
"Capturing": "Capturando", |
|||
"Rendering": "Representación", |
|||
"AccessPoint": "Punto de acceso", |
|||
"Positioning": "Posicionamiento", |
|||
"LimitedDiscovery": "Descubrimiento limitado" |
|||
}, |
|||
"majorDevice": { |
|||
"group": "Dispositivo principal", |
|||
"Uncategorized": "Sin categorizar", |
|||
"Miscellaneous": "Diverso", |
|||
"Toy": "Juguete", |
|||
"Wearable": "Usable", |
|||
"Imaging": "Imágenes", |
|||
"Peripheral": "Periférico", |
|||
"AudioVideo": "Medios de comunicación", |
|||
"AccessPoint": "Punto de acceso", |
|||
"Phone": "Teléfono", |
|||
"Computer": "Computadora" |
|||
}, |
|||
"minorDevice": { |
|||
"group": "Dispositivo menor", |
|||
"None": "No hay dispositivos menores", |
|||
"Toy": { |
|||
"Game": "Juego", |
|||
"Controller": "Controlador", |
|||
"Doll": "Muñeca", |
|||
"Vehicle": "Vehículo", |
|||
"Robot": "Robot" |
|||
}, |
|||
"Wearable": { |
|||
"Watch": "Reloj", |
|||
"Pager": "Buscapersonas", |
|||
"Jacket": "Chaqueta", |
|||
"Helmet": "Casco", |
|||
"Glasses": "Lentes" |
|||
}, |
|||
"Imaging": { |
|||
"Display": "Monitor", |
|||
"Camera": "Cámara", |
|||
"Scanner": "Escáner", |
|||
"Printer": "Impresora" |
|||
}, |
|||
"Peripheral": { |
|||
"Keyboard": "Teclado", |
|||
"Pointer": "Puntero", |
|||
"Uncategorized": "Sin categorizar", |
|||
"Joystick": "Palanca de mando", |
|||
"Gamepad": "Gamepad", |
|||
"RemoteControl": "Control remoto", |
|||
"Sensor": "Sensor", |
|||
"Digitizer": "Digitalizador", |
|||
"CardReader": "Lector de tarjetas" |
|||
}, |
|||
"AudioVideo": { |
|||
"Uncategorized": "Sin categorizar", |
|||
"Headset": "Auriculares", |
|||
"Microphone": "Micrófono", |
|||
"Loudspeaker": "Altoparlante", |
|||
"Headphones": "Auriculares", |
|||
"CarAudio": "Audio del coche", |
|||
"VideoCamera": "Camara de video", |
|||
"Monitor": "Monitor", |
|||
"Conferencing": "Conferencia" |
|||
}, |
|||
"AccessPoint": { |
|||
"Available": "Disponible", |
|||
"Level1": "1-17% de uso", |
|||
"Level2": "17-33% de uso", |
|||
"Level3": "33-50% de uso", |
|||
"Level4": "50-67% de uso", |
|||
"Level5": "67-83% de uso", |
|||
"Level6": "83-99% de uso", |
|||
"Unavailable": "Indisponible" |
|||
}, |
|||
"Phone": { |
|||
"Uncategorized": "Sin categorizar", |
|||
"Cell": "Célula", |
|||
"Cordless": "Sin cable" |
|||
}, |
|||
"Computer": { |
|||
"Uncategorized": "Sin categorizar", |
|||
"Desktop": "Escritorio", |
|||
"Server": "Servidor", |
|||
"Laptop": "Ordenador portátil", |
|||
"PDA": "PDA", |
|||
"Watch": "Reloj" |
|||
} |
|||
} |
|||
} |
|||
{ |
|||
"bluetoothClass": "Clase bluetooth", |
|||
"builtBy": "Construido por", |
|||
"clickToCopy": "Haga clic para copiar", |
|||
"majorService": { |
|||
"group": "Servicio mayor", |
|||
"Information": "Información", |
|||
"Telephony": "Telefonía", |
|||
"Audio": "Audio", |
|||
"Transfer": "Transferir", |
|||
"Capturing": "Capturando", |
|||
"Rendering": "Representación", |
|||
"AccessPoint": "Punto de acceso", |
|||
"Positioning": "Posicionamiento", |
|||
"LimitedDiscovery": "Descubrimiento limitado" |
|||
}, |
|||
"majorDevice": { |
|||
"group": "Dispositivo principal", |
|||
"Uncategorized": "Sin categorizar", |
|||
"Miscellaneous": "Diverso", |
|||
"Toy": "Juguete", |
|||
"Wearable": "Usable", |
|||
"Imaging": "Imágenes", |
|||
"Peripheral": "Periférico", |
|||
"AudioVideo": "Medios de comunicación", |
|||
"AccessPoint": "Punto de acceso", |
|||
"Phone": "Teléfono", |
|||
"Computer": "Computadora" |
|||
}, |
|||
"minorDevice": { |
|||
"group": "Dispositivo menor", |
|||
"None": "No hay dispositivos menores", |
|||
"Toy": { |
|||
"Game": "Juego", |
|||
"Controller": "Controlador", |
|||
"Doll": "Muñeca", |
|||
"Vehicle": "Vehículo", |
|||
"Robot": "Robot" |
|||
}, |
|||
"Wearable": { |
|||
"Watch": "Reloj", |
|||
"Pager": "Buscapersonas", |
|||
"Jacket": "Chaqueta", |
|||
"Helmet": "Casco", |
|||
"Glasses": "Lentes" |
|||
}, |
|||
"Imaging": { |
|||
"Display": "Monitor", |
|||
"Camera": "Cámara", |
|||
"Scanner": "Escáner", |
|||
"Printer": "Impresora" |
|||
}, |
|||
"Peripheral": { |
|||
"Keyboard": "Teclado", |
|||
"Pointer": "Puntero", |
|||
"Uncategorized": "Sin categorizar", |
|||
"Joystick": "Palanca de mando", |
|||
"Gamepad": "Gamepad", |
|||
"RemoteControl": "Control remoto", |
|||
"Sensor": "Sensor", |
|||
"Digitizer": "Digitalizador", |
|||
"CardReader": "Lector de tarjetas" |
|||
}, |
|||
"AudioVideo": { |
|||
"Uncategorized": "Sin categorizar", |
|||
"Headset": "Auriculares", |
|||
"Microphone": "Micrófono", |
|||
"Loudspeaker": "Altoparlante", |
|||
"Headphones": "Auriculares", |
|||
"CarAudio": "Audio del coche", |
|||
"VideoCamera": "Camara de video", |
|||
"Monitor": "Monitor", |
|||
"Conferencing": "Conferencia" |
|||
}, |
|||
"AccessPoint": { |
|||
"Available": "Disponible", |
|||
"Level1": "1-17% de uso", |
|||
"Level2": "17-33% de uso", |
|||
"Level3": "33-50% de uso", |
|||
"Level4": "50-67% de uso", |
|||
"Level5": "67-83% de uso", |
|||
"Level6": "83-99% de uso", |
|||
"Unavailable": "Indisponible" |
|||
}, |
|||
"Phone": { |
|||
"Uncategorized": "Sin categorizar", |
|||
"Cell": "Célula", |
|||
"Cordless": "Sin cable" |
|||
}, |
|||
"Computer": { |
|||
"Uncategorized": "Sin categorizar", |
|||
"Desktop": "Escritorio", |
|||
"Server": "Servidor", |
|||
"Laptop": "Ordenador portátil", |
|||
"PDA": "PDA", |
|||
"Watch": "Reloj" |
|||
} |
|||
} |
|||
} |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
@ -1,31 +0,0 @@ |
|||
{ |
|||
"hosting": { |
|||
"public": "dist", |
|||
"rewrites": [ |
|||
{ |
|||
"source": "**", |
|||
"destination": "/index.html" |
|||
} |
|||
], |
|||
"headers": [ |
|||
{ |
|||
"source": "**/*.@(css|js)", |
|||
"headers": [ |
|||
{ |
|||
"key": "Cache-Control", |
|||
"value": "max-age=604800" |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"source": "/", |
|||
"headers": [ |
|||
{ |
|||
"key": "Link", |
|||
"value": "</index.js>;rel=preload;as=script,</index.css>;rel=preload;as=style" |
|||
} |
|||
] |
|||
} |
|||
] |
|||
} |
|||
} |
@ -1,89 +0,0 @@ |
|||
const browserSync = require("browser-sync").create(); |
|||
const cacheBuster = require("gulp-cache-bust"); |
|||
const clean = require("gulp-clean"); |
|||
const concat = require("gulp-concat"); |
|||
const gulp = require("gulp"); |
|||
const include = require("gulp-include"); |
|||
const pug = require("gulp-pug"); |
|||
const sass = require("gulp-sass"); |
|||
const terser = require("gulp-terser"); |
|||
|
|||
// Creating objects for/from NPM modules
|
|||
const srcDir = "src"; |
|||
const outDir = "dist"; |
|||
|
|||
// Clean the build directory
|
|||
gulp.task("clean", function () { |
|||
return gulp |
|||
.src(outDir, {allowEmpty: true}) |
|||
.pipe(clean()); |
|||
}); |
|||
|
|||
// Copy assets to the build directory
|
|||
gulp.task("assets", function () { |
|||
return gulp |
|||
.src(`${srcDir}/assets/**/*`) |
|||
.pipe(gulp.dest(outDir)) |
|||
.pipe(browserSync.stream()); |
|||
}); |
|||
|
|||
// Process all of our SCSS files into the build
|
|||
gulp.task("css", function () { |
|||
return gulp |
|||
.src(`${srcDir}/styles/index.scss`) |
|||
.pipe(sass({outputStyle: "compressed"}).on("error", sass.logError)) |
|||
.pipe(concat("index.css")) |
|||
.pipe(gulp.dest(outDir)) |
|||
.pipe(browserSync.stream()); |
|||
}); |
|||
|
|||
// Process all of our HTML files into the build
|
|||
gulp.task("html", function () { |
|||
return gulp |
|||
.src(`${srcDir}/routes/**/*.pug`) |
|||
.pipe(pug()) |
|||
.pipe(gulp.dest(outDir)) |
|||
.pipe(browserSync.stream()); |
|||
}); |
|||
|
|||
// Process all of our JS files into the build
|
|||
gulp.task("js", function () { |
|||
return gulp |
|||
.src(`${srcDir}/scripts/index.js`) |
|||
.pipe(include()) |
|||
.pipe(terser()) |
|||
.pipe(gulp.dest(outDir)) |
|||
.pipe(browserSync.stream()); |
|||
}); |
|||
|
|||
// Start a BrowserSync server that executes tasks on file changes
|
|||
gulp.task("sync", function () { |
|||
|
|||
browserSync.init({ |
|||
server: { |
|||
baseDir: `${outDir}/`, |
|||
serveStaticOptions: { |
|||
extensions: ["html"], |
|||
}, |
|||
}, |
|||
}); |
|||
|
|||
gulp.watch(`${srcDir}/assets/**/*`, gulp.series("assets")); |
|||
gulp.watch(`${srcDir}/**/*.scss`, gulp.series("css")); |
|||
gulp.watch(`${srcDir}/**/*.js`, gulp.series("js")); |
|||
gulp.watch(`${srcDir}/**/*.pug`, gulp.series("html", "css")); |
|||
}); |
|||
|
|||
// Create a production build
|
|||
|
|||
gulp.task("cacheBuster", function () { |
|||
return gulp |
|||
.src(`${outDir}/index.html`) |
|||
.pipe(cacheBuster()) |
|||
.pipe(gulp.dest(outDir)) |
|||
}); |
|||
|
|||
gulp.task("build", gulp.series("clean", "assets", "html", "js", "css", "cacheBuster")); |
|||
|
|||
// Tasks run on default `gulp` invocation
|
|||
gulp.task("default", gulp.series("build", "sync")); |
File diff suppressed because it is too large
@ -1,26 +0,0 @@ |
|||
{ |
|||
"name": "bluetooth-class", |
|||
"version": "0.0.0", |
|||
"license": "MIT", |
|||
"private": true, |
|||
"scripts": { |
|||
"start": "gulp", |
|||
"build": "gulp build" |
|||
}, |
|||
"dependencies": { |
|||
"materialize-css": "^1.0.0" |
|||
}, |
|||
"devDependencies": { |
|||
"browser-sync": "^2.26.3", |
|||
"firebase-tools": "^6.4.0", |
|||
"gulp": "^4.0.0", |
|||
"gulp-cache-bust": "^1.4.0", |
|||
"gulp-clean": "^0.4.0", |
|||
"gulp-concat": "^2.6.1", |
|||
"gulp-include": "^2.3.1", |
|||
"gulp-pug": "^4.0.1", |
|||
"gulp-sass": "^4.0.2", |
|||
"gulp-terser": "^1.1.6", |
|||
"gulp-uglify": "^3.0.1" |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
extends ../templates/layout |
|||
|
|||
block content |
|||
|
|||
h1(i18n="bluetoothClass") BlueTooth class |
|||
|
|||
form |
|||
|
|||
.row.center-align |
|||
.input-field.col.s4.offset-s4 |
|||
p#bluetoothClass.text-center.underlined(onclick="copyBluetoothClassField()") |
|||
span.helper-text(i18n="clickToCopy") Click to copy |
|||
|
|||
h2(i18n="majorService.group") Major service |
|||
include ../templates/major-service |
|||
|
|||
h3(i18n="majorDevice.group") Major device |
|||
include ../templates/major-device |
|||
|
|||
h4(i18n="minorDevice.group") Minor device |
|||
include ../templates/minor-device |
@ -0,0 +1,68 @@ |
|||
let bluetoothClass = 0; |
|||
|
|||
// Grab references to our DOM elements
|
|||
const bluetoothClassField = document.getElementById("bluetoothClass"); |
|||
const minorDeviceGroups = document.querySelectorAll("[class^='minor-devices'] > *"); |
|||
const checkboxesAndRadios = document.querySelectorAll("input[type='checkbox'], input[type='radio']"); |
|||
|
|||
/** |
|||
* Write a hex string of our current Bluetooth class to the input |
|||
*/ |
|||
function updateBluetoothClassField() { |
|||
let hex = bluetoothClass.toString(16); |
|||
hex = hex.toLocaleUpperCase(); |
|||
hex = hex.padStart(6, "0"); |
|||
hex = "0x" + hex; |
|||
bluetoothClassField.innerHTML = hex; |
|||
} |
|||
|
|||
/** |
|||
* Copy the current value of the Bluetooth class field to the clipboard |
|||
*/ |
|||
function copyBluetoothClassField() { |
|||
navigator.clipboard.writeText(bluetoothClassField.innerHTML); |
|||
} |
|||
|
|||
/** |
|||
* Depending on our selected major device category, hide or show groups of minor devices |
|||
*/ |
|||
function updateBluetoothMinorDeviceFields() { |
|||
|
|||
// Determine the ID of the selected major device
|
|||
const majorDevice = bluetoothClass & 0x1F00; |
|||
const majorDeviceRadio = document.querySelector(`input[type='radio'][name='majorDevice'][value='${majorDevice}']`); |
|||
const majorDeviceId = majorDeviceRadio.id.replace("majorDevice", ""); |
|||
|
|||
// Hide all minor device fields that don't match our major device id and uncheck them
|
|||
minorDeviceGroups.forEach((element) => { |
|||
element.querySelectorAll("input").forEach((minorDevice) => minorDevice.checked = false); |
|||
element.classList.add("hidden"); |
|||
if (element.classList.contains(majorDeviceId)) { |
|||
element.classList.remove("hidden"); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// Watch the page checkboxes and radio buttons for updating the Bluetooth class
|
|||
checkboxesAndRadios.forEach((element) => { |
|||
element.addEventListener("change", () => { |
|||
|
|||
if (element.id.startsWith("majorService")) { |
|||
// Major services can be combined, so XOR is all we need
|
|||
bluetoothClass ^= element.value; |
|||
} else if (element.id.startsWith("majorDevice")) { |
|||
// Major devices cannot conflict, so zero out any current major and minor devices
|
|||
bluetoothClass = (bluetoothClass & ~0x1FFC) | element.value; |
|||
updateBluetoothMinorDeviceFields(); |
|||
} else if (element.id.startsWith("minorDevice")) { |
|||
// Minor devices cannot conflict, so zero out any current minor devices
|
|||
bluetoothClass = (bluetoothClass & ~0xFC) | element.value; |
|||
} |
|||
|
|||
updateBluetoothClassField(); |
|||
}); |
|||
}); |
|||
|
|||
// Default the bluetooth class field and minor device fields on page load
|
|||
updateBluetoothClassField(); |
|||
updateBluetoothMinorDeviceFields(); |
@ -0,0 +1,14 @@ |
|||
// Materialize CSS
|
|||
//=require ../../../node_modules/materialize-css/js/cash.js
|
|||
//=require ../../../node_modules/materialize-css/js/global.js
|
|||
//=require ../../../node_modules/materialize-css/js/component.js
|
|||
//=require ../../../node_modules/materialize-css/js/anime.min.js
|
|||
//=require ../../../node_modules/materialize-css/js/buttons.js
|
|||
//=require ../../../node_modules/materialize-css/js/forms.js
|
|||
//=require ../../../node_modules/materialize-css/js/waves.js
|
|||
|
|||
// Internationalization script shared between sites in root of project sub-modules
|
|||
//=require ../../shared/scripts/i18n.js
|
|||
|
|||
// Project scripts
|
|||
//=require bluetooth.js
|
@ -1,2 +0,0 @@ |
|||
User-agent: * |
|||
Disallow: |
@ -1,21 +0,0 @@ |
|||
extends ../templates/layout |
|||
|
|||
block content |
|||
|
|||
h1(i18n="bluetoothClass") BlueTooth class |
|||
|
|||
form |
|||
|
|||
.row.center-align |
|||
.input-field.col.s4.offset-s4 |
|||
input#bluetoothClass.text-center(type="text", readonly, onclick="copyBluetoothClassField()") |
|||
span.helper-text(i18n="clickToCopy") Click to copy |
|||
|
|||
h2(i18n="majorService.group") Major service |
|||
include ../templates/major-service |
|||
|
|||
h3(i18n="majorDevice.group") Major device |
|||
include ../templates/major-device |
|||
|
|||
h4(i18n="minorDevice.group") Minor device |
|||
include ../templates/minor-device |
@ -1,68 +0,0 @@ |
|||
let bluetoothClass = 0; |
|||
|
|||
// Grab references to our DOM elements
|
|||
const bluetoothClassField = document.getElementById("bluetoothClass"); |
|||
const minorDeviceGroups = document.querySelectorAll("[class^='minor-devices'] > *"); |
|||
const checkboxesAndRadios = document.querySelectorAll("input[type='checkbox'], input[type='radio']"); |
|||
|
|||
/** |
|||
* Write a hex string of our current Bluetooth class to the input |
|||
*/ |
|||
function updateBluetoothClassField() { |
|||
let hex = bluetoothClass.toString(16); |
|||
hex = hex.toLocaleUpperCase(); |
|||
hex = hex.padStart(6, "0"); |
|||
hex = "0x" + hex; |
|||
bluetoothClassField.value = hex; |
|||
} |
|||
|
|||
/** |
|||
* Copy the current value of the Bluetooth class field to the clipboard |
|||
*/ |
|||
function copyBluetoothClassField() { |
|||
navigator.clipboard.writeText(bluetoothClassField.value); |
|||
} |
|||
|
|||
/** |
|||
* Depending on our selected major device category, hide or show groups of minor devices |
|||
*/ |
|||
function updateBluetoothMinorDeviceFields() { |
|||
|
|||
// Determine the ID of the selected major device
|
|||
const majorDevice = bluetoothClass & 0x1F00; |
|||
const majorDeviceRadio = document.querySelector(`input[type='radio'][name='majorDevice'][value='${majorDevice}']`); |
|||
const majorDeviceId = majorDeviceRadio.id.replace("majorDevice", ""); |
|||
|
|||
// Hide all minor device fields that don't match our major device id and uncheck them
|
|||
minorDeviceGroups.forEach((element) => { |
|||
element.querySelectorAll("input").forEach((minorDevice) => minorDevice.checked = false); |
|||
element.classList.add("hidden"); |
|||
if (element.classList.contains(majorDeviceId)) { |
|||
element.classList.remove("hidden"); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// Watch the page checkboxes and radio buttons for updating the Bluetooth class
|
|||
checkboxesAndRadios.forEach((element) => { |
|||
element.addEventListener("change", () => { |
|||
|
|||
if (element.id.startsWith("majorService")) { |
|||
// Major services can be combined, so XOR is all we need
|
|||
bluetoothClass ^= element.value; |
|||
} else if (element.id.startsWith("majorDevice")) { |
|||
// Major devices cannot conflict, so zero out any current major and minor devices
|
|||
bluetoothClass = (bluetoothClass & ~0x1FFC) | element.value; |
|||
updateBluetoothMinorDeviceFields(); |
|||
} else if (element.id.startsWith("minorDevice")) { |
|||
// Minor devices cannot conflict, so zero out any current minor devices
|
|||
bluetoothClass = (bluetoothClass & ~0xFC) | element.value; |
|||
} |
|||
|
|||
updateBluetoothClassField(); |
|||
}); |
|||
}); |
|||
|
|||
// Default the bluetooth class field and minor device fields on page load
|
|||
updateBluetoothClassField(); |
|||
updateBluetoothMinorDeviceFields(); |
@ -1,114 +0,0 @@ |
|||
// Specify the languages this application can use
|
|||
const languageWhitelist = ["en", "es"]; |
|||
|
|||
// Determine the current language that should be used, with English as a fallback
|
|||
let languageCurrent = [localStorage.getItem("language"), ...navigator.languages] |
|||
.filter((language) => languageWhitelist.includes(language)) |
|||
.find((language) => (language == null) ? "en" : language); |
|||
|
|||
// Fetch our translation files
|
|||
const languageTranslations = {}; |
|||
languageWhitelist.forEach((language) => { |
|||
fetch(`/${language}.json`) |
|||
.then((response) => response.json()) |
|||
.then((translations) => { |
|||
languageTranslations[language] = translations; |
|||
if (languageCurrent === language) { |
|||
languageChange(languageCurrent); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
/** |
|||
* Language change handler for updating page text |
|||
* |
|||
* @param language Two character country code for translation language |
|||
*/ |
|||
function languageChange(language) { |
|||
|
|||
// Save the current language choice
|
|||
languageCurrent = language; |
|||
localStorage.setItem("language", language); |
|||
|
|||
// Set HTML language attribute
|
|||
document.querySelector("html").setAttribute("lang", language); |
|||
|
|||
// Set active language selector underlines
|
|||
document.querySelectorAll("footer button").forEach((element) => { |
|||
element.classList.remove("underlined"); |
|||
if (element.id === `${language}I18nButton`) { |
|||
element.classList.add("underlined"); |
|||
} |
|||
}); |
|||
|
|||
// Translate text
|
|||
document.querySelectorAll("[i18n]").forEach((element) => translateElement(element)); |
|||
} |
|||
|
|||
/** |
|||
* Return translated text based on key-value matching above |
|||
* |
|||
* @param path Translation specifier in above translation map, like majorService.title |
|||
*/ |
|||
function translateKey(path) { |
|||
|
|||
let translation; |
|||
|
|||
if (path != null) { |
|||
translation = languageTranslations[languageCurrent] |
|||
path.split(".").forEach((key) => { |
|||
if (translation != null) { |
|||
translation = translation[key]; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
return translation == null ? "" : translation; |
|||
} |
|||
|
|||
/** |
|||
* Set inner HTML to translated text based on i18n attribute of given element |
|||
* |
|||
* @param element Root element to translate |
|||
*/ |
|||
function translateElement(element) { |
|||
const attribute = element.attributes.getNamedItem("i18n"); |
|||
element.innerHTML = translateKey(attribute.value); |
|||
} |
|||
|
|||
/** |
|||
* Translate any element with necessary attribute qualifier, including child elements |
|||
* |
|||
* @param element Root element to check for translations |
|||
*/ |
|||
function checkElementForTranslations(element) { |
|||
if (element instanceof HTMLElement) { |
|||
|
|||
// Translate element if necessary
|
|||
if (element.hasAttribute("i18n")) { |
|||
translateElement(element); |
|||
} |
|||
|
|||
// Recurse into each child element looking for more potential languageTranslations
|
|||
element.childNodes.forEach((childElement) => checkElementForTranslations(childElement)); |
|||
} |
|||
} |
|||
|
|||
// Call language change on page load to ensure languageTranslations are set
|
|||
// Check local storage / browser for desired language and supply the closest match we have
|
|||
languageChange(languageCurrent); |
|||
|
|||
// Watch the page HTML for changes to ensure translations are kept accurate
|
|||
|
|||
const mutationObserver = new MutationObserver((mutations) => { |
|||
mutations.forEach((mutation) => { |
|||
mutation.addedNodes.forEach((node) => { |
|||
checkElementForTranslations(node); |
|||
}); |
|||
}); |
|||
}); |
|||
|
|||
mutationObserver.observe(document.querySelector("body"), { |
|||
childList: true, |
|||
subtree: true, |
|||
}); |
@ -1,12 +0,0 @@ |
|||
// Materialize CSS
|
|||
//=require ../../node_modules/materialize-css/js/cash.js
|
|||
//=require ../../node_modules/materialize-css/js/global.js
|
|||
//=require ../../node_modules/materialize-css/js/component.js
|
|||
//=require ../../node_modules/materialize-css/js/anime.min.js
|
|||
//=require ../../node_modules/materialize-css/js/buttons.js
|
|||
//=require ../../node_modules/materialize-css/js/forms.js
|
|||
//=require ../../node_modules/materialize-css/js/waves.js
|
|||
|
|||
// Project scripts
|
|||
//=require bluetooth.js
|
|||
//=require i18n.js
|
@ -1,39 +0,0 @@ |
|||
// Color |
|||
@import "../../node_modules/materialize-css/sass/components/color-variables"; |
|||
// @import "../../node_modules/materialize-css/sass/components/color-classes"; |
|||
|
|||
// Variables |
|||
@import "../../node_modules/materialize-css/sass/components/variables"; |
|||
|
|||
// Reset |
|||
@import "../../node_modules/materialize-css/sass/components/normalize"; |
|||
|
|||
// Components |
|||
@import "../../node_modules/materialize-css/sass/components/global"; |
|||
// @import "../../node_modules/materialize-css/sass/components/badges"; |
|||
// @import "../../node_modules/materialize-css/sass/components/icons-material-design"; |
|||
@import "../../node_modules/materialize-css/sass/components/grid"; |
|||
// @import "../../node_modules/materialize-css/sass/components/navbar"; |
|||
@import "../../node_modules/materialize-css/sass/components/typography"; |
|||
// @import "../../node_modules/materialize-css/sass/components/transitions"; |
|||
// @import "../../node_modules/materialize-css/sass/components/cards"; |
|||
// @import "../../node_modules/materialize-css/sass/components/toast"; |
|||
// @import "../../node_modules/materialize-css/sass/components/tabs"; |
|||
// @import "../../node_modules/materialize-css/sass/components/tooltip"; |
|||
@import "../../node_modules/materialize-css/sass/components/buttons"; |
|||
// @import "../../node_modules/materialize-css/sass/components/dropdown"; |
|||
@import "../../node_modules/materialize-css/sass/components/waves"; |
|||
// @import "../../node_modules/materialize-css/sass/components/modal"; |
|||
// @import "../../node_modules/materialize-css/sass/components/collapsible"; |
|||
// @import "../../node_modules/materialize-css/sass/components/chips"; |
|||
// @import "../../node_modules/materialize-css/sass/components/materialbox"; |
|||
@import "../../node_modules/materialize-css/sass/components/forms/forms"; |
|||
// @import "../../node_modules/materialize-css/sass/components/table_of_contents"; |
|||
// @import "../../node_modules/materialize-css/sass/components/sidenav"; |
|||
// @import "../../node_modules/materialize-css/sass/components/preloader"; |
|||
// @import "../../node_modules/materialize-css/sass/components/slider"; |
|||
// @import "../../node_modules/materialize-css/sass/components/carousel"; |
|||
// @import "../../node_modules/materialize-css/sass/components/tapTarget"; |
|||
// @import "../../node_modules/materialize-css/sass/components/pulse"; |
|||
// @import "../../node_modules/materialize-css/sass/components/datepicker"; |
|||
// @import "../../node_modules/materialize-css/sass/components/timepicker"; |
@ -1,21 +0,0 @@ |
|||
// Pushing footer to bottom of page |
|||
|
|||
body { |
|||
display: flex; |
|||
flex-direction: column; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
main { |
|||
flex: 1 0 auto; |
|||
} |
|||
|
|||
// Off-white background colors |
|||
body { |
|||
background-color: whitesmoke; |
|||
} |
|||
|
|||
// Content breathing room |
|||
footer { |
|||
margin: 20px 0; |
|||
} |
@ -1,32 +0,0 @@ |
|||
doctype html |
|||
|
|||
html(lang="en") |
|||
|
|||
head |
|||
|
|||
meta(charset="utf-8") |
|||
meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no") |
|||
meta(name="description", content="Builder for hcitool class codes") |
|||
|
|||
title(i18n="bluetoothClass") BlueTooth Class |
|||
|
|||
link(rel="shortcut icon", href="/favicon.ico") |
|||
link(rel="stylesheet", href="/index.css") |
|||
|
|||
body.container |
|||
|
|||
.text-center |
|||
noscript This application requires JavaScript to run! |
|||
main |
|||
block content |
|||
|
|||
footer.center-align |
|||
div |
|||
button#enI18nButton.btn-flat.waves-effect.waves-light(onclick="languageChange('en')") English |
|||
button#esI18nButton.btn-flat.waves-effect.waves-light(onclick="languageChange('es')") Español |
|||
h5 |
|||
span(i18n="builtBy") Built by |
|||
a(href="https://mobiusk.com") MobiusK |
|||
|
|||
block scripts |
|||
script(src="/index.js") |
@ -1,20 +0,0 @@ |
|||
- |
|||
const majorDevices = { |
|||
"Uncategorized": 0x1F00, |
|||
"Toy": 0x0800, |
|||
"Wearable": 0x0700, |
|||
"Imaging": 0x0600, |
|||
"Peripheral": 0x0500, |
|||
"AudioVideo": 0x0400, |
|||
"AccessPoint": 0x0300, |
|||
"Phone": 0x0200, |
|||
"Computer": 0x0100, |
|||
"Miscellaneous": 0x0000, |
|||
} |
|||
|
|||
.row |
|||
each value, key in majorDevices |
|||
.col.s12.m6.l4 |
|||
label(for="majorDevice" + key) |
|||
input.with-gap(type="radio", name="majorDevice", id="majorDevice" + key, value=value) |
|||
span(i18n="majorDevice." + key) #{key} |
@ -1,19 +0,0 @@ |
|||
- |
|||
const majorServices = { |
|||
"Information": 0x800000, |
|||
"Telephony": 0x400000, |
|||
"Audio": 0x200000, |
|||
"Transfer": 0x100000, |
|||
"Capturing": 0x080000, |
|||
"Rendering": 0x040000, |
|||
"AccessPoint": 0x020000, |
|||
"Positioning": 0x010000, |
|||
"LimitedDiscovery": 0x002000 |
|||
} |
|||
|
|||
.row |
|||
each value, key in majorServices |
|||
.col.s12.m6.l4 |
|||
label(for="majorService" + key) |
|||
input(type="checkbox", id="majorService" + key, value=value) |
|||
span(i18n="majorService." + key) #{key} |
@ -1,82 +0,0 @@ |
|||
- |
|||
const minorDevices = { |
|||
"Toy": { |
|||
"Game": 0x14, |
|||
"Controller": 0x10, |
|||
"Doll": 0x0C, |
|||
"Vehicle": 0x08, |
|||
"Robot": 0x04, |
|||
}, |
|||
"Wearable": { |
|||
"Glasses": 0x14, |
|||
"Helmet": 0x10, |
|||
"Jacket": 0x0C, |
|||
"Pager": 0x08, |
|||
"Watch": 0x04, |
|||
}, |
|||
"Imaging": { |
|||
"Display": 0x10, |
|||
"Camera": 0x20, |
|||
"Scanner": 0x40, |
|||
"Printer": 0x80, |
|||
}, |
|||
"Peripheral": { |
|||
"Uncategorized": 0x00, |
|||
"Keyboard": 0x40, |
|||
"Pointer": 0x80, |
|||
"Joystick": 0x04, |
|||
"Gamepad": 0x08, |
|||
"RemoteControl": 0x0C, |
|||
"Sensor": 0x10, |
|||
"Digitizer": 0x14, |
|||
"CardReader": 0x18, |
|||
}, |
|||
"AudioVideo": { |
|||
"Uncategorized": 0x00, |
|||
"Headset": 0x04, |
|||
"Microphone": 0x10, |
|||
"Loudspeaker": 0x14, |
|||
"Headphones": 0x18, |
|||
"CarAudio": 0x20, |
|||
"VideoCamera": 0x30, |
|||
"Monitor": 0x38, |
|||
"Conferencing": 0x40, |
|||
}, |
|||
"AccessPoint": { |
|||
"Available": 0x00, |
|||
"Level1": 0x20, |
|||
"Level2": 0x40, |
|||
"Level3": 0x60, |
|||
"Level4": 0x80, |
|||
"Level5": 0xA0, |
|||
"Level6": 0xC0, |
|||
"Unavailable": 0xE0, |
|||
}, |
|||
"Phone": { |
|||
"Uncategorized": 0x00, |
|||
"Cell": 0x04, |
|||
"Cordless": 0x08, |
|||
}, |
|||
"Computer": { |
|||
"Uncategorized": 0x00, |
|||
"Desktop": 0x04, |
|||
"Server": 0x08, |
|||
"Laptop": 0x0C, |
|||
"PDA": 0x14, |
|||
"Watch": 0x18, |
|||
}, |
|||
"Miscellaneous": {}, |
|||
"Uncategorized": {} |
|||
} |
|||
|
|||
.minor-devices |
|||
each devices, groupKey in minorDevices |
|||
.row(class=groupKey) |
|||
each value, key in devices |
|||
.col.s12.m6.l4 |
|||
label(for="minorDevice" + groupKey + key) |
|||
input.with-gap(type="radio", name="minorDevice" + groupKey, id="minorDevice" + groupKey + key, value=value) |
|||
span(i18n="minorDevice." + groupKey + "." + key) #{key} |
|||
else |
|||
.col.s12 |
|||
p(i18n="minorDevice.None") No minor devices |
@ -0,0 +1,39 @@ |
|||
// Color |
|||
@import "../../../node_modules/materialize-css/sass/components/color-variables"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/color-classes"; |
|||
|
|||
// Variables |
|||
@import "../../../node_modules/materialize-css/sass/components/variables"; |
|||
|
|||
// Reset |
|||
@import "../../../node_modules/materialize-css/sass/components/normalize"; |
|||
|
|||
// Components |
|||
@import "../../../node_modules/materialize-css/sass/components/global"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/badges"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/icons-material-design"; |
|||
@import "../../../node_modules/materialize-css/sass/components/grid"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/navbar"; |
|||
@import "../../../node_modules/materialize-css/sass/components/typography"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/transitions"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/cards"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/toast"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/tabs"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/tooltip"; |
|||
@import "../../../node_modules/materialize-css/sass/components/buttons"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/dropdown"; |
|||
@import "../../../node_modules/materialize-css/sass/components/waves"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/modal"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/collapsible"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/chips"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/materialbox"; |
|||
@import "../../../node_modules/materialize-css/sass/components/forms/forms"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/table_of_contents"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/sidenav"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/preloader"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/slider"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/carousel"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/tapTarget"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/pulse"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/datepicker"; |
|||
// @import "../../../node_modules/materialize-css/sass/components/timepicker"; |
@ -1,13 +1,13 @@ |
|||
// Bluetooth blue: #3B5998 |
|||
// Darker blue: #14306B |
|||
// Paletton: http://paletton.com/#uid=23K0u0klOszcgHQhAwKqLpHt8k9 |
|||
|
|||
$primary-color: #3B5998; |
|||
$secondary-color: #14306B; |
|||
|
|||
$h1-fontsize: 1.90rem; |
|||
$h2-fontsize: 1.78rem; |
|||
$h3-fontsize: 1.46rem; |
|||
$h4-fontsize: 1.30rem; |
|||
$h5-fontsize: 1.15rem; |
|||
$h6-fontsize: 1.00rem; |
|||
// Bluetooth blue: #3B5998 |
|||
// Darker blue: #14306B |
|||
// Paletton: http://paletton.com/#uid=23K0u0klOszcgHQhAwKqLpHt8k9 |
|||
|
|||
$primary-color: #3B5998; |
|||
$secondary-color: #14306B; |
|||
|
|||
$h1-fontsize: 1.90rem; |
|||
$h2-fontsize: 1.78rem; |
|||
$h3-fontsize: 1.46rem; |
|||
$h4-fontsize: 1.30rem; |
|||
$h5-fontsize: 1.15rem; |
|||
$h6-fontsize: 1.00rem; |
@ -0,0 +1,21 @@ |
|||
// Pushing footer to bottom of page |
|||
|
|||
body { |
|||
display: flex; |
|||
flex-direction: column; |
|||
min-height: 100vh; |
|||
} |
|||
|
|||
main { |
|||
flex: 1 0 auto; |
|||
} |
|||
|
|||
// Off-white background colors |
|||
body { |
|||
background-color: whitesmoke; |
|||
} |
|||
|
|||
// Content breathing room |
|||
footer { |
|||
margin: 20px 0; |
|||
} |
@ -1,40 +1,40 @@ |
|||
// Global variables |
|||
@import "variables"; |
|||
|
|||
// Material framework |
|||
@import "material"; |
|||
|
|||
// Content wrap styles |
|||
@import "wrapper"; |
|||
|
|||
// Give anchors and top level headers our branding color |
|||
a, h1 { |
|||
color: $primary-color; |
|||
} |
|||
|
|||
// Our input text fields are all either readonly |
|||
input[type='text'] { |
|||
cursor: default; |
|||
} |
|||
|
|||
// Self-explanatory |
|||
.text-center { |
|||
text-align: center; |
|||
} |
|||
|
|||
// Hide fields as necessary |
|||
.hidden { |
|||
display: none; |
|||
} |
|||
|
|||
// Make our checkbox labels all the same width, and a more readable color |
|||
label span { |
|||
color: rgba(0,0,0,0.72); |
|||
min-width: 190px; |
|||
} |
|||
|
|||
// Utility class for underlining text |
|||
.underlined { |
|||
text-decoration-color: $primary-color !important; |
|||
text-decoration: underline; |
|||
} |
|||
// Global variables |
|||
@import "variables"; |
|||
|
|||
// Material framework |
|||
@import "material"; |
|||
|
|||
// Content wrap styles |
|||
@import "wrapper"; |
|||
|
|||
// Give anchors and top level headers our branding color |
|||
a, h1 { |
|||
color: $primary-color; |
|||
} |
|||
|
|||
// Our input text fields are all either readonly |
|||
input[type='text'] { |
|||
cursor: default; |
|||
} |
|||
|
|||
// Self-explanatory |
|||
.text-center { |
|||
text-align: center; |
|||
} |
|||
|
|||
// Hide fields as necessary |
|||
.hidden { |
|||
display: none; |
|||
} |
|||
|
|||
// Make our checkbox labels all the same width, and a more readable color |
|||
label span { |
|||
color: rgba(0, 0, 0, 0.72); |
|||
min-width: 190px; |
|||
} |
|||
|
|||
// Utility class for underlining text |
|||
.underlined { |
|||
text-decoration-color: $primary-color !important; |
|||
text-decoration: underline; |
|||
} |
@ -0,0 +1,32 @@ |
|||
doctype html |
|||
|
|||
html(lang="en") |
|||
|
|||
head |
|||
|
|||
meta(charset="utf-8") |
|||
meta(name="viewport", content="width=device-width, initial-scale=1, shrink-to-fit=no") |
|||
meta(name="description", content="Builder for hcitool class codes") |
|||
|
|||
title(i18n="bluetoothClass") BlueTooth Class |
|||
|
|||
link(rel="shortcut icon", href="/favicon.ico") |
|||
link(rel="stylesheet", href="/index.css") |
|||
|
|||
body.container |
|||
|
|||
.text-center |
|||
noscript This application requires JavaScript to run! |
|||
main |
|||
block content |
|||
|
|||
footer.center-align |
|||
div |
|||
button#enI18nButton.btn-flat.waves-effect.waves-light(onclick="languageChange('en')") English |
|||
button#esI18nButton.btn-flat.waves-effect.waves-light(onclick="languageChange('es')") Español |
|||
h5 |
|||
span(i18n="builtBy") Built by |
|||
a(href="https://mobiusk.com") MobiusK |
|||
|
|||
block scripts |
|||
script(src="/index.js") |
@ -0,0 +1,20 @@ |
|||
- |
|||
const majorDevices = { |
|||
"Uncategorized": 0x1F00, |
|||
"Toy": 0x0800, |
|||
"Wearable": 0x0700, |
|||
"Imaging": 0x0600, |
|||
"Peripheral": 0x0500, |
|||
"AudioVideo": 0x0400, |
|||
"AccessPoint": 0x0300, |
|||
"Phone": 0x0200, |
|||
"Computer": 0x0100, |
|||
"Miscellaneous": 0x0000, |
|||
} |
|||
|
|||
.row |
|||
each value, key in majorDevices |
|||
.col.s12.m6.l4 |
|||
label(for="majorDevice" + key) |
|||
input.with-gap(type="radio", name="majorDevice", id="majorDevice" + key, value=value) |
|||
span(i18n="majorDevice." + key) #{key} |
@ -0,0 +1,19 @@ |
|||
- |
|||
const majorServices = { |
|||
"Information": 0x800000, |
|||
"Telephony": 0x400000, |
|||
"Audio": 0x200000, |
|||
"Transfer": 0x100000, |
|||
"Capturing": 0x080000, |
|||
"Rendering": 0x040000, |
|||
"AccessPoint": 0x020000, |
|||
"Positioning": 0x010000, |
|||
"LimitedDiscovery": 0x002000 |
|||
} |
|||
|
|||
.row |
|||
each value, key in majorServices |
|||
.col.s12.m6.l4 |
|||
label(for="majorService" + key) |
|||
input(type="checkbox", id="majorService" + key, value=value) |
|||
span(i18n="majorService." + key) #{key} |
@ -0,0 +1,82 @@ |
|||
- |
|||
const minorDevices = { |
|||
"Toy": { |
|||
"Game": 0x14, |
|||
"Controller": 0x10, |
|||
"Doll": 0x0C, |
|||
"Vehicle": 0x08, |
|||
"Robot": 0x04, |
|||
}, |
|||
"Wearable": { |
|||
"Glasses": 0x14, |
|||
"Helmet": 0x10, |
|||
"Jacket": 0x0C, |
|||
"Pager": 0x08, |
|||
"Watch": 0x04, |
|||
}, |
|||
"Imaging": { |
|||
"Display": 0x10, |
|||
"Camera": 0x20, |
|||
"Scanner": 0x40, |
|||
"Printer": 0x80, |
|||
}, |
|||
"Peripheral": { |
|||
"Uncategorized": 0x00, |
|||
"Keyboard": 0x40, |
|||
"Pointer": 0x80, |
|||
"Joystick": 0x04, |
|||
"Gamepad": 0x08, |
|||
"RemoteControl": 0x0C, |
|||
"Sensor": 0x10, |
|||
"Digitizer": 0x14, |
|||
"CardReader": 0x18, |
|||
}, |
|||
"AudioVideo": { |
|||
"Uncategorized": 0x00, |
|||
"Headset": 0x04, |
|||
"Microphone": 0x10, |
|||
"Loudspeaker": 0x14, |
|||
"Headphones": 0x18, |
|||
"CarAudio": 0x20, |
|||
"VideoCamera": 0x30, |
|||
"Monitor": 0x38, |
|||
"Conferencing": 0x40, |
|||
}, |
|||
"AccessPoint": { |
|||
"Available": 0x00, |
|||
"Level1": 0x20, |
|||
"Level2": 0x40, |
|||
"Level3": 0x60, |
|||
"Level4": 0x80, |
|||
"Level5": 0xA0, |
|||
"Level6": 0xC0, |
|||
"Unavailable": 0xE0, |
|||
}, |
|||
"Phone": { |
|||
"Uncategorized": 0x00, |
|||
"Cell": 0x04, |
|||
"Cordless": 0x08, |
|||
}, |
|||
"Computer": { |
|||
"Uncategorized": 0x00, |
|||
"Desktop": 0x04, |
|||
"Server": 0x08, |
|||
"Laptop": 0x0C, |
|||
"PDA": 0x14, |
|||
"Watch": 0x18, |
|||
}, |
|||
"Miscellaneous": {}, |
|||
"Uncategorized": {} |
|||
} |
|||
|
|||
.minor-devices |
|||
each devices, groupKey in minorDevices |
|||
.row(class=groupKey) |
|||
each value, key in devices |
|||
.col.s12.m6.l4 |
|||
label(for="minorDevice" + groupKey + key) |
|||
input.with-gap(type="radio", name="minorDevice" + groupKey, id="minorDevice" + groupKey + key, value=value) |
|||
span(i18n="minorDevice." + groupKey + "." + key) #{key} |
|||
else |
|||
.col.s12 |
|||
p(i18n="minorDevice.None") No minor devices |
Loading…
Reference in new issue