mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
Disable Bold button in Codable
This commit is contained in:
parent
817dee1a1b
commit
eeb954535f
8 changed files with 81 additions and 32 deletions
|
@ -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
|
||||||
|
|
16
ts/components/WithContext.svelte
Normal file
16
ts/components/WithContext.svelte
Normal 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} />
|
|
@ -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;
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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
4
ts/editor/contextKeys.ts
Normal 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");
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue