mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 06:22:22 -04:00
Re-enable formatting for .ts files
There are some style differences compared to prettier, and not all are necessarily an improvement, but it's much faster now.
This commit is contained in:
parent
ea5153e7a4
commit
b2049209ff
47 changed files with 174 additions and 258 deletions
|
@ -18,7 +18,6 @@
|
||||||
"**/node_modules",
|
"**/node_modules",
|
||||||
"out/**",
|
"out/**",
|
||||||
"**/*-lock.json",
|
"**/*-lock.json",
|
||||||
"**/*.{ts}",
|
|
||||||
"qt/aqt/data/web/js/vendor/*.js",
|
"qt/aqt/data/web/js/vendor/*.js",
|
||||||
"ftl/qt-repo",
|
"ftl/qt-repo",
|
||||||
"ftl/core-repo",
|
"ftl/core-repo",
|
||||||
|
|
|
@ -8,7 +8,7 @@ function init() {
|
||||||
scroll: false,
|
scroll: false,
|
||||||
|
|
||||||
// can't use "helper: 'clone'" because of a bug in jQuery 1.5
|
// can't use "helper: 'clone'" because of a bug in jQuery 1.5
|
||||||
helper: function (_event) {
|
helper: function(_event) {
|
||||||
return $(this).clone(false);
|
return $(this).clone(false);
|
||||||
},
|
},
|
||||||
delay: 200,
|
delay: 200,
|
||||||
|
|
|
@ -10,7 +10,7 @@ let time: number; // set in python code
|
||||||
let maxTime = 0;
|
let maxTime = 0;
|
||||||
document.addEventListener("DOMContentLoaded", () => {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
updateTime();
|
updateTime();
|
||||||
setInterval(function () {
|
setInterval(function() {
|
||||||
time += 1;
|
time += 1;
|
||||||
updateTime();
|
updateTime();
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* 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 */
|
||||||
|
|
||||||
// prevent backspace key from going back a page
|
// prevent backspace key from going back a page
|
||||||
document.addEventListener("keydown", function (evt: KeyboardEvent) {
|
document.addEventListener("keydown", function(evt: KeyboardEvent) {
|
||||||
if (evt.keyCode !== 8) {
|
if (evt.keyCode !== 8) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import * as tr from "@tslib/ftl";
|
import * as tr from "@tslib/ftl";
|
||||||
import { Notetypes, notetypes } from "@tslib/proto";
|
import { Notetypes, notetypes } from "@tslib/proto";
|
||||||
import { isEqual } from "lodash-es";
|
import { isEqual } from "lodash-es";
|
||||||
import type { Readable} from "svelte/store";
|
import type { Readable } from "svelte/store";
|
||||||
import { readable } from "svelte/store";
|
import { readable } from "svelte/store";
|
||||||
|
|
||||||
function nullToNegativeOne(list: (number | null)[]): number[] {
|
function nullToNegativeOne(list: (number | null)[]): number[] {
|
||||||
|
|
|
@ -15,14 +15,10 @@ export function mergeTooltipAndShortcut(
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const withButton =
|
export const withButton = (f: (button: HTMLButtonElement) => void) => ({ detail }: CustomEvent): void => {
|
||||||
(f: (button: HTMLButtonElement) => void) =>
|
f(detail.button);
|
||||||
({ detail }: CustomEvent): void => {
|
};
|
||||||
f(detail.button);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const withSpan =
|
export const withSpan = (f: (span: HTMLSpanElement) => void) => ({ detail }: CustomEvent): void => {
|
||||||
(f: (span: HTMLSpanElement) => void) =>
|
f(detail.span);
|
||||||
({ detail }: CustomEvent): void => {
|
};
|
||||||
f(detail.span);
|
|
||||||
};
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
@typescript-eslint/no-explicit-any: "off",
|
@typescript-eslint/no-explicit-any: "off",
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
import { DeckConfig } from "@tslib/proto";
|
import { DeckConfig } from "@tslib/proto";
|
||||||
import { get } from "svelte/store";
|
import { get } from "svelte/store";
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { localeCompare } from "@tslib/i18n";
|
import { localeCompare } from "@tslib/i18n";
|
||||||
import { DeckConfig, deckConfig } from "@tslib/proto";
|
import { DeckConfig, deckConfig } from "@tslib/proto";
|
||||||
import { cloneDeep, isEqual } from "lodash-es";
|
import { cloneDeep, isEqual } from "lodash-es";
|
||||||
import type { Readable, Writable} from "svelte/store";
|
import type { Readable, Writable } from "svelte/store";
|
||||||
import { get, readable, writable } from "svelte/store";
|
import { get, readable, writable } from "svelte/store";
|
||||||
|
|
||||||
import type { DynamicSvelteComponent } from "../sveltelib/dynamicComponent";
|
import type { DynamicSvelteComponent } from "../sveltelib/dynamicComponent";
|
||||||
|
|
|
@ -13,13 +13,6 @@ registerPackage("anki/location", {
|
||||||
saveSelection,
|
saveSelection,
|
||||||
});
|
});
|
||||||
|
|
||||||
export {
|
export { findNodeFromCoordinates, getNodeCoordinates, getRangeCoordinates, Position, restoreSelection, saveSelection };
|
||||||
findNodeFromCoordinates,
|
|
||||||
getNodeCoordinates,
|
|
||||||
getRangeCoordinates,
|
|
||||||
Position,
|
|
||||||
restoreSelection,
|
|
||||||
saveSelection,
|
|
||||||
};
|
|
||||||
export type { RangeCoordinates } from "./range";
|
export type { RangeCoordinates } from "./range";
|
||||||
export type { SelectionLocation } from "./selection";
|
export type { SelectionLocation } from "./selection";
|
||||||
|
|
|
@ -62,9 +62,9 @@ function buildFromElement<T>(
|
||||||
|
|
||||||
if (
|
if (
|
||||||
// blocking
|
// blocking
|
||||||
only instanceof BlockNode ||
|
only instanceof BlockNode
|
||||||
// ascension
|
// ascension
|
||||||
(only instanceof FormattingNode && format.tryAscend(only, matchNode))
|
|| (only instanceof FormattingNode && format.tryAscend(only, matchNode))
|
||||||
) {
|
) {
|
||||||
return [only];
|
return [only];
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Position } from "../../location";
|
||||||
import { Match } from "../match-type";
|
import { Match } from "../match-type";
|
||||||
import type { SplitRange } from "../split-text";
|
import type { SplitRange } from "../split-text";
|
||||||
import type { SurroundFormat } from "../surround-format";
|
import type { SurroundFormat } from "../surround-format";
|
||||||
import type { ElementNode} from "../tree";
|
import type { ElementNode } from "../tree";
|
||||||
import { FormattingNode } from "../tree";
|
import { FormattingNode } from "../tree";
|
||||||
|
|
||||||
function nodeWithinRange(node: Node, range: Range): boolean {
|
function nodeWithinRange(node: Node, range: Range): boolean {
|
||||||
|
@ -14,9 +14,9 @@ function nodeWithinRange(node: Node, range: Range): boolean {
|
||||||
nodeRange.selectNodeContents(node);
|
nodeRange.selectNodeContents(node);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
range.compareBoundaryPoints(Range.START_TO_START, nodeRange) !==
|
range.compareBoundaryPoints(Range.START_TO_START, nodeRange)
|
||||||
Position.After &&
|
!== Position.After
|
||||||
range.compareBoundaryPoints(Range.END_TO_END, nodeRange) !== Position.Before
|
&& range.compareBoundaryPoints(Range.END_TO_END, nodeRange) !== Position.Before
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,8 +69,7 @@ export class FlatRange {
|
||||||
if (range.collapsed) {
|
if (range.collapsed) {
|
||||||
// If the range is collapsed to a single element, move the range inside the element.
|
// If the range is collapsed to a single element, move the range inside the element.
|
||||||
// This prevents putting the surround above the base element.
|
// This prevents putting the surround above the base element.
|
||||||
const selected =
|
const selected = range.commonAncestorContainer.childNodes[range.startOffset];
|
||||||
range.commonAncestorContainer.childNodes[range.startOffset];
|
|
||||||
|
|
||||||
if (nodeIsElement(selected)) {
|
if (nodeIsElement(selected)) {
|
||||||
range.selectNode(selected);
|
range.selectNode(selected);
|
||||||
|
|
|
@ -83,7 +83,7 @@ class FakeMatch implements MatchType<never> {
|
||||||
export function boolMatcher<T>(
|
export function boolMatcher<T>(
|
||||||
format: SurroundFormat<T>,
|
format: SurroundFormat<T>,
|
||||||
): (element: Element) => boolean {
|
): (element: Element) => boolean {
|
||||||
return function (element: Element): boolean {
|
return function(element: Element): boolean {
|
||||||
const fake = new FakeMatch();
|
const fake = new FakeMatch();
|
||||||
format.matcher(element as HTMLElement | SVGElement, fake);
|
format.matcher(element as HTMLElement | SVGElement, fake);
|
||||||
return fake.value;
|
return fake.value;
|
||||||
|
|
|
@ -10,8 +10,8 @@ function length(node: Node): number {
|
||||||
if (node instanceof CharacterData) {
|
if (node instanceof CharacterData) {
|
||||||
return node.length;
|
return node.length;
|
||||||
} else if (
|
} else if (
|
||||||
node.nodeType === Node.DOCUMENT_TYPE_NODE ||
|
node.nodeType === Node.DOCUMENT_TYPE_NODE
|
||||||
node.nodeType === Node.ATTRIBUTE_NODE
|
|| node.nodeType === Node.ATTRIBUTE_NODE
|
||||||
) {
|
) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,8 @@
|
||||||
|
|
||||||
import type { Matcher } from "../find-above";
|
import type { Matcher } from "../find-above";
|
||||||
import { findFarthest } from "../find-above";
|
import { findFarthest } from "../find-above";
|
||||||
import {
|
import { apply, ApplyFormat, ReformatApplyFormat, UnsurroundApplyFormat } from "./apply";
|
||||||
apply,
|
import { build, BuildFormat, ReformatBuildFormat, UnsurroundBuildFormat } from "./build";
|
||||||
ApplyFormat,
|
|
||||||
ReformatApplyFormat,
|
|
||||||
UnsurroundApplyFormat,
|
|
||||||
} from "./apply";
|
|
||||||
import {
|
|
||||||
build,
|
|
||||||
BuildFormat,
|
|
||||||
ReformatBuildFormat,
|
|
||||||
UnsurroundBuildFormat,
|
|
||||||
} from "./build";
|
|
||||||
import { boolMatcher } from "./match-type";
|
import { boolMatcher } from "./match-type";
|
||||||
import { splitPartiallySelected } from "./split-text";
|
import { splitPartiallySelected } from "./split-text";
|
||||||
import type { SurroundFormat } from "./surround-format";
|
import type { SurroundFormat } from "./surround-format";
|
||||||
|
@ -53,7 +43,7 @@ function reformatInner<T>(
|
||||||
* Assumes that there are no matching ancestor elements above
|
* Assumes that there are no matching ancestor elements above
|
||||||
* `range.commonAncestorContainer`. Make sure that the range is not placed
|
* `range.commonAncestorContainer`. Make sure that the range is not placed
|
||||||
* inside the format before using this.
|
* inside the format before using this.
|
||||||
**/
|
*/
|
||||||
export function surround<T>(
|
export function surround<T>(
|
||||||
range: Range,
|
range: Range,
|
||||||
base: Element,
|
base: Element,
|
||||||
|
|
|
@ -3,13 +3,11 @@
|
||||||
|
|
||||||
import type { MatchType } from "./match-type";
|
import type { MatchType } from "./match-type";
|
||||||
|
|
||||||
export const matchTagName =
|
export const matchTagName = (tagName: string) => <T>(element: Element, match: MatchType<T>): void => {
|
||||||
(tagName: string) =>
|
if (element.matches(tagName)) {
|
||||||
<T>(element: Element, match: MatchType<T>): void => {
|
match.remove();
|
||||||
if (element.matches(tagName)) {
|
}
|
||||||
match.remove();
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const easyBold = {
|
export const easyBold = {
|
||||||
surroundElement: document.createElement("b"),
|
surroundElement: document.createElement("b"),
|
||||||
|
@ -38,7 +36,7 @@ export function t(data: string): Text {
|
||||||
}
|
}
|
||||||
|
|
||||||
function element(tagName: string): (...childNodes: Node[]) => HTMLElement {
|
function element(tagName: string): (...childNodes: Node[]) => HTMLElement {
|
||||||
return function (...childNodes: Node[]): HTMLElement {
|
return function(...childNodes: Node[]): HTMLElement {
|
||||||
const element = document.createElement(tagName);
|
const element = document.createElement(tagName);
|
||||||
element.append(...childNodes);
|
element.append(...childNodes);
|
||||||
return element;
|
return element;
|
||||||
|
|
|
@ -24,9 +24,7 @@ interface WithTagName {
|
||||||
tagName: string;
|
tagName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DecoratedElementConstructor
|
export interface DecoratedElementConstructor extends CustomElementConstructor, WithTagName {
|
||||||
extends CustomElementConstructor,
|
|
||||||
WithTagName {
|
|
||||||
prototype: DecoratedElement;
|
prototype: DecoratedElement;
|
||||||
/**
|
/**
|
||||||
* Transforms elements in input HTML from undecorated to stored state.
|
* Transforms elements in input HTML from undecorated to stored state.
|
||||||
|
|
|
@ -9,7 +9,7 @@ export function clearableArray<T>(): (T & Destroyable)[] {
|
||||||
const list: (T & Destroyable)[] = [];
|
const list: (T & Destroyable)[] = [];
|
||||||
|
|
||||||
return new Proxy(list, {
|
return new Proxy(list, {
|
||||||
get: function (target: (T & Destroyable)[], prop: string | symbol) {
|
get: function(target: (T & Destroyable)[], prop: string | symbol) {
|
||||||
if (!(typeof prop === "symbol") && !isNaN(Number(prop)) && !target[prop]) {
|
if (!(typeof prop === "symbol") && !isNaN(Number(prop)) && !target[prop]) {
|
||||||
const item = {} as T & Destroyable;
|
const item = {} as T & Destroyable;
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ export function clearableArray<T>(): (T & Destroyable)[] {
|
||||||
};
|
};
|
||||||
|
|
||||||
target[prop] = new Proxy(item, {
|
target[prop] = new Proxy(item, {
|
||||||
get: function (target: T & Destroyable, prop: string | symbol) {
|
get: function(target: T & Destroyable, prop: string | symbol) {
|
||||||
if (prop === "destroy") {
|
if (prop === "destroy") {
|
||||||
return destroy;
|
return destroy;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
/// <reference types="../lib/image-import" />
|
/// <reference types="../lib/image-import" />
|
||||||
|
|
||||||
export { default as incrementClozeIcon } from "../icons/contain-plus.svg";
|
|
||||||
export { default as alertIcon } from "@mdi/svg/svg/alert.svg";
|
export { default as alertIcon } from "@mdi/svg/svg/alert.svg";
|
||||||
export { default as chevronDown } from "@mdi/svg/svg/chevron-down.svg";
|
export { default as chevronDown } from "@mdi/svg/svg/chevron-down.svg";
|
||||||
export { default as chevronUp } from "@mdi/svg/svg/chevron-up.svg";
|
export { default as chevronUp } from "@mdi/svg/svg/chevron-up.svg";
|
||||||
|
@ -11,3 +10,7 @@ export { default as plainTextIcon } from "@mdi/svg/svg/code-tags.svg";
|
||||||
export { default as clozeIcon } from "@mdi/svg/svg/contain.svg";
|
export { default as clozeIcon } from "@mdi/svg/svg/contain.svg";
|
||||||
export { default as richTextIcon } from "@mdi/svg/svg/format-font.svg";
|
export { default as richTextIcon } from "@mdi/svg/svg/format-font.svg";
|
||||||
export { default as stickyIcon } from "@mdi/svg/svg/pin-outline.svg";
|
export { default as stickyIcon } from "@mdi/svg/svg/pin-outline.svg";
|
||||||
|
|
||||||
|
// This comment prevents disagreement between eslint-plugin-simple-sort and
|
||||||
|
// dprint about whether .. or @ should come first.
|
||||||
|
export { default as incrementClozeIcon } from "../icons/contain-plus.svg";
|
||||||
|
|
|
@ -10,9 +10,11 @@ function normalizeFragment(fragment: DocumentFragment): void {
|
||||||
fragment.normalize();
|
fragment.normalize();
|
||||||
|
|
||||||
for (const decorated of decoratedElements) {
|
for (const decorated of decoratedElements) {
|
||||||
for (const element of fragment.querySelectorAll(
|
for (
|
||||||
decorated.tagName,
|
const element of fragment.querySelectorAll(
|
||||||
) as NodeListOf<DecoratedElement>) {
|
decorated.tagName,
|
||||||
|
) as NodeListOf<DecoratedElement>
|
||||||
|
) {
|
||||||
element.undecorate();
|
element.undecorate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import {
|
import { fragmentToString, nodeContainsInlineContent, nodeIsElement } from "../../lib/dom";
|
||||||
fragmentToString,
|
|
||||||
nodeContainsInlineContent,
|
|
||||||
nodeIsElement,
|
|
||||||
} from "../../lib/dom";
|
|
||||||
import { createDummyDoc } from "../../lib/parsing";
|
import { createDummyDoc } from "../../lib/parsing";
|
||||||
import { decoratedElements } from "../decorated-elements";
|
import { decoratedElements } from "../decorated-elements";
|
||||||
|
|
||||||
|
@ -35,10 +31,10 @@ export function storedToFragment(storedHTML: string): DocumentFragment {
|
||||||
|
|
||||||
function adjustOutputFragment(fragment: DocumentFragment): void {
|
function adjustOutputFragment(fragment: DocumentFragment): void {
|
||||||
if (
|
if (
|
||||||
fragment.hasChildNodes() &&
|
fragment.hasChildNodes()
|
||||||
nodeIsElement(fragment.lastChild!) &&
|
&& nodeIsElement(fragment.lastChild!)
|
||||||
nodeContainsInlineContent(fragment) &&
|
&& nodeContainsInlineContent(fragment)
|
||||||
fragment.lastChild!.tagName === "BR"
|
&& fragment.lastChild!.tagName === "BR"
|
||||||
) {
|
) {
|
||||||
fragment.lastChild!.remove();
|
fragment.lastChild!.remove();
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
sum,
|
sum,
|
||||||
} from "d3";
|
} from "d3";
|
||||||
|
|
||||||
import type { GraphBounds, GraphRange} from "./graph-helpers";
|
import type { GraphBounds, GraphRange } from "./graph-helpers";
|
||||||
import { millisecondCutoffForRange, setDataAvailable } from "./graph-helpers";
|
import { millisecondCutoffForRange, setDataAvailable } from "./graph-helpers";
|
||||||
import { hideTooltip, showTooltip } from "./tooltip";
|
import { hideTooltip, showTooltip } from "./tooltip";
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ import {
|
||||||
timeYear,
|
timeYear,
|
||||||
} from "d3";
|
} from "d3";
|
||||||
|
|
||||||
import type { GraphBounds, SearchDispatch} from "./graph-helpers";
|
import type { GraphBounds, SearchDispatch } from "./graph-helpers";
|
||||||
import { RevlogRange, setDataAvailable } from "./graph-helpers";
|
import { RevlogRange, setDataAvailable } from "./graph-helpers";
|
||||||
import { clickableClass } from "./graph-styles";
|
import { clickableClass } from "./graph-styles";
|
||||||
import { hideTooltip, showTooltip } from "./tooltip";
|
import { hideTooltip, showTooltip } from "./tooltip";
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { localizedNumber } from "@tslib/i18n";
|
||||||
import type { Bin, ScaleLinear, ScaleSequential } from "d3";
|
import type { Bin, ScaleLinear, ScaleSequential } from "d3";
|
||||||
import { area, axisBottom, axisLeft, axisRight, cumsum, curveBasis, max, pointer, scaleLinear, select } from "d3";
|
import { area, axisBottom, axisLeft, axisRight, cumsum, curveBasis, max, pointer, scaleLinear, select } from "d3";
|
||||||
|
|
||||||
import type { GraphBounds} from "./graph-helpers";
|
import type { GraphBounds } from "./graph-helpers";
|
||||||
import { setDataAvailable } from "./graph-helpers";
|
import { setDataAvailable } from "./graph-helpers";
|
||||||
import { clickableClass } from "./graph-styles";
|
import { clickableClass } from "./graph-styles";
|
||||||
import { hideTooltip, showTooltip } from "./tooltip";
|
import { hideTooltip, showTooltip } from "./tooltip";
|
||||||
|
|
|
@ -22,7 +22,7 @@ import {
|
||||||
select,
|
select,
|
||||||
} from "d3";
|
} from "d3";
|
||||||
|
|
||||||
import type { GraphBounds, GraphRange} from "./graph-helpers";
|
import type { GraphBounds, GraphRange } from "./graph-helpers";
|
||||||
import { millisecondCutoffForRange, setDataAvailable } from "./graph-helpers";
|
import { millisecondCutoffForRange, setDataAvailable } from "./graph-helpers";
|
||||||
import { oddTickClass } from "./graph-styles";
|
import { oddTickClass } from "./graph-styles";
|
||||||
import { hideTooltip, showTooltip } from "./tooltip";
|
import { hideTooltip, showTooltip } from "./tooltip";
|
||||||
|
|
|
@ -9,8 +9,7 @@ import * as tr from "@tslib/ftl";
|
||||||
import { localizedNumber } from "@tslib/i18n";
|
import { localizedNumber } from "@tslib/i18n";
|
||||||
import { Stats } from "@tslib/proto";
|
import { Stats } from "@tslib/proto";
|
||||||
import { dayLabel, timeSpan } from "@tslib/time";
|
import { dayLabel, timeSpan } from "@tslib/time";
|
||||||
import type { Bin ,
|
import type { Bin, ScaleSequential } from "d3";
|
||||||
ScaleSequential} from "d3";
|
|
||||||
import {
|
import {
|
||||||
area,
|
area,
|
||||||
axisBottom,
|
axisBottom,
|
||||||
|
@ -32,7 +31,7 @@ import {
|
||||||
sum,
|
sum,
|
||||||
} from "d3";
|
} from "d3";
|
||||||
|
|
||||||
import type { GraphBounds,TableDatum } from "./graph-helpers";
|
import type { GraphBounds, TableDatum } from "./graph-helpers";
|
||||||
import { GraphRange, setDataAvailable } from "./graph-helpers";
|
import { GraphRange, setDataAvailable } from "./graph-helpers";
|
||||||
import { hideTooltip, showTooltip } from "./tooltip";
|
import { hideTooltip, showTooltip } from "./tooltip";
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import type { DebouncedFunc} from "lodash-es";
|
import type { DebouncedFunc } from "lodash-es";
|
||||||
import { throttle } from "lodash-es";
|
import { throttle } from "lodash-es";
|
||||||
|
|
||||||
import Tooltip from "./Tooltip.svelte";
|
import Tooltip from "./Tooltip.svelte";
|
||||||
|
@ -26,8 +26,7 @@ function showTooltipInner(msg: string, x: number, y: number): void {
|
||||||
tooltip.$set({ html: msg, x, y, show: true });
|
tooltip.$set({ html: msg, x, y, show: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
export const showTooltip: DebouncedFunc<(msg: string, x: number, y: number) => void> =
|
export const showTooltip: DebouncedFunc<(msg: string, x: number, y: number) => void> = throttle(showTooltipInner, 16);
|
||||||
throttle(showTooltipInner, 16);
|
|
||||||
|
|
||||||
export function hideTooltip(): void {
|
export function hideTooltip(): void {
|
||||||
const tooltip = getOrCreateTooltip();
|
const tooltip = getOrCreateTooltip();
|
||||||
|
|
|
@ -3,11 +3,7 @@
|
||||||
|
|
||||||
import { isHTMLElement, isNightMode } from "./helpers";
|
import { isHTMLElement, isNightMode } from "./helpers";
|
||||||
import { removeNode as removeElement } from "./node";
|
import { removeNode as removeElement } from "./node";
|
||||||
import {
|
import { filterStylingInternal, filterStylingLightMode, filterStylingNightMode } from "./styling";
|
||||||
filterStylingInternal,
|
|
||||||
filterStylingLightMode,
|
|
||||||
filterStylingNightMode,
|
|
||||||
} from "./styling";
|
|
||||||
|
|
||||||
interface TagsAllowed {
|
interface TagsAllowed {
|
||||||
[tagName: string]: FilterMethod;
|
[tagName: string]: FilterMethod;
|
||||||
|
@ -32,13 +28,11 @@ function allowNone(element: Element): void {
|
||||||
filterAttributes(() => false, element);
|
filterAttributes(() => false, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
const allow =
|
const allow = (attrs: string[]): FilterMethod => (element: Element): void =>
|
||||||
(attrs: string[]): FilterMethod =>
|
filterAttributes(
|
||||||
(element: Element): void =>
|
(attributeName: string) => attrs.includes(attributeName),
|
||||||
filterAttributes(
|
element,
|
||||||
(attributeName: string) => attrs.includes(attributeName),
|
);
|
||||||
element,
|
|
||||||
);
|
|
||||||
|
|
||||||
function unwrapElement(element: Element): void {
|
function unwrapElement(element: Element): void {
|
||||||
element.replaceWith(...element.childNodes);
|
element.replaceWith(...element.childNodes);
|
||||||
|
@ -93,19 +87,17 @@ const tagsAllowedExtended: TagsAllowed = {
|
||||||
UL: allowNone,
|
UL: allowNone,
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterElementTagsAllowed =
|
const filterElementTagsAllowed = (tagsAllowed: TagsAllowed) => (element: Element): void => {
|
||||||
(tagsAllowed: TagsAllowed) =>
|
const tagName = element.tagName;
|
||||||
(element: Element): void => {
|
|
||||||
const tagName = element.tagName;
|
|
||||||
|
|
||||||
if (Object.prototype.hasOwnProperty.call(tagsAllowed, tagName)) {
|
if (Object.prototype.hasOwnProperty.call(tagsAllowed, tagName)) {
|
||||||
tagsAllowed[tagName](element);
|
tagsAllowed[tagName](element);
|
||||||
} else if (element.innerHTML) {
|
} else if (element.innerHTML) {
|
||||||
unwrapElement(element);
|
unwrapElement(element);
|
||||||
} else {
|
} else {
|
||||||
removeElement(element);
|
removeElement(element);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const filterElementBasic = filterElementTagsAllowed(tagsAllowedBasic);
|
export const filterElementBasic = filterElementTagsAllowed(tagsAllowedBasic);
|
||||||
export const filterElementExtended = filterElementTagsAllowed(tagsAllowedExtended);
|
export const filterElementExtended = filterElementTagsAllowed(tagsAllowedExtended);
|
||||||
|
|
|
@ -13,35 +13,35 @@ describe("filterHTML", () => {
|
||||||
// font-size is filtered, weight is not
|
// font-size is filtered, weight is not
|
||||||
expect(
|
expect(
|
||||||
filterHTML(
|
filterHTML(
|
||||||
'<div style="font-weight: bold; font-size: 10px;"></div>',
|
"<div style=\"font-weight: bold; font-size: 10px;\"></div>",
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
).toBe('<div style="font-weight: bold;"></div>');
|
).toBe("<div style=\"font-weight: bold;\"></div>");
|
||||||
});
|
});
|
||||||
test("background color", () => {
|
test("background color", () => {
|
||||||
// transparent is stripped, other colors are not
|
// transparent is stripped, other colors are not
|
||||||
expect(
|
expect(
|
||||||
filterHTML(
|
filterHTML(
|
||||||
'<span style="background-color: transparent;"></span>',
|
"<span style=\"background-color: transparent;\"></span>",
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
).toBe('<span style=""></span>');
|
).toBe("<span style=\"\"></span>");
|
||||||
expect(
|
expect(
|
||||||
filterHTML('<span style="background-color: blue;"></span>', false, true),
|
filterHTML("<span style=\"background-color: blue;\"></span>", false, true),
|
||||||
).toBe('<span style="background-color: blue;"></span>');
|
).toBe("<span style=\"background-color: blue;\"></span>");
|
||||||
// except if extended mode is off
|
// except if extended mode is off
|
||||||
expect(
|
expect(
|
||||||
filterHTML('<span style="background-color: blue;">x</span>', false, false),
|
filterHTML("<span style=\"background-color: blue;\">x</span>", false, false),
|
||||||
).toBe("x");
|
).toBe("x");
|
||||||
// no filtering on internal paste
|
// no filtering on internal paste
|
||||||
expect(
|
expect(
|
||||||
filterHTML(
|
filterHTML(
|
||||||
'<span style="background-color: transparent;"></span>',
|
"<span style=\"background-color: transparent;\"></span>",
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
).toBe('<span style="background-color: transparent;"></span>');
|
).toBe("<span style=\"background-color: transparent;\"></span>");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import {
|
import { filterElementBasic, filterElementExtended, filterElementInternal } from "./element";
|
||||||
filterElementBasic,
|
|
||||||
filterElementExtended,
|
|
||||||
filterElementInternal,
|
|
||||||
} from "./element";
|
|
||||||
import { filterNode } from "./node";
|
import { filterNode } from "./node";
|
||||||
|
|
||||||
enum FilterMode {
|
enum FilterMode {
|
||||||
|
@ -31,8 +27,7 @@ function trim(value: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const outputHTMLProcessors: Record<FilterMode, (outputHTML: string) => string> = {
|
const outputHTMLProcessors: Record<FilterMode, (outputHTML: string) => string> = {
|
||||||
[FilterMode.Basic]: (outputHTML: string): string =>
|
[FilterMode.Basic]: (outputHTML: string): string => trim(collapseWhitespace(outputHTML)),
|
||||||
trim(collapseWhitespace(outputHTML)),
|
|
||||||
[FilterMode.Extended]: trim,
|
[FilterMode.Extended]: trim,
|
||||||
[FilterMode.Internal]: trim,
|
[FilterMode.Internal]: trim,
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,24 +14,22 @@ function iterateElement(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const filterNode =
|
export const filterNode = (elementFilter: (element: Element) => void) => (node: Node): void => {
|
||||||
(elementFilter: (element: Element) => void) =>
|
switch (node.nodeType) {
|
||||||
(node: Node): void => {
|
case Node.COMMENT_NODE:
|
||||||
switch (node.nodeType) {
|
removeNode(node);
|
||||||
case Node.COMMENT_NODE:
|
break;
|
||||||
removeNode(node);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Node.DOCUMENT_FRAGMENT_NODE:
|
case Node.DOCUMENT_FRAGMENT_NODE:
|
||||||
iterateElement(filterNode(elementFilter), node as DocumentFragment);
|
iterateElement(filterNode(elementFilter), node as DocumentFragment);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Node.ELEMENT_NODE:
|
case Node.ELEMENT_NODE:
|
||||||
iterateElement(filterNode(elementFilter), node as Element);
|
iterateElement(filterNode(elementFilter), node as Element);
|
||||||
elementFilter(node as Element);
|
elementFilter(node as Element);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -99,8 +99,8 @@ export function elementIsEmpty(element: Element): boolean {
|
||||||
export function nodeContainsInlineContent(node: Node): boolean {
|
export function nodeContainsInlineContent(node: Node): boolean {
|
||||||
for (const child of node.childNodes) {
|
for (const child of node.childNodes) {
|
||||||
if (
|
if (
|
||||||
(nodeIsElement(child) && elementIsBlock(child)) ||
|
(nodeIsElement(child) && elementIsBlock(child))
|
||||||
!nodeContainsInlineContent(child)
|
|| !nodeContainsInlineContent(child)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,7 @@ export function fragmentToString(fragment: DocumentFragment): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAnchorParent =
|
const getAnchorParent =
|
||||||
<T extends Element>(predicate: (element: Element) => element is T) =>
|
<T extends Element>(predicate: (element: Element) => element is T) => (root: Node): T | null => {
|
||||||
(root: Node): T | null => {
|
|
||||||
const anchor = getSelection(root)?.anchorNode;
|
const anchor = getSelection(root)?.anchorNode;
|
||||||
|
|
||||||
if (!anchor) {
|
if (!anchor) {
|
||||||
|
@ -143,12 +142,10 @@ const getAnchorParent =
|
||||||
|
|
||||||
const isListItem = (element: Element): element is HTMLLIElement =>
|
const isListItem = (element: Element): element is HTMLLIElement =>
|
||||||
window.getComputedStyle(element).display === "list-item";
|
window.getComputedStyle(element).display === "list-item";
|
||||||
const isParagraph = (element: Element): element is HTMLParamElement =>
|
const isParagraph = (element: Element): element is HTMLParamElement => element.tagName === "P";
|
||||||
element.tagName === "P";
|
|
||||||
const isBlockElement = (
|
const isBlockElement = (
|
||||||
element: Element,
|
element: Element,
|
||||||
): element is HTMLLIElement & HTMLParamElement =>
|
): element is HTMLLIElement & HTMLParamElement => isListItem(element) || isParagraph(element);
|
||||||
isListItem(element) || isParagraph(element);
|
|
||||||
|
|
||||||
export const getListItem = getAnchorParent(isListItem);
|
export const getListItem = getAnchorParent(isListItem);
|
||||||
export const getParagraph = getAnchorParent(isParagraph);
|
export const getParagraph = getAnchorParent(isParagraph);
|
||||||
|
|
|
@ -1,24 +1,15 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
export type EventTargetToMap<A extends EventTarget> = A extends HTMLElement
|
export type EventTargetToMap<A extends EventTarget> = A extends HTMLElement ? HTMLElementEventMap
|
||||||
? HTMLElementEventMap
|
: A extends Document ? DocumentEventMap
|
||||||
: A extends Document
|
: A extends Window ? WindowEventMap
|
||||||
? DocumentEventMap
|
: A extends FileReader ? FileReaderEventMap
|
||||||
: A extends Window
|
: A extends Element ? ElementEventMap
|
||||||
? WindowEventMap
|
: A extends Animation ? AnimationEventMap
|
||||||
: A extends FileReader
|
: A extends EventSource ? EventSourceEventMap
|
||||||
? FileReaderEventMap
|
: A extends AbortSignal ? AbortSignalEventMap
|
||||||
: A extends Element
|
: A extends AbstractWorker ? AbstractWorkerEventMap
|
||||||
? ElementEventMap
|
|
||||||
: A extends Animation
|
|
||||||
? AnimationEventMap
|
|
||||||
: A extends EventSource
|
|
||||||
? EventSourceEventMap
|
|
||||||
: A extends AbortSignal
|
|
||||||
? AbortSignalEventMap
|
|
||||||
: A extends AbstractWorker
|
|
||||||
? AbstractWorkerEventMap
|
|
||||||
: never;
|
: never;
|
||||||
|
|
||||||
export function on<T extends EventTarget, K extends keyof EventTargetToMap<T>>(
|
export function on<T extends EventTarget, K extends keyof EventTargetToMap<T>>(
|
||||||
|
@ -28,8 +19,7 @@ export function on<T extends EventTarget, K extends keyof EventTargetToMap<T>>(
|
||||||
options?: AddEventListenerOptions,
|
options?: AddEventListenerOptions,
|
||||||
): () => void {
|
): () => void {
|
||||||
target.addEventListener(eventType, handler as EventListener, options);
|
target.addEventListener(eventType, handler as EventListener, options);
|
||||||
return () =>
|
return () => target.removeEventListener(eventType, handler as EventListener, options);
|
||||||
target.removeEventListener(eventType, handler as EventListener, options);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function preventDefault(event: Event): void {
|
export function preventDefault(event: Event): void {
|
||||||
|
|
|
@ -12,18 +12,18 @@ import type { ModuleName } from "./modules";
|
||||||
export function supportsVerticalText(): boolean {
|
export function supportsVerticalText(): boolean {
|
||||||
const firstLang = firstLanguage();
|
const firstLang = firstLanguage();
|
||||||
return (
|
return (
|
||||||
firstLang.startsWith("ja") ||
|
firstLang.startsWith("ja")
|
||||||
firstLang.startsWith("zh") ||
|
|| firstLang.startsWith("zh")
|
||||||
firstLang.startsWith("ko")
|
|| firstLang.startsWith("ko")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function direction(): string {
|
export function direction(): string {
|
||||||
const firstLang = firstLanguage();
|
const firstLang = firstLanguage();
|
||||||
if (
|
if (
|
||||||
firstLang.startsWith("ar") ||
|
firstLang.startsWith("ar")
|
||||||
firstLang.startsWith("he") ||
|
|| firstLang.startsWith("he")
|
||||||
firstLang.startsWith("fa")
|
|| firstLang.startsWith("fa")
|
||||||
) {
|
) {
|
||||||
return "rtl";
|
return "rtl";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
export function isApplePlatform(): boolean {
|
export function isApplePlatform(): boolean {
|
||||||
// avoid deprecation warning
|
// avoid deprecation warning
|
||||||
const platform = window.navigator["platform" + ""]
|
const platform = window.navigator["platform" + ""];
|
||||||
return (
|
return (
|
||||||
platform.startsWith("Mac") ||
|
platform.startsWith("Mac")
|
||||||
platform.startsWith("iP")
|
|| platform.startsWith("iP")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,17 +52,17 @@ export function registerPackage<
|
||||||
>(name: T, entries: U, deprecation?: PackageDeprecation<U>): void {
|
>(name: T, entries: U, deprecation?: PackageDeprecation<U>): void {
|
||||||
const pack = deprecation
|
const pack = deprecation
|
||||||
? new Proxy(entries, {
|
? new Proxy(entries, {
|
||||||
set: prohibit,
|
set: prohibit,
|
||||||
defineProperty: prohibit,
|
defineProperty: prohibit,
|
||||||
deleteProperty: prohibit,
|
deleteProperty: prohibit,
|
||||||
get: (target, name: string) => {
|
get: (target, name: string) => {
|
||||||
if (name in deprecation) {
|
if (name in deprecation) {
|
||||||
console.log(`anki: ${name} is deprecated: ${deprecation[name]}`);
|
console.log(`anki: ${name} is deprecated: ${deprecation[name]}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return target[name];
|
return target[name];
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: entries;
|
: entries;
|
||||||
|
|
||||||
registerPackageRaw(name, pack);
|
registerPackageRaw(name, pack);
|
||||||
|
|
|
@ -3,12 +3,7 @@
|
||||||
|
|
||||||
import { on } from "./events";
|
import { on } from "./events";
|
||||||
import type { Modifier } from "./keys";
|
import type { Modifier } from "./keys";
|
||||||
import {
|
import { checkIfModifierKey, checkModifiers, keyToPlatformString, modifiersToPlatformString } from "./keys";
|
||||||
checkIfModifierKey,
|
|
||||||
checkModifiers,
|
|
||||||
keyToPlatformString,
|
|
||||||
modifiersToPlatformString,
|
|
||||||
} from "./keys";
|
|
||||||
import { registerPackage } from "./runtime-require";
|
import { registerPackage } from "./runtime-require";
|
||||||
|
|
||||||
const keyCodeLookup = {
|
const keyCodeLookup = {
|
||||||
|
@ -65,7 +60,7 @@ export function getPlatformString(keyCombinationString: string): string {
|
||||||
|
|
||||||
function checkKey(event: KeyboardEvent, key: number): boolean {
|
function checkKey(event: KeyboardEvent, key: number): boolean {
|
||||||
// avoid deprecation warning
|
// avoid deprecation warning
|
||||||
const which = event["which" + ""]
|
const which = event["which" + ""];
|
||||||
return which === key;
|
return which === key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,8 +96,8 @@ const check =
|
||||||
(keyCode: number, requiredModifiers: Modifier[], optionalModifiers: Modifier[]) =>
|
(keyCode: number, requiredModifiers: Modifier[], optionalModifiers: Modifier[]) =>
|
||||||
(event: KeyboardEvent): boolean => {
|
(event: KeyboardEvent): boolean => {
|
||||||
return (
|
return (
|
||||||
checkKey(event, keyCode) &&
|
checkKey(event, keyCode)
|
||||||
checkModifiers(requiredModifiers, optionalModifiers)(event)
|
&& checkModifiers(requiredModifiers, optionalModifiers)(event)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -166,8 +161,7 @@ export function registerShortcut(
|
||||||
event = defaultRegisterShortcutRestParams.event,
|
event = defaultRegisterShortcutRestParams.event,
|
||||||
} = restParams;
|
} = restParams;
|
||||||
|
|
||||||
const [check, ...restChecks] =
|
const [check, ...restChecks] = splitKeyCombinationString(keyCombinationString).map(keyCombinationToCheck);
|
||||||
splitKeyCombinationString(keyCombinationString).map(keyCombinationToCheck);
|
|
||||||
|
|
||||||
function handler(event: KeyboardEvent): void {
|
function handler(event: KeyboardEvent): void {
|
||||||
if (check(event)) {
|
if (check(event)) {
|
||||||
|
|
|
@ -9,9 +9,8 @@ export function randomUUID(): string {
|
||||||
|
|
||||||
return value.replace(/[018]/g, (character: string): string =>
|
return value.replace(/[018]/g, (character: string): string =>
|
||||||
(
|
(
|
||||||
Number(character) ^
|
Number(character)
|
||||||
(crypto.getRandomValues(new Uint8Array(1))[0] &
|
^ (crypto.getRandomValues(new Uint8Array(1))[0]
|
||||||
(15 >> (Number(character) / 4)))
|
& (15 >> (Number(character) / 4)))
|
||||||
).toString(16),
|
).toString(16));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ export function wrapInternal(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
wasCollapsed &&
|
wasCollapsed
|
||||||
/* ugly solution: treat <anki-mathjax> differently than other wraps */ !front.includes(
|
/* ugly solution: treat <anki-mathjax> differently than other wraps */ && !front.includes(
|
||||||
"<anki-mathjax",
|
"<anki-mathjax",
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -19,18 +19,16 @@ export async function maybePreloadExternalCss(html: string): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPreloadedCss(): void {
|
function clearPreloadedCss(): void {
|
||||||
[...document.head.getElementsByClassName(preloadCssClassName)].forEach((css) =>
|
[...document.head.getElementsByClassName(preloadCssClassName)].forEach((css) => css.remove());
|
||||||
css.remove(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractExternalCssElements(fragment: DocumentFragment): CssElementType[] {
|
function extractExternalCssElements(fragment: DocumentFragment): CssElementType[] {
|
||||||
return <CssElementType[]>(
|
return <CssElementType[]> (
|
||||||
[...fragment.querySelectorAll("style, link")].filter(
|
[...fragment.querySelectorAll("style, link")].filter(
|
||||||
(css) =>
|
(css) =>
|
||||||
(css instanceof HTMLStyleElement &&
|
(css instanceof HTMLStyleElement
|
||||||
css.innerHTML.includes("@import")) ||
|
&& css.innerHTML.includes("@import"))
|
||||||
(css instanceof HTMLLinkElement && css.rel === "stylesheet"),
|
|| (css instanceof HTMLLinkElement && css.rel === "stylesheet"),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@ function imageLoaded(img: HTMLImageElement): Promise<void> {
|
||||||
return img.complete
|
return img.complete
|
||||||
? Promise.resolve()
|
? Promise.resolve()
|
||||||
: new Promise((resolve) => {
|
: new Promise((resolve) => {
|
||||||
img.addEventListener("load", () => resolve());
|
img.addEventListener("load", () => resolve());
|
||||||
img.addEventListener("error", () => resolve());
|
img.addEventListener("error", () => resolve());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPreloadLinks(): void {
|
function clearPreloadLinks(): void {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import type { Readable} from "svelte/store";
|
import type { Readable } from "svelte/store";
|
||||||
import { readable } from "svelte/store";
|
import { readable } from "svelte/store";
|
||||||
|
|
||||||
interface AsyncData<T, E> {
|
interface AsyncData<T, E> {
|
||||||
|
|
|
@ -31,7 +31,7 @@ function useAsyncReactive<T, E>(
|
||||||
|
|
||||||
const error = derived(
|
const error = derived(
|
||||||
promise,
|
promise,
|
||||||
($promise, set: (error: E | null) => void): (() => void) => {
|
($promise, set: (error: E | null) => void): () => void => {
|
||||||
$promise?.catch((error: E) => set(error));
|
$promise?.catch((error: E) => set(error));
|
||||||
return (): void => set(null);
|
return (): void => set(null);
|
||||||
},
|
},
|
||||||
|
@ -40,7 +40,7 @@ function useAsyncReactive<T, E>(
|
||||||
|
|
||||||
const loading = derived(
|
const loading = derived(
|
||||||
promise,
|
promise,
|
||||||
($promise, set: (value: boolean) => void): (() => void) => {
|
($promise, set: (value: boolean) => void): () => void => {
|
||||||
$promise?.finally(() => set(false));
|
$promise?.finally(() => set(false));
|
||||||
return (): void => set(true);
|
return (): void => set(true);
|
||||||
},
|
},
|
||||||
|
|
|
@ -9,13 +9,12 @@ export interface DynamicSvelteComponent<
|
||||||
[k: string]: unknown;
|
[k: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dynamicComponent =
|
export const dynamicComponent = <
|
||||||
<
|
Comp extends typeof SvelteComponentDev,
|
||||||
Comp extends typeof SvelteComponentDev,
|
DefaultProps = NonNullable<ConstructorParameters<Comp>[0]["props"]>,
|
||||||
DefaultProps = NonNullable<ConstructorParameters<Comp>[0]["props"]>,
|
>(
|
||||||
>(
|
component: Comp,
|
||||||
component: Comp,
|
) =>
|
||||||
) =>
|
<Props = DefaultProps>(props: Props): DynamicSvelteComponent<Comp> & Props => {
|
||||||
<Props = DefaultProps>(props: Props): DynamicSvelteComponent<Comp> & Props => {
|
return { component, ...props };
|
||||||
return { component, ...props };
|
};
|
||||||
};
|
|
||||||
|
|
|
@ -1,22 +1,8 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import type {
|
import type { ComputePositionConfig, FloatingElement, Middleware, Placement, ReferenceElement } from "@floating-ui/dom";
|
||||||
ComputePositionConfig,
|
import { arrow, computePosition, flip, hide, inline, offset, shift } from "@floating-ui/dom";
|
||||||
FloatingElement,
|
|
||||||
Middleware,
|
|
||||||
Placement,
|
|
||||||
ReferenceElement,
|
|
||||||
} from "@floating-ui/dom";
|
|
||||||
import {
|
|
||||||
arrow,
|
|
||||||
computePosition,
|
|
||||||
flip,
|
|
||||||
hide,
|
|
||||||
inline,
|
|
||||||
offset,
|
|
||||||
shift,
|
|
||||||
} from "@floating-ui/dom";
|
|
||||||
|
|
||||||
import type { PositionAlgorithm } from "./position-algorithm";
|
import type { PositionAlgorithm } from "./position-algorithm";
|
||||||
|
|
||||||
|
@ -41,7 +27,7 @@ function positionFloating({
|
||||||
hideIfReferenceHidden,
|
hideIfReferenceHidden,
|
||||||
hideCallback,
|
hideCallback,
|
||||||
}: PositionFloatingArgs): PositionAlgorithm {
|
}: PositionFloatingArgs): PositionAlgorithm {
|
||||||
return async function (
|
return async function(
|
||||||
reference: ReferenceElement,
|
reference: ReferenceElement,
|
||||||
floating: FloatingElement,
|
floating: FloatingElement,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import type {
|
import type { ComputePositionConfig, FloatingElement, Middleware, ReferenceElement } from "@floating-ui/dom";
|
||||||
ComputePositionConfig,
|
|
||||||
FloatingElement,
|
|
||||||
Middleware,
|
|
||||||
ReferenceElement,
|
|
||||||
} from "@floating-ui/dom";
|
|
||||||
import { computePosition, inline, offset } from "@floating-ui/dom";
|
import { computePosition, inline, offset } from "@floating-ui/dom";
|
||||||
|
|
||||||
import type { PositionAlgorithm } from "./position-algorithm";
|
import type { PositionAlgorithm } from "./position-algorithm";
|
||||||
|
@ -22,7 +17,7 @@ function positionOverlay({
|
||||||
inline: inlineArg,
|
inline: inlineArg,
|
||||||
hideCallback,
|
hideCallback,
|
||||||
}: PositionOverlayArgs): PositionAlgorithm {
|
}: PositionOverlayArgs): PositionAlgorithm {
|
||||||
return async function (
|
return async function(
|
||||||
reference: ReferenceElement,
|
reference: ReferenceElement,
|
||||||
floating: FloatingElement,
|
floating: FloatingElement,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright: Ankitects Pty Ltd and contributors
|
// 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
|
||||||
|
|
||||||
import type { Writable} from "svelte/store";
|
import type { Writable } from "svelte/store";
|
||||||
import { get, writable } from "svelte/store";
|
import { get, writable } from "svelte/store";
|
||||||
|
|
||||||
export interface CustomStore<T> extends Writable<T> {
|
export interface CustomStore<T> extends Writable<T> {
|
||||||
|
@ -61,9 +61,11 @@ function preparePreferences<T>(
|
||||||
setter(constructPreferences());
|
setter(constructPreferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(
|
for (
|
||||||
toObject(Preferences, { defaults: true }),
|
const [key, value] of Object.entries(
|
||||||
)) {
|
toObject(Preferences, { defaults: true }),
|
||||||
|
)
|
||||||
|
) {
|
||||||
preferences[key] = createPreference(value, savePreferences);
|
preferences[key] = createPreference(value, savePreferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue