mirror of
https://github.com/NaitLee/Cat-Printer.git
synced 2025-05-16 07:10:30 -07:00
clean js routine; concat script; try fix macos
This commit is contained in:
parent
002072b586
commit
1b4402c6d2
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
cd www
|
||||
npx tsc --allowJs --outFile main.comp.js polyfill.js i18n-ext.js i18n.js image.js accessibility.js main.js
|
||||
npx tsc $@ --allowJs --outFile main.comp.js $(cat all_js.txt)
|
||||
cd ..
|
||||
|
17
printer.py
17
printer.py
@ -364,11 +364,10 @@ class PrinterDriver(Commander):
|
||||
elif (identifier not in Models and
|
||||
identifier[2::3] != ':::::' and len(identifier.replace('-', '')) != 32):
|
||||
error('model-0-is-not-supported-yet', identifier, exception=PrinterError)
|
||||
scanner = BleakScanner()
|
||||
# scanner = BleakScanner()
|
||||
devices = self.loop(
|
||||
scanner.discover(self.scan_timeout)
|
||||
BleakScanner.discover(self.scan_timeout)
|
||||
)
|
||||
devices = [dev for dev in devices if dev.name in Models]
|
||||
if identifier is not None:
|
||||
if identifier in Models:
|
||||
devices = [dev for dev in devices if dev.name == identifier]
|
||||
@ -694,7 +693,7 @@ def main():
|
||||
'Run the `_main` routine while catching exceptions'
|
||||
try:
|
||||
_main()
|
||||
except (BleakError, AttributeError) as e:
|
||||
except BleakError as e:
|
||||
error_message = str(e)
|
||||
if (
|
||||
('not turned on' in error_message) or # windows or android
|
||||
@ -702,15 +701,15 @@ def main():
|
||||
getattr(e, 'dbus_error') == 'org.bluez.Error.NotReady')
|
||||
):
|
||||
fatal(I18n['please-enable-bluetooth'], code=ExitCodes.GeneralError)
|
||||
elif (
|
||||
(isinstance(e, AttributeError) and # macos, possibly?
|
||||
'CentralManagerDelegate' in error_message)
|
||||
):
|
||||
fatal(I18n['please-enable-bluetooth-or-try-to-reboot'], code=ExitCodes.GeneralError)
|
||||
else:
|
||||
raise
|
||||
except PrinterError as e:
|
||||
fatal(e.message_localized, code=ExitCodes.PrinterError)
|
||||
except RuntimeError as e:
|
||||
if 'no running event loop' in str(e):
|
||||
pass # non-sense
|
||||
else:
|
||||
raise
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
54
server.py
54
server.py
@ -46,6 +46,13 @@ def mime(url: str):
|
||||
'Get pre-defined MIME type of a certain url by extension name'
|
||||
return mime_type.get(url.rsplit('.', 1)[-1], mime_type['octet-stream'])
|
||||
|
||||
def concat_files(*paths, prefix_format='', buffer=4 * 1024 * 1024):
|
||||
for path in paths:
|
||||
yield prefix_format.format(path).encode('utf-8')
|
||||
with open(path, 'rb') as file:
|
||||
while data := file.read(buffer):
|
||||
yield data
|
||||
|
||||
class PrinterServerHandler(BaseHTTPRequestHandler):
|
||||
'(Local) server handler for Cat Printer Web interface'
|
||||
|
||||
@ -64,6 +71,7 @@ class PrinterServerHandler(BaseHTTPRequestHandler):
|
||||
_settings_blacklist = (
|
||||
'printer', 'is_android'
|
||||
)
|
||||
all_js: list = []
|
||||
|
||||
printer: PrinterDriver = PrinterDriver()
|
||||
|
||||
@ -84,17 +92,31 @@ class PrinterServerHandler(BaseHTTPRequestHandler):
|
||||
pass
|
||||
|
||||
def do_GET(self):
|
||||
'Called when server get a GET http request'
|
||||
path = 'www' + self.path
|
||||
if self.path == '/':
|
||||
path += 'index.html'
|
||||
if '/..' in path:
|
||||
'Called when server got a GET http request'
|
||||
# prepare
|
||||
path, _, _args = self.path.partition('?')
|
||||
if '/..' in path or '../' in path:
|
||||
return
|
||||
if path == '/':
|
||||
path += 'index.html'
|
||||
# special
|
||||
if path.startswith('/~'):
|
||||
action = path[2:]
|
||||
if action == 'every.js':
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', mime(path))
|
||||
self.end_headers()
|
||||
for data in concat_files(*(self.all_js), prefix_format='\n// {0}\n'):
|
||||
self.wfile.write(data)
|
||||
return
|
||||
path = 'www' + path
|
||||
# not found
|
||||
if not os.path.isfile(path):
|
||||
self.send_response(404)
|
||||
self.send_header('Content-Type', mime('txt'))
|
||||
self.end_headers()
|
||||
return
|
||||
# static
|
||||
self.send_response(200)
|
||||
self.send_header('Content-Type', mime(path))
|
||||
# self.send_header('Content-Size', str(os.stat(path).st_size))
|
||||
@ -214,7 +236,7 @@ class PrinterServerHandler(BaseHTTPRequestHandler):
|
||||
sys.exit(0)
|
||||
|
||||
def do_POST(self):
|
||||
'Called when server get a POST http request'
|
||||
'Called when server got a POST http request'
|
||||
content_length = int(self.headers.get('Content-Length', -1))
|
||||
if (content_length < -1 or
|
||||
content_length > self.max_payload
|
||||
@ -239,16 +261,22 @@ class PrinterServerHandler(BaseHTTPRequestHandler):
|
||||
'name': 'BleakError',
|
||||
'details': str(e)
|
||||
})
|
||||
except EOFError as e:
|
||||
# mostly, device disconnected but not by this program
|
||||
self.api_fail({
|
||||
'name': 'EOFError',
|
||||
'details': ''
|
||||
})
|
||||
except RuntimeError as e:
|
||||
self.api_fail({
|
||||
'name': 'RuntimeError',
|
||||
'details': str(e)
|
||||
})
|
||||
except PrinterError as e:
|
||||
self.api_fail({
|
||||
'name': e.message,
|
||||
'details': e.message_localized
|
||||
})
|
||||
except EOFError as e:
|
||||
self.api_fail({
|
||||
'name': 'EOFError',
|
||||
'details': ''
|
||||
})
|
||||
except Exception as e:
|
||||
self.api_fail({
|
||||
'name': 'Exception',
|
||||
@ -272,6 +300,10 @@ class PrinterServer(HTTPServer):
|
||||
def finish_request(self, request, client_address):
|
||||
if self.handler is None:
|
||||
self.handler = self.handler_class(request, client_address, self)
|
||||
with open(os.path.join('www', 'all_js.txt'), 'r', encoding='utf-8') as file:
|
||||
for path in file.read().split('\n'):
|
||||
if path != '':
|
||||
self.handler.all_js.append(os.path.join('www', path))
|
||||
return
|
||||
self.handler.__init__(request, client_address, self)
|
||||
|
||||
|
@ -39,22 +39,30 @@ function keyToLetter(key) {
|
||||
return map[key] || key;
|
||||
}
|
||||
|
||||
function keyFromCode(code) {
|
||||
const map = {
|
||||
9: 'Tab'
|
||||
};
|
||||
return map[code] || String.fromCharCode(code);
|
||||
}
|
||||
|
||||
function initKeyboardShortcuts() {
|
||||
const layer = document.getElementById('keyboard-shortcuts-layer');
|
||||
const dialog = document.getElementById('dialog');
|
||||
const keys = 'qwertyuiopasdfghjklzxcvbnm';
|
||||
let focusing = false, started = false;
|
||||
let shortcuts = {};
|
||||
let key, focus, inputs;
|
||||
let focus, inputs;
|
||||
const mark_keys = () => {
|
||||
let index;
|
||||
document.querySelectorAll(':focus').forEach(e => e.isSameNode(focus) || e.blur());
|
||||
let index, key;
|
||||
if (dialog.classList.contains('hidden'))
|
||||
inputs = Array.from(document.querySelectorAll('*[data-key]'));
|
||||
else inputs = Array.from(document.querySelectorAll('#dialog *[data-key]'));
|
||||
/** @type {{ [key: string]: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement }} */
|
||||
let keys2 = keys.split('');
|
||||
shortcuts = {};
|
||||
if (focusing) shortcuts = { ESC: focus };
|
||||
if (focusing) shortcuts = { 'ESC': focus };
|
||||
else
|
||||
for (let input of inputs) {
|
||||
if (isHidden(input)) continue;
|
||||
@ -69,14 +77,14 @@ function initKeyboardShortcuts() {
|
||||
layer.appendChild(span);
|
||||
}
|
||||
index = 0;
|
||||
for (let key in shortcuts) {
|
||||
for (key in shortcuts) {
|
||||
let span = layer.children[index++];
|
||||
let input = shortcuts[key];
|
||||
let position = input.getBoundingClientRect();
|
||||
let text = i18n(keyToLetter(key.toUpperCase()));
|
||||
if (span.innerText !== text) span.innerText = text;
|
||||
span.style.top = position.y + 'px';
|
||||
span.style.left = position.x + 'px';
|
||||
span.style.top = (position.y || position.top) + 'px';
|
||||
span.style.left = (position.x || position.left) + 'px';
|
||||
span.style.display = '';
|
||||
}
|
||||
for (let i = index; i < layer.children.length; i++) {
|
||||
@ -86,17 +94,15 @@ function initKeyboardShortcuts() {
|
||||
const start = () => setInterval(mark_keys, 1000);
|
||||
const types_to_click = ['submit', 'file', 'checkbox', 'radio', 'A'];
|
||||
document.body.addEventListener('keyup', (event) => {
|
||||
key = event.key;
|
||||
let key = event.key || keyFromCode(event.keyCode);
|
||||
if (!started) {
|
||||
if (key !== 'Tab') return;
|
||||
mark_keys();
|
||||
start();
|
||||
started = true;
|
||||
}
|
||||
document.body.addEventListener('keyup', () =>
|
||||
requestAnimationFrame(mark_keys)
|
||||
, { once: true });
|
||||
let input = shortcuts[key.toLocaleLowerCase()];
|
||||
requestAnimationFrame(mark_keys)
|
||||
let input = shortcuts[key];
|
||||
if (input) {
|
||||
if (types_to_click.includes(input.type || input.tagName))
|
||||
input.dispatchEvent(new MouseEvent(event.shiftKey ? 'contextmenu' : 'click'));
|
||||
@ -105,7 +111,7 @@ function initKeyboardShortcuts() {
|
||||
focusing = true;
|
||||
}
|
||||
focus = input;
|
||||
} else if (key === 'Escape' && focus) {
|
||||
} else if ((key === 'Escape' || !event.isTrusted) && focus) {
|
||||
focus.blur();
|
||||
focusing = !focusing;
|
||||
}
|
||||
|
6
www/all_js.txt
Normal file
6
www/all_js.txt
Normal file
@ -0,0 +1,6 @@
|
||||
polyfill.js
|
||||
i18n-ext.js
|
||||
i18n.js
|
||||
image.js
|
||||
accessibility.js
|
||||
main.js
|
@ -46,7 +46,7 @@
|
||||
</label> --><br />
|
||||
<!-- "brightness" is historically "threshold" -->
|
||||
<label for="threshold" data-i18n="brightness-">Brightness:</label>
|
||||
<input type="range" min="0" max="256" value="86" step="1" id="threshold" data-key data-default />
|
||||
<input type="range" min="0" max="256" value="86" step="16" id="threshold" data-key data-default />
|
||||
<br />
|
||||
<input type="checkbox" name="transparent-as-white" id="transparent-as-white" data-key checked />
|
||||
<label for="transparent-as-white" data-i18n="transparent-as-white">Transparent as White</label>
|
||||
|
@ -26,6 +26,18 @@
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a href="~every.js">~every.js</a></td>
|
||||
<td><a href="https://www.gnu.org/licenses/gpl-3.0.html">GPL-3.0</a></td>
|
||||
<td><a href="main.js">main.js</a></td>
|
||||
<td>Dynamic concatenation of all development scripts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="main.comp.js">main.comp.js</a></td>
|
||||
<td><a href="https://www.gnu.org/licenses/gpl-3.0.html">GPL-3.0</a></td>
|
||||
<td><a href="main.js">main.js</a></td>
|
||||
<td>All following development scripts, transpiled for compatibility.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="loader.js">loader.js</a></td>
|
||||
<td><a href="http://creativecommons.org/publicdomain/zero/1.0/legalcode">CC0-1.0</a></td>
|
||||
@ -33,10 +45,16 @@
|
||||
<td>For dynamically loading other scripts, and fallback if there are problems.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="image.js">image.js</a></td>
|
||||
<td><a href="polyfill.js">polyfill.js</a></td>
|
||||
<td><a href="http://creativecommons.org/publicdomain/zero/1.0/legalcode">CC0-1.0</a></td>
|
||||
<td><a href="image.js">image.js</a></td>
|
||||
<td>Contains functions for image manipulation and public algorithms of image monochrome filters.</td>
|
||||
<td><a href="polyfill.js">polyfill.js</a></td>
|
||||
<td>Put features that are not supported by old browsers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="i18n-ext.js">i18n-ext.js</a></td>
|
||||
<td><a href="http://creativecommons.org/publicdomain/zero/1.0/legalcode">CC0-1.0</a></td>
|
||||
<td><a href="i18n-ext.js">i18n-ext.js</a></td>
|
||||
<td>I18n "extensions"</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="i18n.js">i18n.js</a></td>
|
||||
@ -45,10 +63,10 @@
|
||||
<td>For internationalization (language support)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="i18n-ext.js">i18n-ext.js</a></td>
|
||||
<td><a href="image.js">image.js</a></td>
|
||||
<td><a href="http://creativecommons.org/publicdomain/zero/1.0/legalcode">CC0-1.0</a></td>
|
||||
<td><a href="i18n-ext.js">i18n-ext.js</a></td>
|
||||
<td>I18n "extensions"</td>
|
||||
<td><a href="image.js">image.js</a></td>
|
||||
<td>For canvas image manipulation</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="accessibility.js">accessibility.js</a></td>
|
||||
@ -62,18 +80,6 @@
|
||||
<td><a href="main.js">main.js</a></td>
|
||||
<td>The main script for Cat-Printer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="polyfill.js">polyfill.js</a></td>
|
||||
<td><a href="http://creativecommons.org/publicdomain/zero/1.0/legalcode">CC0-1.0</a></td>
|
||||
<td><a href="polyfill.js">polyfill.js</a></td>
|
||||
<td>Put features that are not supported by old browsers.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="main.comp.js">main.comp.js</a></td>
|
||||
<td><a href="https://www.gnu.org/licenses/gpl-3.0.html">GPL-3.0</a></td>
|
||||
<td><a href="main.js">main.js</a></td>
|
||||
<td>A bundle of transpiled scripts (polyfill.js, image.js, i18n.js, main.js), for compatibility to old browsers.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
|
@ -119,5 +119,5 @@
|
||||
"reset-configuration-": "Reset configuration?",
|
||||
"brightness-": "Brightness:",
|
||||
"text-printing-mode": "Text Printing Mode",
|
||||
"please-enable-bluetooth-or-try-to-reboot": "Please enable bluetooth or try to reboot"
|
||||
"internal-error-please-see-terminal": "Internal error, please see terminal"
|
||||
}
|
@ -114,5 +114,5 @@
|
||||
"reset-configuration-": "要重置配置吗?",
|
||||
"brightness-": "亮度:",
|
||||
"text-printing-mode": "文字打印模式",
|
||||
"please-enable-bluetooth-or-try-to-reboot": "请启用蓝牙或尝试重启"
|
||||
"internal-error-please-see-terminal": "内部错误,请检查终端"
|
||||
}
|
@ -4,12 +4,11 @@
|
||||
*/
|
||||
(function() {
|
||||
|
||||
var fallbacks = [
|
||||
// main scripts, which we will directly modify
|
||||
'i18n-ext.js', 'i18n.js', 'image.js', 'accessibility.js', 'main.js',
|
||||
// "compatibility" script, produced with eg. typescript tsc
|
||||
'main.comp.js'
|
||||
];
|
||||
var fallbacks;
|
||||
if (location.href.indexOf('?debug') !== -1)
|
||||
fallbacks = ['i18n-ext.js', 'i18n.js', 'image.js', 'accessibility.js', 'main.js'];
|
||||
else
|
||||
fallbacks = ['~every.js', 'main.comp.js'];
|
||||
var trial_count = 0;
|
||||
/**
|
||||
* Try to load next "fallback" script,
|
||||
@ -21,6 +20,7 @@
|
||||
var script = document.createElement('script');
|
||||
script.addEventListener('load', function() {
|
||||
if (typeof main === 'undefined') {
|
||||
// the script can't be 'unrun', though
|
||||
script.remove();
|
||||
try_load();
|
||||
} else {
|
||||
|
@ -82,7 +82,7 @@ input[type="number"], input[type="text"] {
|
||||
}
|
||||
button:hover {
|
||||
margin: 0;
|
||||
padding: var(--span) calc(var(--span-double));
|
||||
padding: var(--span) var(--span-double);
|
||||
min-width: calc(6em + var(--span-double));
|
||||
}
|
||||
button:active {
|
||||
|
83
www/main.js
83
www/main.js
@ -418,7 +418,7 @@ function applyI18nToDom(doc) {
|
||||
element.firstChild.textContent = translated_string;
|
||||
});
|
||||
}
|
||||
async function initI18n() {
|
||||
async function initI18n(current_language) {
|
||||
if (typeof i18n === 'undefined') return;
|
||||
/** @type {HTMLSelectElement} */
|
||||
let language_options = document.getElementById('select-language');
|
||||
@ -429,9 +429,6 @@ async function initI18n() {
|
||||
i18n.add(value, await fetch(`/lang/${value}.json`).then(r => r.json()), true);
|
||||
applyI18nToDom();
|
||||
}
|
||||
language_options.addEventListener('change', () => {
|
||||
language_options.selectedOptions.item(0).click();
|
||||
});
|
||||
for (let code in list) {
|
||||
let option = document.createElement('option');
|
||||
option.value = code;
|
||||
@ -440,35 +437,28 @@ async function initI18n() {
|
||||
/** @type {HTMLOptionElement} */
|
||||
let option = event.currentTarget;
|
||||
let value = option.value;
|
||||
// option.selected = true;
|
||||
option.selected = true;
|
||||
language_options.selectedIndex = option.index;
|
||||
use_language(value);
|
||||
Notice.note('welcome');
|
||||
});
|
||||
language_options.appendChild(option);
|
||||
}
|
||||
apply_default:
|
||||
for (let code of navigator.languages) {
|
||||
if (list[code]) {
|
||||
for (let option of language_options.children) {
|
||||
if (option.value === code) {
|
||||
// option.setAttribute('data-default', '');
|
||||
option.setAttribute('data-default', '');
|
||||
option.click();
|
||||
i18n.useLanguage(navigator.languages[0]);
|
||||
for (let language of navigator.languages) {
|
||||
if (!list[language]) return;
|
||||
let data = await fetch(`/lang/${language}.json`)
|
||||
.then(response => response.ok ? response.json() : null);
|
||||
if (data !== null) {
|
||||
i18n.add(language, data);
|
||||
}
|
||||
}
|
||||
break apply_default;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!navigator.languages) {
|
||||
if (!navigator.language) return;
|
||||
else navigator.languages = [navigator.language, 'en-US'];
|
||||
}
|
||||
if (current_language) {
|
||||
for (let option of language_options.children)
|
||||
if (option.value === current_language)
|
||||
option.click();
|
||||
} else for (let code of navigator.languages)
|
||||
if (list[code]) for (let option of language_options.children)
|
||||
if (option.value === code) {
|
||||
option.setAttribute('data-default', '');
|
||||
if (!current_language) option.click();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async function testI18n(lang) {
|
||||
@ -500,14 +490,18 @@ class Main {
|
||||
this.setters = {};
|
||||
// window.addEventListener('unload', () => this.exit());
|
||||
this.promise = new Promise(async (resolve, reject) => {
|
||||
await initI18n();
|
||||
/** @type {HTMLIFrameElement} */
|
||||
let iframe = document.getElementById('frame');
|
||||
iframe.addEventListener('load', () => {
|
||||
if (!iframe.contentWindow.NodeList.prototype.forEach)
|
||||
iframe.contentWindow.NodeList.prototype.forEach = NodeList.prototype.forEach;
|
||||
iframe.contentDocument.body.classList.value = document.body.classList.value;
|
||||
iframe.contentDocument.body.addEventListener('keyup', (event) => {
|
||||
if (event.key === 'Escape')
|
||||
document.body.dispatchEvent(new KeyboardEvent('keyup', { key: 'Escape' }));
|
||||
if (event.key === 'Escape' || event.keyCode === 27) {
|
||||
document.body.dispatchEvent(
|
||||
new KeyboardEvent('keyup', { key: 'Escape', keyCode: 27 })
|
||||
);
|
||||
}
|
||||
});
|
||||
applyI18nToDom(iframe.contentDocument);
|
||||
});
|
||||
@ -517,6 +511,10 @@ class Main {
|
||||
d.body.classList.remove(class_name)
|
||||
);
|
||||
}
|
||||
|
||||
await this.loadConfig();
|
||||
await initI18n(this.settings['language']);
|
||||
|
||||
this.canvasController = new CanvasController();
|
||||
putEvent('#button-exit', 'click', () => this.exit(false), this);
|
||||
putEvent('#button-exit', 'contextmenu',
|
||||
@ -531,7 +529,6 @@ class Main {
|
||||
(value) => this.settings['text_mode'] = (value === 'algo-direct')
|
||||
);
|
||||
this.attachSetter('#transparent-as-white', 'change', 'transparent_as_white');
|
||||
this.attachSetter('#select-language option', 'click', 'language');
|
||||
this.attachSetter('#dry-run', 'change', 'dry_run',
|
||||
(checked) => checked && Notice.note('dry-run-test-print-process-only')
|
||||
);
|
||||
@ -556,7 +553,10 @@ class Main {
|
||||
this.attachSetter('#flip-h', 'change', 'flip_h');
|
||||
this.attachSetter('#flip-v', 'change', 'flip_v');
|
||||
this.attachSetter('#dump', 'change', 'dump');
|
||||
await this.loadConfig();
|
||||
await this.activateConfig();
|
||||
// one exception
|
||||
this.attachSetter('#select-language option', 'click', 'language');
|
||||
|
||||
if (this.settings['is_android']) {
|
||||
// Android doesn't work well with select[multiple]
|
||||
let div = document.createElement('div');
|
||||
@ -583,13 +583,19 @@ class Main {
|
||||
else return null;
|
||||
}
|
||||
/**
|
||||
* Load saved config from server, and activate all setters with corresponding values in settings.
|
||||
* Please do `attachSetter` on all desired elements/inputs before calling.
|
||||
* After the load, will save config to server again in order to sync default values.
|
||||
* Then, if permitted, every single change will sync to server instantly
|
||||
* Load saved config from server
|
||||
*/
|
||||
async loadConfig() {
|
||||
this.settings = await callApi('/query');
|
||||
}
|
||||
/**
|
||||
* Activate all setters with corresponding values in settings.
|
||||
* Before calling, please first loadConfig & do `attachSetter` on all desired elements/inputs.
|
||||
* After the load, will save config to server again in order to sync default values.
|
||||
* Then, if permitted, every single change will sync to server instantly
|
||||
*/
|
||||
async activateConfig() {
|
||||
this.allowSet = false;
|
||||
if (this.settings['first_run'])
|
||||
Dialog.alert('#accessibility', () => this.set({ first_run: false }));
|
||||
for (let key in this.settings) {
|
||||
@ -627,7 +633,7 @@ class Main {
|
||||
* @param {(value: any) => any} callback Optional additinal post-procedure to call, with a *reasonable* value as parameter
|
||||
*/
|
||||
attachSetter(selector, type, attribute, callback) {
|
||||
this.setters[attribute] = putEvent(selector, type, (event => {
|
||||
this.setters[attribute] = putEvent(selector, type, event => {
|
||||
event.stopPropagation();
|
||||
event.cancelBubble = true;
|
||||
let input = event.currentTarget;
|
||||
@ -647,7 +653,7 @@ class Main {
|
||||
this.settings[attribute] = value;
|
||||
this.set({ [attribute]: value });
|
||||
return callback ? callback(value) : undefined;
|
||||
}).bind(this), this);
|
||||
}, this);
|
||||
}
|
||||
async exit(reset) {
|
||||
Notice.wait('exiting');
|
||||
@ -674,6 +680,9 @@ class Main {
|
||||
error_details.details.includes('not turned on') ||
|
||||
error_details.details.includes('WinError -2147020577')
|
||||
) Notice.warn('please-enable-bluetooth');
|
||||
else if (
|
||||
error_details.details.includes('no running event loop')
|
||||
) Notice.error('internal-error-please-see-terminal');
|
||||
else throw new Error('Unknown Bluetooth Problem');
|
||||
return null;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user