mirror of
https://github.com/ankitects/anki.git
synced 2025-12-10 21:36:55 -05:00
Refactor {CommandIcon,Icon,Square}Button into IconButton and WithState
This commit is contained in:
parent
2f5074bff6
commit
0baf14dc8b
11 changed files with 221 additions and 226 deletions
|
|
@ -41,7 +41,7 @@ ts_library(
|
||||||
"@npm//@types/bootstrap",
|
"@npm//@types/bootstrap",
|
||||||
"@npm//bootstrap",
|
"@npm//bootstrap",
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
],
|
] + svelte_names,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
|
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
<!--
|
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
-->
|
|
||||||
<script lang="typescript" context="module">
|
|
||||||
import { writable } from "svelte/store";
|
|
||||||
|
|
||||||
type UpdateMap = Map<string, (event: Event) => boolean>;
|
|
||||||
type ActiveMap = Map<string, boolean>;
|
|
||||||
|
|
||||||
const updateMap = new Map() as UpdateMap;
|
|
||||||
const activeMap = new Map() as ActiveMap;
|
|
||||||
const activeStore = writable(activeMap);
|
|
||||||
|
|
||||||
function updateButton(key: string, event: MouseEvent): void {
|
|
||||||
activeStore.update(
|
|
||||||
(map: ActiveMap): ActiveMap =>
|
|
||||||
new Map([...map, [key, updateMap.get(key)(event)]])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateButtons(callback: (key: string) => boolean): void {
|
|
||||||
activeStore.update(
|
|
||||||
(map: ActiveMap): ActiveMap => {
|
|
||||||
const newMap = new Map() as ActiveMap;
|
|
||||||
|
|
||||||
for (const key of map.keys()) {
|
|
||||||
newMap.set(key, callback(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
return newMap;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateActiveButtons(event: Event) {
|
|
||||||
updateButtons((key: string): boolean => updateMap.get(key)(event));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearActiveButtons() {
|
|
||||||
updateButtons((): boolean => false);
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="typescript">
|
|
||||||
import SquareButton from "./SquareButton.svelte";
|
|
||||||
|
|
||||||
export let id: string;
|
|
||||||
export let className = "";
|
|
||||||
export let tooltip: string;
|
|
||||||
export let command: string;
|
|
||||||
|
|
||||||
export let onClick: (event: Event) => void;
|
|
||||||
|
|
||||||
function onClickWrapped(event: MouseEvent): void {
|
|
||||||
onClick(event);
|
|
||||||
updateButton(command, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
// document.queryCommandState(command);
|
|
||||||
export let update: (event: Event) => boolean;
|
|
||||||
|
|
||||||
updateMap.set(command, update);
|
|
||||||
|
|
||||||
let active = false;
|
|
||||||
|
|
||||||
activeStore.subscribe((map: ActiveMap): (() => void) => {
|
|
||||||
active = Boolean(map.get(command));
|
|
||||||
return () => map.delete(command);
|
|
||||||
});
|
|
||||||
activeMap.set(command, active);
|
|
||||||
|
|
||||||
export let disables = true;
|
|
||||||
export let dropdownToggle = false;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<SquareButton
|
|
||||||
{id}
|
|
||||||
{className}
|
|
||||||
{tooltip}
|
|
||||||
{active}
|
|
||||||
{disables}
|
|
||||||
{dropdownToggle}
|
|
||||||
on:click
|
|
||||||
on:mount>
|
|
||||||
<slot />
|
|
||||||
</SquareButton>
|
|
||||||
|
|
@ -3,18 +3,82 @@ Copyright: Ankitects Pty Ltd and contributors
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
-->
|
-->
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import ButtonGroupItem from "./ButtonGroupItem.svelte";
|
import type { Readable } from "svelte/store";
|
||||||
import SquareButton from "./SquareButton.svelte";
|
import { getContext, onMount, createEventDispatcher } from "svelte";
|
||||||
|
import { disabledKey, nightModeKey } from "./contextKeys";
|
||||||
|
|
||||||
export let id: string;
|
export let id: string;
|
||||||
let className = "";
|
let className = "";
|
||||||
export { className as class };
|
export { className as class };
|
||||||
|
|
||||||
export let tooltip: string | undefined;
|
export let tooltip: string | undefined;
|
||||||
|
export let active = false;
|
||||||
export let disables = true;
|
export let disables = true;
|
||||||
export let dropdownToggle = false;
|
export let dropdownToggle = false;
|
||||||
|
|
||||||
|
$: extraProps = dropdownToggle
|
||||||
|
? {
|
||||||
|
"data-bs-toggle": "dropdown",
|
||||||
|
"aria-expanded": "false",
|
||||||
|
}
|
||||||
|
: {};
|
||||||
|
|
||||||
|
let buttonRef: HTMLButtonElement;
|
||||||
|
|
||||||
|
const disabled = getContext<Readable<boolean>>(disabledKey);
|
||||||
|
$: _disabled = disables && $disabled;
|
||||||
|
|
||||||
|
const nightMode = getContext<boolean>(nightModeKey);
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
onMount(() => dispatch("mount", { button: buttonRef }));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<SquareButton {id} {className} {tooltip} {disables} {dropdownToggle} on:click on:mount>
|
<style lang="scss">
|
||||||
<slot />
|
@use "ts/sass/button_mixins" as button;
|
||||||
</SquareButton>
|
|
||||||
|
button {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include button.btn-day;
|
||||||
|
@include button.btn-night;
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
/* constrain icon */
|
||||||
|
width: calc(var(--toolbar-size) - 2px);
|
||||||
|
height: calc(var(--toolbar-size) - 2px);
|
||||||
|
|
||||||
|
& > :global(svg),
|
||||||
|
& > :global(img) {
|
||||||
|
fill: currentColor;
|
||||||
|
vertical-align: unset;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-toggle::after {
|
||||||
|
margin-right: 0.25rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<button
|
||||||
|
bind:this={buttonRef}
|
||||||
|
{id}
|
||||||
|
class={`btn ${className}`}
|
||||||
|
class:active
|
||||||
|
class:dropdown-toggle={dropdownToggle}
|
||||||
|
class:btn-day={!nightMode}
|
||||||
|
class:btn-night={nightMode}
|
||||||
|
tabindex="-1"
|
||||||
|
title={tooltip}
|
||||||
|
disabled={_disabled}
|
||||||
|
{...extraProps}
|
||||||
|
on:click
|
||||||
|
on:mousedown|preventDefault>
|
||||||
|
<span class="p-1"><slot /></span>
|
||||||
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
<!--
|
|
||||||
Copyright: Ankitects Pty Ltd and contributors
|
|
||||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|
||||||
-->
|
|
||||||
<script lang="typescript">
|
|
||||||
import type { Readable } from "svelte/store";
|
|
||||||
import { getContext, onMount, createEventDispatcher } from "svelte";
|
|
||||||
import { disabledKey, nightModeKey } from "./contextKeys";
|
|
||||||
import { mergeTooltipAndShortcut } from "./helpers";
|
|
||||||
|
|
||||||
export let id: string;
|
|
||||||
export let className = "";
|
|
||||||
export let tooltip: string | undefined;
|
|
||||||
export let shortcutLabel: string | undefined;
|
|
||||||
|
|
||||||
$: title = mergeTooltipAndShortcut(tooltip, shortcutLabel);
|
|
||||||
|
|
||||||
export let onClick: (event: MouseEvent) => void;
|
|
||||||
export let active = false;
|
|
||||||
export let disables = true;
|
|
||||||
export let dropdownToggle = false;
|
|
||||||
|
|
||||||
$: extraProps = dropdownToggle
|
|
||||||
? {
|
|
||||||
"data-bs-toggle": "dropdown",
|
|
||||||
"aria-expanded": "false",
|
|
||||||
}
|
|
||||||
: {};
|
|
||||||
|
|
||||||
let buttonRef: HTMLButtonElement;
|
|
||||||
|
|
||||||
function extendClassName(className: string): string {
|
|
||||||
return `btn ${className}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const disabled = getContext<Readable<boolean>>(disabledKey);
|
|
||||||
$: _disabled = disables && $disabled;
|
|
||||||
|
|
||||||
const nightMode = getContext<boolean>(nightModeKey);
|
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
|
||||||
onMount(() => dispatch("mount", { button: buttonRef }));
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@use "ts/sass/button_mixins" as button;
|
|
||||||
|
|
||||||
button {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@include button.btn-day;
|
|
||||||
@include button.btn-night;
|
|
||||||
|
|
||||||
span {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
/* constrain icon */
|
|
||||||
width: calc(var(--toolbar-size) - 2px);
|
|
||||||
height: calc(var(--toolbar-size) - 2px);
|
|
||||||
|
|
||||||
& > :global(svg),
|
|
||||||
& > :global(img) {
|
|
||||||
fill: currentColor;
|
|
||||||
vertical-align: unset;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-toggle::after {
|
|
||||||
margin-right: 0.25rem;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<button
|
|
||||||
bind:this={buttonRef}
|
|
||||||
{id}
|
|
||||||
class={extendClassName(className)}
|
|
||||||
class:active
|
|
||||||
class:dropdown-toggle={dropdownToggle}
|
|
||||||
class:btn-day={!nightMode}
|
|
||||||
class:btn-night={nightMode}
|
|
||||||
tabindex="-1"
|
|
||||||
{title}
|
|
||||||
disabled={_disabled}
|
|
||||||
{...extraProps}
|
|
||||||
on:click={onClick}
|
|
||||||
on:mousedown|preventDefault>
|
|
||||||
<span class="p-1"><slot /></span>
|
|
||||||
</button>
|
|
||||||
68
ts/components/WithState.svelte
Normal file
68
ts/components/WithState.svelte
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
<!--
|
||||||
|
Copyright: Ankitects Pty Ltd and contributors
|
||||||
|
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
-->
|
||||||
|
<script lang="typescript" context="module">
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
type T = unknown;
|
||||||
|
|
||||||
|
type UpdaterMap = Map<string, (event: Event) => T>;
|
||||||
|
type StateMap = Map<string, T>;
|
||||||
|
|
||||||
|
const updaterMap = new Map() as UpdaterMap;
|
||||||
|
const stateMap = new Map() as StateMap;
|
||||||
|
const stateStore = writable(stateMap);
|
||||||
|
|
||||||
|
function updateAllStateWithCallback(callback: (key: string) => T): void {
|
||||||
|
stateStore.update(
|
||||||
|
(map: StateMap): StateMap => {
|
||||||
|
const newMap = new Map() as StateMap;
|
||||||
|
|
||||||
|
for (const key of map.keys()) {
|
||||||
|
newMap.set(key, callback(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return newMap;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateAllState(event: Event): void {
|
||||||
|
updateAllStateWithCallback((key: string): T => updaterMap.get(key)(event));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resetAllState(state: T): void {
|
||||||
|
updateAllStateWithCallback((): T => state);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateStateByKey(key: string, event: MouseEvent): void {
|
||||||
|
stateStore.update(
|
||||||
|
(map: StateMap): StateMap => {
|
||||||
|
map.set(key, updaterMap.get(key)(event));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="typescript">
|
||||||
|
export let key: string;
|
||||||
|
export let update: (event: Event) => T;
|
||||||
|
export let state: T;
|
||||||
|
|
||||||
|
updaterMap.set(key, update);
|
||||||
|
|
||||||
|
stateStore.subscribe((map: StateMap): (() => void) => {
|
||||||
|
state = Boolean(map.get(key));
|
||||||
|
return () => map.delete(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
stateMap.set(key, state);
|
||||||
|
|
||||||
|
function updateState(event: Event): void {
|
||||||
|
updateStateByKey(key, event);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<slot {state} {updateState} />
|
||||||
|
|
@ -19,7 +19,9 @@ filegroup(
|
||||||
compile_svelte(
|
compile_svelte(
|
||||||
name = "svelte",
|
name = "svelte",
|
||||||
srcs = svelte_files,
|
srcs = svelte_files,
|
||||||
deps = [],
|
deps = [
|
||||||
|
"//ts/components",
|
||||||
|
],
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -66,13 +68,11 @@ ts_library(
|
||||||
srcs = glob(["*.ts"]),
|
srcs = glob(["*.ts"]),
|
||||||
tsconfig = "//ts:tsconfig.json",
|
tsconfig = "//ts:tsconfig.json",
|
||||||
deps = [
|
deps = [
|
||||||
"//ts:image_module_support",
|
|
||||||
"//ts/lib",
|
"//ts/lib",
|
||||||
"//ts/sveltelib",
|
"//ts/sveltelib",
|
||||||
"//ts/components",
|
"//ts/components",
|
||||||
"//ts/html-filter",
|
"//ts/html-filter",
|
||||||
# "svelte_components",
|
"//ts:image_module_support",
|
||||||
# "//ts/components:svelte_components",
|
|
||||||
"@npm//svelte",
|
"@npm//svelte",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import type { EditingArea } from "./editingArea";
|
import type { EditingArea } from "./editingArea";
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
|
||||||
import CommandIconButton from "components/CommandIconButton.svelte";
|
|
||||||
import IconButton from "components/IconButton.svelte";
|
import IconButton from "components/IconButton.svelte";
|
||||||
import ButtonGroup from "components/ButtonGroup.svelte";
|
import ButtonGroup from "components/ButtonGroup.svelte";
|
||||||
import ButtonDropdown from "components/ButtonDropdown.svelte";
|
import ButtonDropdown from "components/ButtonDropdown.svelte";
|
||||||
|
import WithState from "components/WithState.svelte";
|
||||||
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
||||||
|
|
||||||
import { getListItem } from "./helpers";
|
import { getListItem } from "./helpers";
|
||||||
|
|
@ -44,25 +44,25 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
<ButtonDropdown id="listFormatting">
|
<ButtonDropdown id="listFormatting">
|
||||||
<ButtonGroup id="justify" {api}>
|
<ButtonGroup id="justify" {api}>
|
||||||
<CommandIconButton command="justifyLeft" tooltip={tr.editingAlignLeft()}>
|
<IconButton command="justifyLeft" tooltip={tr.editingAlignLeft()}>
|
||||||
{@html justifyLeftIcon}
|
{@html justifyLeftIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
|
|
||||||
<CommandIconButton command="justifyCenter" tooltip={tr.editingCenter()}>
|
<IconButton command="justifyCenter" tooltip={tr.editingCenter()}>
|
||||||
{@html justifyCenterIcon}
|
{@html justifyCenterIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
|
|
||||||
<CommandIconButton command="justifyCenter" tooltip={tr.editingCenter()}>
|
<IconButton command="justifyCenter" tooltip={tr.editingCenter()}>
|
||||||
{@html justifyCenterIcon}
|
{@html justifyCenterIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
|
|
||||||
<CommandIconButton command="justifyRight" tooltip={tr.editingAlignRight()}>
|
<IconButton command="justifyRight" tooltip={tr.editingAlignRight()}>
|
||||||
{@html justifyRightIcon}
|
{@html justifyRightIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
|
|
||||||
<CommandIconButton command="justifyFull" tooltip={tr.editingJustify()}>
|
<IconButton command="justifyFull" tooltip={tr.editingJustify()}>
|
||||||
{@html justifyFullIcon}
|
{@html justifyFullIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
||||||
<ButtonGroup id="indentation" {api}>
|
<ButtonGroup id="indentation" {api}>
|
||||||
|
|
@ -77,15 +77,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
</ButtonDropdown>
|
</ButtonDropdown>
|
||||||
|
|
||||||
<ButtonGroup id="blockFormatting" {api}>
|
<ButtonGroup id="blockFormatting" {api}>
|
||||||
<CommandIconButton
|
<IconButton command="insertUnorderedList" tooltip={tr.editingUnorderedList()}>
|
||||||
command="insertUnorderedList"
|
|
||||||
tooltip={tr.editingUnorderedList()}>
|
|
||||||
{@html ulIcon}
|
{@html ulIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
|
|
||||||
<CommandIconButton command="insertOrderedList" tooltip={tr.editingOrderedList()}>
|
<IconButton command="insertOrderedList" tooltip={tr.editingOrderedList()}>
|
||||||
{@html olIcon}
|
{@html olIcon}
|
||||||
</CommandIconButton>
|
</IconButton>
|
||||||
|
|
||||||
<WithDropdownMenu menuId="listFormatting">
|
<WithDropdownMenu menuId="listFormatting">
|
||||||
<IconButton>
|
<IconButton>
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
<script lang="typescript">
|
<script lang="typescript">
|
||||||
import * as tr from "lib/i18n";
|
import * as tr from "lib/i18n";
|
||||||
|
|
||||||
import CommandIconButton from "components/CommandIconButton.svelte";
|
|
||||||
import IconButton from "components/IconButton.svelte";
|
import IconButton from "components/IconButton.svelte";
|
||||||
import ButtonGroup from "components/ButtonGroup.svelte";
|
import ButtonGroup from "components/ButtonGroup.svelte";
|
||||||
|
import WithState from "components/WithState.svelte";
|
||||||
import WithShortcut from "components/WithShortcut.svelte";
|
import WithShortcut from "components/WithShortcut.svelte";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -24,22 +24,63 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
<ButtonGroup id="notetype" {api}>
|
<ButtonGroup id="notetype" {api}>
|
||||||
<WithShortcut shortcut="Control+KeyB" let:createShortcut let:shortcutLabel>
|
<WithShortcut shortcut="Control+KeyB" let:createShortcut let:shortcutLabel>
|
||||||
<CommandIconButton
|
<WithState
|
||||||
tooltip={`${tr.editingBoldText()} (${shortcutLabel})`}
|
key="bold"
|
||||||
command="bold"
|
update={() => document.queryCommandState('bold')}
|
||||||
onClick={() => document.execCommand('bold')}
|
let:state={active}
|
||||||
on:mount={createShortcut}>
|
let:updateState>
|
||||||
{@html boldIcon}
|
<IconButton
|
||||||
</CommandIconButton>
|
tooltip={`${tr.editingBoldText()} (${shortcutLabel})`}
|
||||||
|
{active}
|
||||||
|
on:click={(event) => {
|
||||||
|
document.execCommand('bold');
|
||||||
|
updateState(event);
|
||||||
|
}}
|
||||||
|
on:mount={createShortcut}>
|
||||||
|
{@html boldIcon}
|
||||||
|
</IconButton>
|
||||||
|
</WithState>
|
||||||
</WithShortcut>
|
</WithShortcut>
|
||||||
|
|
||||||
<WithShortcut shortcut="Control+KeyI">
|
<WithShortcut shortcut="Control+KeyI" let:createShortcut let:shortcutLabel>
|
||||||
<CommandIconButton tooltip={tr.editingItalicText()} command="italic">
|
<WithState
|
||||||
{@html italicIcon}
|
key="italic"
|
||||||
</CommandIconButton>
|
update={() => document.queryCommandState('italic')}
|
||||||
|
let:state={active}
|
||||||
|
let:updateState>
|
||||||
|
<IconButton
|
||||||
|
tooltip={`${tr.editingItalicText()} (${shortcutLabel})`}
|
||||||
|
{active}
|
||||||
|
on:click={(event) => {
|
||||||
|
document.execCommand('italic');
|
||||||
|
updateState(event);
|
||||||
|
}}
|
||||||
|
on:mount={createShortcut}>
|
||||||
|
{@html italicIcon}
|
||||||
|
</IconButton>
|
||||||
|
</WithState>
|
||||||
</WithShortcut>
|
</WithShortcut>
|
||||||
|
|
||||||
<WithShortcut shortcut="Control+KeyU">
|
<WithShortcut shortcut="Control+KeyU" let:createShortcut let:shortcutLabel>
|
||||||
|
<WithState
|
||||||
|
key="underline"
|
||||||
|
update={() => document.queryCommandState('underline')}
|
||||||
|
let:state={active}
|
||||||
|
let:updateState>
|
||||||
|
<IconButton
|
||||||
|
tooltip={`${tr.editingUnderlineText()} (${shortcutLabel})`}
|
||||||
|
{active}
|
||||||
|
on:click={(event) => {
|
||||||
|
document.execCommand('underline');
|
||||||
|
updateState(event);
|
||||||
|
}}
|
||||||
|
on:mount={createShortcut}>
|
||||||
|
{@html underlineIcon}
|
||||||
|
</IconButton>
|
||||||
|
</WithState>
|
||||||
|
</WithShortcut>
|
||||||
|
|
||||||
|
<!--<WithShortcut shortcut="Control+KeyU">
|
||||||
<CommandIconButton tooltip={tr.editingUnderlineText()} command="underline">
|
<CommandIconButton tooltip={tr.editingUnderlineText()} command="underline">
|
||||||
{@html underlineIcon}
|
{@html underlineIcon}
|
||||||
</CommandIconButton>
|
</CommandIconButton>
|
||||||
|
|
@ -65,5 +106,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
}}>
|
}}>
|
||||||
{@html eraserIcon}
|
{@html eraserIcon}
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</WithShortcut>
|
</WithShortcut> -->
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export function focusField(n: number): void {
|
||||||
if (field) {
|
if (field) {
|
||||||
field.editingArea.focusEditable();
|
field.editingArea.focusEditable();
|
||||||
caretToEnd(field.editingArea);
|
caretToEnd(field.editingArea);
|
||||||
updateActiveButtons();
|
updateActiveButtons(new Event("manualfocus"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,7 +163,7 @@ export function setFormat(cmd: string, arg?: any, nosave: boolean = false): void
|
||||||
document.execCommand(cmd, false, arg);
|
document.execCommand(cmd, false, arg);
|
||||||
if (!nosave) {
|
if (!nosave) {
|
||||||
saveField(getCurrentField() as EditingArea, "key");
|
saveField(getCurrentField() as EditingArea, "key");
|
||||||
updateActiveButtons();
|
updateActiveButtons(new Event(cmd));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { registerShortcut } from "lib/shortcuts";
|
||||||
export function onInput(event: Event): void {
|
export function onInput(event: Event): void {
|
||||||
// make sure IME changes get saved
|
// make sure IME changes get saved
|
||||||
triggerChangeTimer(event.currentTarget as EditingArea);
|
triggerChangeTimer(event.currentTarget as EditingArea);
|
||||||
updateActiveButtons();
|
updateActiveButtons(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onKey(evt: KeyboardEvent): void {
|
export function onKey(evt: KeyboardEvent): void {
|
||||||
|
|
@ -56,7 +56,7 @@ function updateFocus(evt: FocusEvent) {
|
||||||
const newFocusTarget = evt.target;
|
const newFocusTarget = evt.target;
|
||||||
if (newFocusTarget instanceof EditingArea) {
|
if (newFocusTarget instanceof EditingArea) {
|
||||||
caretToEnd(newFocusTarget);
|
caretToEnd(newFocusTarget);
|
||||||
updateActiveButtons();
|
updateActiveButtons(evt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,10 @@ export function initToolbar(i18n: Promise<void>): Promise<EditorToolbar> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exports for editor */
|
/* Exports for editor */
|
||||||
|
export {
|
||||||
|
updateAllState as updateActiveButtons,
|
||||||
|
resetAllState as clearActiveButtons,
|
||||||
|
} from "components/WithState.svelte";
|
||||||
|
|
||||||
// @ts-expect-error insufficient typing of svelte modules
|
// @ts-expect-error insufficient typing of svelte modules
|
||||||
export { enableButtons, disableButtons } from "./EditorToolbar.svelte";
|
export { enableButtons, disableButtons } from "./EditorToolbar.svelte";
|
||||||
// @ts-expect-error insufficient typing of svelte modules
|
|
||||||
export { updateActiveButtons, clearActiveButtons } from "components/CommandIconButton.svelte";
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue