mirror of
https://github.com/NaitLee/Cat-Printer.git
synced 2025-05-18 00:00:18 -07:00
Accessibility: keyboard mode by Tab
This commit is contained in:
parent
bf81524083
commit
ab9ad406cb
@ -16,73 +16,73 @@
|
|||||||
<div class="menu">
|
<div class="menu">
|
||||||
<div class="panel" id="panel-print" data-default>
|
<div class="panel" id="panel-print" data-default>
|
||||||
<label for="device-options" data-i18n="device-">Device:</label>
|
<label for="device-options" data-i18n="device-">Device:</label>
|
||||||
<select id="device-options">
|
<select id="device-options" data-key>
|
||||||
</select>
|
</select>
|
||||||
<button id="device-refresh" data-i18n="refresh">Refresh</button>
|
<button id="device-refresh" data-i18n="refresh" data-key>Refresh</button>
|
||||||
<hr />
|
<hr />
|
||||||
<label data-i18n="mode-">Mode:</label>
|
<label data-i18n="mode-">Mode:</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="mode" value="mode-canvas" checked />
|
<input type="radio" name="mode" value="mode-canvas" data-key checked />
|
||||||
<span data-i18n="canvas">Canvas</span>
|
<span data-i18n="canvas">Canvas</span>
|
||||||
</label>
|
</label>
|
||||||
<!-- <label>
|
<!-- <label>
|
||||||
<input type="radio" name="mode" value="mode-document" />
|
<input type="radio" name="mode" value="mode-document" data-key />
|
||||||
<span data-i18n="document">Document</span>
|
<span data-i18n="document">Document</span>
|
||||||
</label><br /> -->
|
</label><br /> -->
|
||||||
<button id="insert-picture" data-i18n="insert-picture">Insert Picture</button>
|
<button id="insert-picture" data-i18n="insert-picture" data-key="Enter">Insert Picture</button>
|
||||||
<br />
|
<br />
|
||||||
<label data-i18n="process-as-">Process as:</label>
|
<label data-i18n="process-as-">Process as:</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="algo" value="algo-direct" />
|
<input type="radio" name="algo" value="algo-direct" data-key />
|
||||||
<span data-i18n="text">Text</span>
|
<span data-i18n="text">Text</span>
|
||||||
</label>
|
</label>
|
||||||
<label>
|
<label>
|
||||||
<input type="radio" name="algo" value="algo-steinberg" checked />
|
<input type="radio" name="algo" value="algo-steinberg" data-key checked />
|
||||||
<span data-i18n="picture">Picture</span>
|
<span data-i18n="picture">Picture</span>
|
||||||
</label>
|
</label>
|
||||||
<!-- <label>
|
<!-- <label>
|
||||||
<input type="radio" name="algo" value="algo-halftone" />
|
<input type="radio" name="algo" value="algo-halftone" data-key />
|
||||||
<span data-i18n="pattern">Pattern</span>
|
<span data-i18n="pattern">Pattern</span>
|
||||||
</label> --><br />
|
</label> --><br />
|
||||||
<label for="threshold" data-i18n="threshold-">Threshold:</label>
|
<label for="threshold" data-i18n="threshold-">Threshold:</label>
|
||||||
<input type="range" min="0" max="256" value="128" step="8" id="threshold" data-default />
|
<input type="range" min="0" max="256" value="128" step="8" id="threshold" data-key data-default />
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="transparent-as-white" id="transparent-as-white" checked />
|
<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>
|
<label for="transparent-as-white" data-i18n="transparent-as-white">Transparent as White</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel active" id="panel-help">
|
<div class="panel active" id="panel-help">
|
||||||
<div>
|
<div>
|
||||||
<p data-i18n="coming-soon">Coming Soon...</p>
|
<p data-i18n="coming-soon">Coming Soon...</p>
|
||||||
<p>
|
<p>
|
||||||
<a href="about.html" target="frame" data-i18n="about">About</a>
|
<a href="about.html" target="frame" data-i18n="about" data-key>About</a>
|
||||||
<!-- LibreJS doesn't work with dynamically inserted script tag. Going to complain -->
|
<!-- LibreJS doesn't work with dynamically inserted script tag. Going to complain -->
|
||||||
<a href="jslicense.html" data-jslicense="1" target="frame"
|
<a href="jslicense.html" data-jslicense="1" target="frame"
|
||||||
data-i18n="javascript-license-information">JavaScript License Information</a>
|
data-i18n="javascript-license-information" data-key>JavaScript License Information</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel" id="panel-settings">
|
<div class="panel" id="panel-settings">
|
||||||
<label for="scan-time" data-i18n="scan-time-">Scan Time:</label>
|
<label for="scan-time" data-i18n="scan-time-">Scan Time:</label>
|
||||||
<input type="number" name="scan-time" id="scan-time" min="1" max="10" value="3" />
|
<input type="number" name="scan-time" id="scan-time" min="1" max="10" value="3" data-key />
|
||||||
<span data-i18n="-seconds">seconds</span>
|
<span data-i18n="-seconds">seconds</span>
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="flip-h" id="flip-h" />
|
<input type="checkbox" name="flip-h" id="flip-h" data-key />
|
||||||
<label for="flip-h" data-i18n="flip-horizontally">Flip Horizontally</label>
|
<label for="flip-h" data-i18n="flip-horizontally">Flip Horizontally</label>
|
||||||
<input type="checkbox" name="flip-v" id="flip-v" />
|
<input type="checkbox" name="flip-v" id="flip-v" data-key />
|
||||||
<label for="flip-v" data-i18n="flip-vertically">Flip Vertically</label>
|
<label for="flip-v" data-i18n="flip-vertically">Flip Vertically</label>
|
||||||
<hr />
|
<hr />
|
||||||
<input type="checkbox" name="dry-run" id="dry-run" />
|
<input type="checkbox" name="dry-run" id="dry-run" data-key />
|
||||||
<label for="dry-run" data-i18n="dry-run">Dry Run</label>
|
<label for="dry-run" data-i18n="dry-run">Dry Run</label>
|
||||||
<input type="checkbox" name="dump" id="dump" />
|
<input type="checkbox" name="dump" id="dump" data-key />
|
||||||
<label for="dump" data-i18n="dump-traffic">Dump Traffic</label>
|
<label for="dump" data-i18n="dump-traffic">Dump Traffic</label>
|
||||||
<br />
|
<br />
|
||||||
<button id="set-accessibility">
|
<button id="set-accessibility" data-key>
|
||||||
<span>🌎</span>
|
<span>🌎</span>
|
||||||
<span data-i18n="accessibility">Accessibility</span>
|
<span data-i18n="accessibility">Accessibility</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="hidden" data-panel="panel-error" data-i18n="error-message">Error Message</button>
|
<button class="hidden" data-panel="panel-error" data-i18n="error-message" data-key>Error Message</button>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<button id="button-exit" data-i18n="exit">Exit</button>
|
<button id="button-exit" data-i18n="exit" data-key>Exit</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel" id="panel-error">
|
<div class="panel" id="panel-error">
|
||||||
@ -91,9 +91,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="compact-menu">
|
<div class="compact-menu">
|
||||||
<div class="compact-button" data-panel="panel-print" data-i18n="print">Print</div>
|
<button class="compact-button" data-panel="panel-print" data-i18n="print" data-key="8">Print</button>
|
||||||
<div class="compact-button active" data-panel="panel-help" data-i18n="help">Help</div>
|
<button class="compact-button active" data-panel="panel-help" data-i18n="help" data-key="9">Help</button>
|
||||||
<div class="compact-button" data-panel="panel-settings" data-i18n="settings">Settings</div>
|
<button class="compact-button" data-panel="panel-settings" data-i18n="settings" data-key="0">Settings</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
<!-- -->
|
<!-- -->
|
||||||
@ -107,7 +107,7 @@
|
|||||||
<!-- <button id="canvas-expand" data-i18n="expand">Expand</button>
|
<!-- <button id="canvas-expand" data-i18n="expand">Expand</button>
|
||||||
<button id="canvas-crop" data-i18n="crop">Crop</button> -->
|
<button id="canvas-crop" data-i18n="crop">Crop</button> -->
|
||||||
<!-- <button id="button-preview" data-i18n="preview">Preview</button> -->
|
<!-- <button id="button-preview" data-i18n="preview">Preview</button> -->
|
||||||
<button id="button-print" data-i18n="print">Print</button>
|
<button id="button-print" data-i18n="print" data-key=" ">Print</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="blank"></div>
|
<div class="blank"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -117,29 +117,33 @@
|
|||||||
<input type="file" id="file" />
|
<input type="file" id="file" />
|
||||||
<div id="accessibility">
|
<div id="accessibility">
|
||||||
<div>
|
<div>
|
||||||
<h2 data-i18n="language">Language</h2>
|
<h2>
|
||||||
<div id="select-language">
|
<span>🌎</span>
|
||||||
</div>
|
<span data-i18n="language">Language</span>
|
||||||
|
</h2>
|
||||||
|
<select multiple id="select-language" data-key="5">
|
||||||
|
</select>
|
||||||
|
<p data-i18n="press-tab-to-control-with-keyboard">Press Tab to control with keyboard</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2 data-i18n="layout">Layout</h2>
|
<h2 data-i18n="layout">Layout</h2>
|
||||||
<input type="checkbox" name="dark-theme" id="dark-theme" />
|
<input type="checkbox" name="dark-theme" id="dark-theme" data-key />
|
||||||
<label for="dark-theme" data-i18n="dark-theme">Dark Theme</label>
|
<label for="dark-theme" data-i18n="dark-theme">Dark Theme</label>
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="high-contrast" id="high-contrast" />
|
<input type="checkbox" name="high-contrast" id="high-contrast" data-key />
|
||||||
<label for="high-contrast" data-i18n="high-contrast">High Contrast</label>
|
<label for="high-contrast" data-i18n="high-contrast">High Contrast</label>
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="no-animation" id="no-animation" />
|
<input type="checkbox" name="no-animation" id="no-animation" data-key />
|
||||||
<label for="no-animation" data-i18n="disable-animation">Disable Animation</label>
|
<label for="no-animation" data-i18n="disable-animation">Disable Animation</label>
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="force-rtl" id="force-rtl" />
|
<input type="checkbox" name="force-rtl" id="force-rtl" data-key />
|
||||||
<label for="force-rtl" data-i18n="right-to-left-text-order">Right-to-left text order</label>
|
<label for="force-rtl" data-i18n="right-to-left-text-order">Right-to-left text order</label>
|
||||||
<br />
|
<br />
|
||||||
<input type="checkbox" name="large-font" id="large-font" />
|
<input type="checkbox" name="large-font" id="large-font" data-key />
|
||||||
<label for="large-font" data-i18n="large-font">Large Font</label>
|
<label for="large-font" data-i18n="large-font">Large Font</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<iframe id="frame" src="about:blank" name="frame" title="frame"></iframe>
|
<iframe id="frame" src="about:blank" name="frame" title="frame" data-key="6"></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div id="dialog" class="hidden">
|
<div id="dialog" class="hidden">
|
||||||
<div class="shade"></div>
|
<div class="shade"></div>
|
||||||
@ -148,7 +152,7 @@
|
|||||||
<!-- Dialog content -->
|
<!-- Dialog content -->
|
||||||
</div>
|
</div>
|
||||||
<div id="dialog-choices">
|
<div id="dialog-choices">
|
||||||
<input id="dialog-input" type="text" id="dialog-input" placeholder="">
|
<input id="dialog-input" type="text" id="dialog-input" placeholder="" data-key="4">
|
||||||
<hr />
|
<hr />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -164,10 +168,11 @@
|
|||||||
<p class="noscript">
|
<p class="noscript">
|
||||||
<span>Please enable JavaScript!</span><br />
|
<span>Please enable JavaScript!</span><br />
|
||||||
<a href="jslicense.html" data-i18n="javascript-license-information"
|
<a href="jslicense.html" data-i18n="javascript-license-information"
|
||||||
data-jslicense="1" >JavaScript License Information</a>
|
data-jslicense="1" tabindex="1" >JavaScript License Information</a>
|
||||||
</p>
|
</p>
|
||||||
</noscript>
|
</noscript>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="keyboard-shortcuts-layer"></div>
|
||||||
<script src="loader.js"></script>
|
<script src="loader.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -101,5 +101,10 @@
|
|||||||
"high-contrast": "High Contrast",
|
"high-contrast": "High Contrast",
|
||||||
"welcome": "Welcome!",
|
"welcome": "Welcome!",
|
||||||
"copyright-and-license": "Copyright and License",
|
"copyright-and-license": "Copyright and License",
|
||||||
"some-rights-reserved": "Some rights reserved."
|
"some-rights-reserved": "Some rights reserved.",
|
||||||
|
"ENTER": "Enter",
|
||||||
|
"SPACE": "Space",
|
||||||
|
"ESCAPE": "Esc",
|
||||||
|
"TAB": "Tab",
|
||||||
|
"press-tab-to-control-with-keyboard": "Press Tab to control with keyboard"
|
||||||
}
|
}
|
@ -96,5 +96,10 @@
|
|||||||
"high-contrast": "高对比度",
|
"high-contrast": "高对比度",
|
||||||
"welcome": "欢迎!",
|
"welcome": "欢迎!",
|
||||||
"copyright-and-license": "版权与许可",
|
"copyright-and-license": "版权与许可",
|
||||||
"some-rights-reserved": "保留一些权利。"
|
"some-rights-reserved": "保留一些权利。",
|
||||||
|
"ENTER": "回车",
|
||||||
|
"SPACE": "空格",
|
||||||
|
"ESCAPE": "ESC",
|
||||||
|
"TAB": "Tab",
|
||||||
|
"press-tab-to-control-with-keyboard": "按下 Tab 以使用键盘操作"
|
||||||
}
|
}
|
44
www/main.css
44
www/main.css
@ -20,6 +20,7 @@
|
|||||||
--notice-note: rgba(0, 255, 0, 0.2);
|
--notice-note: rgba(0, 255, 0, 0.2);
|
||||||
--notice-warn: rgba(255, 128, 0, 0.2);
|
--notice-warn: rgba(255, 128, 0, 0.2);
|
||||||
--notice-error: rgba(255, 0, 0, 0.2);
|
--notice-error: rgba(255, 0, 0, 0.2);
|
||||||
|
--shade: rgba(238, 238, 238, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@ -141,7 +142,7 @@ main>.menu-side {
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
/* overflow: auto; */
|
||||||
margin: var(--span);
|
margin: var(--span);
|
||||||
min-width: 12em;
|
min-width: 12em;
|
||||||
}
|
}
|
||||||
@ -163,8 +164,15 @@ main>.menu-side>.menu {
|
|||||||
line-height: 2em;
|
line-height: 2em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
border-top: var(--border) solid var(--fore-color);
|
border-top: var(--border) solid var(--fore-color);
|
||||||
border-bottom: var(--border) solid transparent;
|
border-bottom: var(--border) solid transparent;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.compact-button:hover {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
}
|
}
|
||||||
.compact-button.active {
|
.compact-button.active {
|
||||||
border: var(--border) solid var(--fore-color);
|
border: var(--border) solid var(--fore-color);
|
||||||
@ -339,7 +347,7 @@ hr {
|
|||||||
#accessibility>*:nth-child(1) {
|
#accessibility>*:nth-child(1) {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
#select-language {
|
#select-language[multiple] {
|
||||||
width: calc(100% - var(--span-double));
|
width: calc(100% - var(--span-double));
|
||||||
height: 8em;
|
height: 8em;
|
||||||
border: var(--border) solid var(--fore-color);
|
border: var(--border) solid var(--fore-color);
|
||||||
@ -408,6 +416,33 @@ hr {
|
|||||||
#loading-screen>.dots>span:nth-child(2) { animation-delay: 0.3s; }
|
#loading-screen>.dots>span:nth-child(2) { animation-delay: 0.3s; }
|
||||||
#loading-screen>.dots>span:nth-child(3) { animation-delay: 0.6s; }
|
#loading-screen>.dots>span:nth-child(3) { animation-delay: 0.6s; }
|
||||||
|
|
||||||
|
#keyboard-shortcuts-layer {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
overflow: visible;
|
||||||
|
pointer-events: all;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
#keyboard-shortcuts-layer span {
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
/* border: var(--border) dotted var(--fore-color); */
|
||||||
|
background-color: var(--shade);
|
||||||
|
padding: var(--span-half) var(--span);
|
||||||
|
white-space: pre;
|
||||||
|
line-height: 1em;
|
||||||
|
font-family: 'DejaVu Sans Mono', 'Consolas', monospace;
|
||||||
|
transform: translateY(calc(var(--font-size) * -1));
|
||||||
|
}
|
||||||
|
body.force-rtl #keyboard-shortcuts-layer span {
|
||||||
|
transform: translate(
|
||||||
|
calc(var(--font-size) * 2),
|
||||||
|
calc(var(--font-size) * -1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
transition: all var(--anim-time) ease-out;
|
transition: all var(--anim-time) ease-out;
|
||||||
}
|
}
|
||||||
@ -485,7 +520,7 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root { --fore-color: #eee; --back-color: #333; }
|
:root { --fore-color: #eee; --back-color: #333; --shade: rgba(51, 51, 51, 0.5); }
|
||||||
body, .shade { transition: background-color calc(var(--anim-time) * 2) ease-in; }
|
body, .shade { transition: background-color calc(var(--anim-time) * 2) ease-in; }
|
||||||
a:link, a:visited { color: #66f; }
|
a:link, a:visited { color: #66f; }
|
||||||
a:hover, a:active { color: #77f; }
|
a:hover, a:active { color: #77f; }
|
||||||
@ -493,7 +528,7 @@ a {
|
|||||||
#control-document, .logo { filter: brightness(0.6); }
|
#control-document, .logo { filter: brightness(0.6); }
|
||||||
}
|
}
|
||||||
/* so silly... */
|
/* so silly... */
|
||||||
body.dark { --fore-color: #eee; --back-color: #333; }
|
body.dark { --fore-color: #eee; --back-color: #333; --shade: rgba(51, 51, 51, 0.5); }
|
||||||
body.dark, .shade { transition: background-color calc(var(--anim-time) * 2) ease-in; }
|
body.dark, .shade { transition: background-color calc(var(--anim-time) * 2) ease-in; }
|
||||||
body.dark a:link, body.dark a:visited { color: #66f; }
|
body.dark a:link, body.dark a:visited { color: #66f; }
|
||||||
body.dark a:hover, body.dark a:active { color: #77f; }
|
body.dark a:hover, body.dark a:active { color: #77f; }
|
||||||
@ -541,6 +576,7 @@ body.high-contrast {
|
|||||||
--notice-note: transparent;
|
--notice-note: transparent;
|
||||||
--notice-warn: transparent;
|
--notice-warn: transparent;
|
||||||
--notice-error: transparent;
|
--notice-error: transparent;
|
||||||
|
--shade: rgba(0, 0, 0, 0.8);
|
||||||
transition-duration: 0s;
|
transition-duration: 0s;
|
||||||
}
|
}
|
||||||
body.high-contrast .shade { transition-duration: 0s; opacity: 1; }
|
body.high-contrast .shade { transition-duration: 0s; opacity: 1; }
|
||||||
|
104
www/main.js
104
www/main.js
@ -83,9 +83,11 @@ const Dialog = (function() {
|
|||||||
last_choices = [];
|
last_choices = [];
|
||||||
dialog_input.value = '';
|
dialog_input.value = '';
|
||||||
dialog_input.style.display = have_input ? 'unset' : 'none';
|
dialog_input.style.display = have_input ? 'unset' : 'none';
|
||||||
|
let index = 1;
|
||||||
for (let choice of choices) {
|
for (let choice of choices) {
|
||||||
let button = document.createElement('button');
|
let button = document.createElement('button');
|
||||||
button.setAttribute('data-i18n', choice);
|
button.setAttribute('data-i18n', choice);
|
||||||
|
button.setAttribute('data-key', index++);
|
||||||
button.innerText = i18n(choice);
|
button.innerText = i18n(choice);
|
||||||
if (!have_input)
|
if (!have_input)
|
||||||
button.addEventListener('click', () => dialog_input.value = choice);
|
button.addEventListener('click', () => dialog_input.value = choice);
|
||||||
@ -403,7 +405,7 @@ function applyI18nToDom(doc) {
|
|||||||
}
|
}
|
||||||
async function initI18n() {
|
async function initI18n() {
|
||||||
if (typeof i18n === 'undefined') return;
|
if (typeof i18n === 'undefined') return;
|
||||||
/** @type {HTMLOptionElement} */
|
/** @type {HTMLSelectElement} */
|
||||||
let language_options = document.getElementById('select-language');
|
let language_options = document.getElementById('select-language');
|
||||||
/** @type {{ [code: string]: string }} */
|
/** @type {{ [code: string]: string }} */
|
||||||
let list = await fetch('/lang/list.json').then(r => r.json());
|
let list = await fetch('/lang/list.json').then(r => r.json());
|
||||||
@ -412,14 +414,20 @@ async function initI18n() {
|
|||||||
i18n.add(value, await fetch(`/lang/${value}.json`).then(r => r.json()), true);
|
i18n.add(value, await fetch(`/lang/${value}.json`).then(r => r.json()), true);
|
||||||
applyI18nToDom();
|
applyI18nToDom();
|
||||||
}
|
}
|
||||||
|
language_options.addEventListener('change', () => {
|
||||||
|
language_options.selectedOptions.item(0).click();
|
||||||
|
});
|
||||||
for (let code in list) {
|
for (let code in list) {
|
||||||
let option = document.createElement('option');
|
let option = document.createElement('option');
|
||||||
option.value = code;
|
option.value = code;
|
||||||
option.innerText = list[code];
|
option.innerText = list[code];
|
||||||
option.addEventListener('click', (event) => {
|
option.addEventListener('click', (event) => {
|
||||||
|
/** @type {HTMLOptionElement} */
|
||||||
let option = event.currentTarget;
|
let option = event.currentTarget;
|
||||||
let value = option.value;
|
let value = option.value;
|
||||||
|
language_options.selectedIndex = option.index;
|
||||||
use_language(value);
|
use_language(value);
|
||||||
|
Notice.note('welcome');
|
||||||
});
|
});
|
||||||
language_options.appendChild(option);
|
language_options.appendChild(option);
|
||||||
}
|
}
|
||||||
@ -455,6 +463,97 @@ async function testI18n(lang) {
|
|||||||
, true);
|
, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isHidden(element) {
|
||||||
|
let parents = [element];
|
||||||
|
while (parents[0].parentElement)
|
||||||
|
parents.unshift(parents[0].parentElement);
|
||||||
|
return parents.some(e => {
|
||||||
|
let rect = e.getBoundingClientRect();
|
||||||
|
return (
|
||||||
|
e.classList.contains('hidden') ||
|
||||||
|
e.classList.contains('hard-hidden') ||
|
||||||
|
e.style.display == 'none' ||
|
||||||
|
rect.width == 0 || rect.height == 0 ||
|
||||||
|
rect.x < 0 || rect.y < 0 ||
|
||||||
|
e.style.visibility == 'none' ||
|
||||||
|
e.style.opacity == '0'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initKeyboardShortcuts() {
|
||||||
|
const layer = document.getElementById('keyboard-shortcuts-layer');
|
||||||
|
const dialog = document.getElementById('dialog');
|
||||||
|
let key, keys = 'qwertyuiopasdfghjklzxcvbnm';
|
||||||
|
let focused, onbreak = false, started = false;
|
||||||
|
let inputs, shortcuts = {};
|
||||||
|
const mark_keys = () => {
|
||||||
|
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 key_index = 0;
|
||||||
|
shortcuts = {};
|
||||||
|
for (let input of inputs) {
|
||||||
|
if (isHidden(input)) continue;
|
||||||
|
let key = input.getAttribute('data-key') || keys[key_index++];
|
||||||
|
shortcuts[key] = input;
|
||||||
|
}
|
||||||
|
Array.from(layer.children).forEach(e => e.remove());
|
||||||
|
for (let key in shortcuts) {
|
||||||
|
if (onbreak) {
|
||||||
|
let rect = focused.getBoundingClientRect();
|
||||||
|
let span = document.createElement('span');
|
||||||
|
span.innerText = i18n('ESCAPE');
|
||||||
|
span.style.top = rect.y + 'px';
|
||||||
|
span.style.left = rect.x + 'px';
|
||||||
|
layer.appendChild(span);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
let input = shortcuts[key];
|
||||||
|
let position = input.getBoundingClientRect();
|
||||||
|
let span = document.createElement('span');
|
||||||
|
span.innerText = i18n(key.toUpperCase().replace(' ', 'SPACE'));
|
||||||
|
span.style.top = position.y + 'px';
|
||||||
|
span.style.right = (window.innerWidth - position.x) + 'px';
|
||||||
|
layer.appendChild(span);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const start = () => setInterval(mark_keys, 1000);
|
||||||
|
document.body.addEventListener('keyup', (event) => {
|
||||||
|
document.body.addEventListener('keyup', () => requestAnimationFrame(mark_keys), { once: true });
|
||||||
|
key = event.key;
|
||||||
|
if (key === 'Tab') {
|
||||||
|
if (!started) { start(); started = true; }
|
||||||
|
mark_keys();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let input = shortcuts[key];
|
||||||
|
if (input) {
|
||||||
|
switch (input.type || input.tagName) {
|
||||||
|
case 'range':
|
||||||
|
case 'text':
|
||||||
|
case 'number':
|
||||||
|
case 'tel':
|
||||||
|
case 'date':
|
||||||
|
case 'select-one':
|
||||||
|
case 'select-multiple':
|
||||||
|
case 'DIV':
|
||||||
|
case 'TEXTAREA':
|
||||||
|
input.focus();
|
||||||
|
onbreak = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
focused = input;
|
||||||
|
} else if (key === 'Escape' && focused) {
|
||||||
|
focused.blur();
|
||||||
|
onbreak = !onbreak;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class Main {
|
class Main {
|
||||||
promise;
|
promise;
|
||||||
/** @type {CanvasController} */
|
/** @type {CanvasController} */
|
||||||
@ -525,6 +624,9 @@ class Main {
|
|||||||
this.attachSetter('#flip-v', 'change', 'flip_v');
|
this.attachSetter('#flip-v', 'change', 'flip_v');
|
||||||
this.attachSetter('#dump', 'change', 'dump');
|
this.attachSetter('#dump', 'change', 'dump');
|
||||||
await this.loadConfig();
|
await this.loadConfig();
|
||||||
|
if (this.settings['is_android'])
|
||||||
|
document.getElementById('select-language').multiple = false;
|
||||||
|
initKeyboardShortcuts();
|
||||||
this.searchDevices();
|
this.searchDevices();
|
||||||
document.querySelector('main').classList.remove('hard-hidden');
|
document.querySelector('main').classList.remove('hard-hidden');
|
||||||
document.getElementById('loading-screen').classList.add('hidden');
|
document.getElementById('loading-screen').classList.add('hidden');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user