Disable Bold button in Codable

This commit is contained in:
Henrik Giesel 2021-06-18 00:27:07 +02:00
parent 817dee1a1b
commit eeb954535f
8 changed files with 81 additions and 32 deletions

View file

@ -3,9 +3,8 @@ 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 type { Readable } from "svelte/store";
import { getContext, onMount, createEventDispatcher } from "svelte"; import { getContext, onMount, createEventDispatcher } from "svelte";
import { disabledKey, nightModeKey, dropdownKey } from "./contextKeys"; import { nightModeKey, dropdownKey } from "./contextKeys";
import type { DropdownProps } from "./dropdown"; import type { DropdownProps } from "./dropdown";
export let id: string | undefined = undefined; export let id: string | undefined = undefined;
@ -14,7 +13,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let tooltip: string | undefined = undefined; export let tooltip: string | undefined = undefined;
export let active = false; export let active = false;
export let disables = true; export let disabled = false;
export const disables = false; /* unused */
export let tabbable = false; export let tabbable = false;
export let iconSize: number = 75; export let iconSize: number = 75;
@ -22,9 +22,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let buttonRef: HTMLButtonElement; let buttonRef: HTMLButtonElement;
const disabled = getContext<Readable<boolean>>(disabledKey);
$: _disabled = disables && $disabled;
const nightMode = getContext<boolean>(nightModeKey); const nightMode = getContext<boolean>(nightModeKey);
const dropdownProps = getContext<DropdownProps>(dropdownKey) ?? { dropdown: false }; const dropdownProps = getContext<DropdownProps>(dropdownKey) ?? { dropdown: false };
@ -43,7 +40,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
style={`--icon-size: ${iconSize}%`} style={`--icon-size: ${iconSize}%`}
title={tooltip} title={tooltip}
{...dropdownProps} {...dropdownProps}
disabled={_disabled} {disabled}
tabindex={tabbable ? 0 : -1} tabindex={tabbable ? 0 : -1}
on:click on:click
on:mousedown|preventDefault on:mousedown|preventDefault

View file

@ -0,0 +1,16 @@
<!--
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 } from "svelte";
type T = unknown;
export let key: Symbol | string;
const store = getContext<Readable<T>>(key);
</script>
<slot context={$store} />

View file

@ -5,14 +5,15 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<script lang="typescript" context="module"> <script lang="typescript" context="module">
import { writable } from "svelte/store"; import { writable } from "svelte/store";
type UpdaterMap = Map<string, (event: Event) => boolean>; type KeyType = Symbol | string;
type StateMap = Map<string, boolean>; type UpdaterMap = Map<KeyType, (event: Event) => boolean>;
type StateMap = Map<KeyType, boolean>;
const updaterMap = new Map() as UpdaterMap; const updaterMap = new Map() as UpdaterMap;
const stateMap = new Map() as StateMap; const stateMap = new Map() as StateMap;
const stateStore = writable(stateMap); const stateStore = writable(stateMap);
function updateAllStateWithCallback(callback: (key: string) => boolean): void { function updateAllStateWithCallback(callback: (key: KeyType) => boolean): void {
stateStore.update((map: StateMap): StateMap => { stateStore.update((map: StateMap): StateMap => {
const newMap = new Map() as StateMap; const newMap = new Map() as StateMap;
@ -25,7 +26,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
export function updateAllState(event: Event): void { export function updateAllState(event: Event): void {
updateAllStateWithCallback((key: string): boolean => updateAllStateWithCallback((key: KeyType): boolean =>
updaterMap.get(key)!(event) updaterMap.get(key)!(event)
); );
} }
@ -34,7 +35,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
updateAllStateWithCallback((): boolean => state); updateAllStateWithCallback((): boolean => state);
} }
function updateStateByKey(key: string, event: Event): void { function updateStateByKey(key: KeyType, event: Event): void {
stateStore.update((map: StateMap): StateMap => { stateStore.update((map: StateMap): StateMap => {
map.set(key, updaterMap.get(key)!(event)); map.set(key, updaterMap.get(key)!(event));
return map; return map;
@ -43,7 +44,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
</script> </script>
<script lang="typescript"> <script lang="typescript">
export let key: string; export let key: KeyType;
export let update: (event: Event) => boolean; export let update: (event: Event) => boolean;
let state: boolean = false; let state: boolean = false;

View file

@ -8,8 +8,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import ButtonGroup from "components/ButtonGroup.svelte"; import ButtonGroup from "components/ButtonGroup.svelte";
import ButtonGroupItem from "components/ButtonGroupItem.svelte"; import ButtonGroupItem from "components/ButtonGroupItem.svelte";
import IconButton from "components/IconButton.svelte"; import IconButton from "components/IconButton.svelte";
import WithState from "components/WithState.svelte";
import WithShortcut from "components/WithShortcut.svelte"; import WithShortcut from "components/WithShortcut.svelte";
import WithContext from "components/WithContext.svelte";
import WithState from "components/WithState.svelte";
import { import {
boldIcon, boldIcon,
@ -20,6 +21,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
eraserIcon, eraserIcon,
} from "./icons"; } from "./icons";
import { appendInParentheses } from "./helpers"; import { appendInParentheses } from "./helpers";
import { disabledKey } from "components/contextKeys";
import { inCodableKey } from "./contextKeys";
export let api = {}; export let api = {};
</script> </script>
@ -27,6 +30,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<ButtonGroup {api}> <ButtonGroup {api}>
<ButtonGroupItem> <ButtonGroupItem>
<WithShortcut shortcut={"Control+B"} let:createShortcut let:shortcutLabel> <WithShortcut shortcut={"Control+B"} let:createShortcut let:shortcutLabel>
<WithContext key={disabledKey} let:context={disabled}>
<WithContext key={inCodableKey} let:context={inCodable}>
<WithState <WithState
key="bold" key="bold"
update={() => document.queryCommandState("bold")} update={() => document.queryCommandState("bold")}
@ -34,8 +39,12 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
let:updateState let:updateState
> >
<IconButton <IconButton
tooltip={appendInParentheses(tr.editingBoldText(), shortcutLabel)} tooltip={appendInParentheses(
tr.editingBoldText(),
shortcutLabel
)}
{active} {active}
disabled={disabled || inCodable}
on:click={(event) => { on:click={(event) => {
document.execCommand("bold"); document.execCommand("bold");
updateState(event); updateState(event);
@ -45,6 +54,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
{@html boldIcon} {@html boldIcon}
</IconButton> </IconButton>
</WithState> </WithState>
</WithContext>
</WithContext>
</WithShortcut> </WithShortcut>
</ButtonGroupItem> </ButtonGroupItem>

View file

@ -9,6 +9,8 @@ import "codemirror/addon/fold/xml-fold";
import "codemirror/addon/edit/matchtags.js"; import "codemirror/addon/edit/matchtags.js";
import "codemirror/addon/edit/closetag.js"; import "codemirror/addon/edit/closetag.js";
import { setCodableButtons } from "./toolbar";
const codeMirrorOptions = { const codeMirrorOptions = {
mode: "htmlmixed", mode: "htmlmixed",
theme: "monokai", theme: "monokai",
@ -64,6 +66,7 @@ export class Codable extends HTMLTextAreaElement {
focus(): void { focus(): void {
this.codeMirror.focus(); this.codeMirror.focus();
setCodableButtons();
} }
caretToEnd(): void { caretToEnd(): void {

4
ts/editor/contextKeys.ts Normal file
View file

@ -0,0 +1,4 @@
// Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export const inCodableKey = Symbol("inCodable");

View file

@ -3,6 +3,7 @@
import { bridgeCommand } from "./lib"; import { bridgeCommand } from "./lib";
import { nodeIsInline, caretToEnd, getBlockElement } from "./helpers"; import { nodeIsInline, caretToEnd, getBlockElement } from "./helpers";
import { setEditableButtons } from "./toolbar";
function containsInlineContent(field: Element): boolean { function containsInlineContent(field: Element): boolean {
if (field.childNodes.length === 0) { if (field.childNodes.length === 0) {
@ -38,6 +39,11 @@ export class Editable extends HTMLElement {
this.setAttribute("contenteditable", ""); this.setAttribute("contenteditable", "");
} }
focus() {
super.focus();
setEditableButtons();
}
caretToEnd() { caretToEnd() {
caretToEnd(this); caretToEnd(this);
} }

View file

@ -7,12 +7,14 @@
*/ */
import { disabledKey, nightModeKey } from "components/contextKeys"; import { disabledKey, nightModeKey } from "components/contextKeys";
import { inCodableKey } from "./contextKeys";
import { writable } from "svelte/store"; import { writable } from "svelte/store";
import EditorToolbar from "./EditorToolbar.svelte"; import EditorToolbar from "./EditorToolbar.svelte";
import "./bootstrap.css"; import "./bootstrap.css";
const disabled = writable(false); const disabled = writable(false);
const inCodable = writable(false);
export function initToolbar(i18n: Promise<void>): Promise<EditorToolbar> { export function initToolbar(i18n: Promise<void>): Promise<EditorToolbar> {
let toolbarResolve: (value: EditorToolbar) => void; let toolbarResolve: (value: EditorToolbar) => void;
@ -27,6 +29,7 @@ export function initToolbar(i18n: Promise<void>): Promise<EditorToolbar> {
const context = new Map(); const context = new Map();
context.set(disabledKey, disabled); context.set(disabledKey, disabled);
context.set(inCodableKey, inCodable);
context.set( context.set(
nightModeKey, nightModeKey,
document.documentElement.classList.contains("night-mode") document.documentElement.classList.contains("night-mode")
@ -47,6 +50,14 @@ export function disableButtons(): void {
disabled.set(true); disabled.set(true);
} }
export function setCodableButtons(): void {
inCodable.set(true);
}
export function setEditableButtons(): void {
inCodable.set(false);
}
export { export {
updateActiveButtons, updateActiveButtons,
clearActiveButtons, clearActiveButtons,