Use trailingComma: all setting in .prettierrc (#1435)
This commit is contained in:
parent
bf3adbc812
commit
0dff5ea3a3
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"trailingComma": "es5",
|
"trailingComma": "all",
|
||||||
"printWidth": 88,
|
"printWidth": 88,
|
||||||
"tabWidth": 4,
|
"tabWidth": 4,
|
||||||
"semi": true
|
"semi": true,
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,6 @@ import { postRequest } from "../lib/postrequest";
|
|||||||
|
|
||||||
export async function getCardStats(cardId: number): Promise<Stats.CardStatsResponse> {
|
export async function getCardStats(cardId: number): Promise<Stats.CardStatsResponse> {
|
||||||
return Stats.CardStatsResponse.decode(
|
return Stats.CardStatsResponse.decode(
|
||||||
await postRequest("/_anki/cardStats", JSON.stringify({ cardId }))
|
await postRequest("/_anki/cardStats", JSON.stringify({ cardId })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
async function blur(event: Event): Promise<void> {
|
async function blur(event: Event): Promise<void> {
|
||||||
await state.setTargetNotetypeIndex(
|
await state.setTargetNotetypeIndex(
|
||||||
parseInt((event.target! as HTMLSelectElement).value)
|
parseInt((event.target! as HTMLSelectElement).value),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -14,7 +14,7 @@ import { nightModeKey } from "../components/context-keys";
|
|||||||
export async function changeNotetypePage(
|
export async function changeNotetypePage(
|
||||||
target: HTMLDivElement,
|
target: HTMLDivElement,
|
||||||
oldNotetypeId: number,
|
oldNotetypeId: number,
|
||||||
newNotetypeId: number
|
newNotetypeId: number,
|
||||||
): Promise<ChangeNotetypePage> {
|
): Promise<ChangeNotetypePage> {
|
||||||
const [info, names] = await Promise.all([
|
const [info, names] = await Promise.all([
|
||||||
getChangeNotetypeInfo(oldNotetypeId, newNotetypeId),
|
getChangeNotetypeInfo(oldNotetypeId, newNotetypeId),
|
||||||
|
@ -65,14 +65,14 @@ const exampleInfoSame = {
|
|||||||
function differentState(): ChangeNotetypeState {
|
function differentState(): ChangeNotetypeState {
|
||||||
return new ChangeNotetypeState(
|
return new ChangeNotetypeState(
|
||||||
Notetypes.NotetypeNames.fromObject(exampleNames),
|
Notetypes.NotetypeNames.fromObject(exampleNames),
|
||||||
Notetypes.ChangeNotetypeInfo.fromObject(exampleInfoDifferent)
|
Notetypes.ChangeNotetypeInfo.fromObject(exampleInfoDifferent),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sameState(): ChangeNotetypeState {
|
function sameState(): ChangeNotetypeState {
|
||||||
return new ChangeNotetypeState(
|
return new ChangeNotetypeState(
|
||||||
Notetypes.NotetypeNames.fromObject(exampleNames),
|
Notetypes.NotetypeNames.fromObject(exampleNames),
|
||||||
Notetypes.ChangeNotetypeInfo.fromObject(exampleInfoSame)
|
Notetypes.ChangeNotetypeInfo.fromObject(exampleInfoSame),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +92,7 @@ test("mapping", () => {
|
|||||||
expect(get(state.info).getNewName(MapContext.Field, 1)).toBe("Back");
|
expect(get(state.info).getNewName(MapContext.Field, 1)).toBe("Back");
|
||||||
expect(get(state.info).getNewName(MapContext.Field, 2)).toBe("Add Reverse");
|
expect(get(state.info).getNewName(MapContext.Field, 2)).toBe("Add Reverse");
|
||||||
expect(get(state.info).getOldNamesIncludingNothing(MapContext.Field)).toStrictEqual(
|
expect(get(state.info).getOldNamesIncludingNothing(MapContext.Field)).toStrictEqual(
|
||||||
["Front", "Back", "(Nothing)"]
|
["Front", "Back", "(Nothing)"],
|
||||||
);
|
);
|
||||||
expect(get(state.info).getOldIndex(MapContext.Field, 0)).toBe(0);
|
expect(get(state.info).getOldIndex(MapContext.Field, 0)).toBe(0);
|
||||||
expect(get(state.info).getOldIndex(MapContext.Field, 1)).toBe(1);
|
expect(get(state.info).getOldIndex(MapContext.Field, 1)).toBe(1);
|
||||||
@ -102,7 +102,7 @@ test("mapping", () => {
|
|||||||
|
|
||||||
// the same template shouldn't be mappable twice
|
// the same template shouldn't be mappable twice
|
||||||
expect(
|
expect(
|
||||||
get(state.info).getOldNamesIncludingNothing(MapContext.Template)
|
get(state.info).getOldNamesIncludingNothing(MapContext.Template),
|
||||||
).toStrictEqual(["Card 1", "(Nothing)"]);
|
).toStrictEqual(["Card 1", "(Nothing)"]);
|
||||||
expect(get(state.info).getOldIndex(MapContext.Template, 0)).toBe(0);
|
expect(get(state.info).getOldIndex(MapContext.Template, 0)).toBe(0);
|
||||||
expect(get(state.info).getOldIndex(MapContext.Template, 1)).toBe(1);
|
expect(get(state.info).getOldIndex(MapContext.Template, 1)).toBe(1);
|
||||||
|
@ -12,24 +12,24 @@ import { isEqual } from "lodash-es";
|
|||||||
|
|
||||||
export async function getNotetypeNames(): Promise<Notetypes.NotetypeNames> {
|
export async function getNotetypeNames(): Promise<Notetypes.NotetypeNames> {
|
||||||
return Notetypes.NotetypeNames.decode(
|
return Notetypes.NotetypeNames.decode(
|
||||||
await postRequest("/_anki/notetypeNames", "")
|
await postRequest("/_anki/notetypeNames", ""),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getChangeNotetypeInfo(
|
export async function getChangeNotetypeInfo(
|
||||||
oldNotetypeId: number,
|
oldNotetypeId: number,
|
||||||
newNotetypeId: number
|
newNotetypeId: number,
|
||||||
): Promise<Notetypes.ChangeNotetypeInfo> {
|
): Promise<Notetypes.ChangeNotetypeInfo> {
|
||||||
return Notetypes.ChangeNotetypeInfo.decode(
|
return Notetypes.ChangeNotetypeInfo.decode(
|
||||||
await postRequest(
|
await postRequest(
|
||||||
"/_anki/changeNotetypeInfo",
|
"/_anki/changeNotetypeInfo",
|
||||||
JSON.stringify({ oldNotetypeId, newNotetypeId })
|
JSON.stringify({ oldNotetypeId, newNotetypeId }),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function changeNotetype(
|
export async function changeNotetype(
|
||||||
input: Notetypes.ChangeNotetypeRequest
|
input: Notetypes.ChangeNotetypeRequest,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const data: Uint8Array = Notetypes.ChangeNotetypeRequest.encode(input).finish();
|
const data: Uint8Array = Notetypes.ChangeNotetypeRequest.encode(input).finish();
|
||||||
await postRequest("/_anki/changeNotetype", data);
|
await postRequest("/_anki/changeNotetype", data);
|
||||||
@ -98,7 +98,7 @@ export class ChangeNotetypeInfoWrapper {
|
|||||||
const usedEntries = new Set(this.mapForContext(ctx).filter((v) => v !== null));
|
const usedEntries = new Set(this.mapForContext(ctx).filter((v) => v !== null));
|
||||||
const oldNames = this.getOldNames(ctx);
|
const oldNames = this.getOldNames(ctx);
|
||||||
const unusedIdxs = [...Array(oldNames.length).keys()].filter(
|
const unusedIdxs = [...Array(oldNames.length).keys()].filter(
|
||||||
(idx) => !usedEntries.has(idx)
|
(idx) => !usedEntries.has(idx),
|
||||||
);
|
);
|
||||||
const unusedNames = unusedIdxs.map((idx) => oldNames[idx]);
|
const unusedNames = unusedIdxs.map((idx) => oldNames[idx]);
|
||||||
unusedNames.sort();
|
unusedNames.sort();
|
||||||
@ -150,7 +150,7 @@ export class ChangeNotetypeState {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
notetypes: Notetypes.NotetypeNames,
|
notetypes: Notetypes.NotetypeNames,
|
||||||
info: Notetypes.ChangeNotetypeInfo
|
info: Notetypes.ChangeNotetypeInfo,
|
||||||
) {
|
) {
|
||||||
this.info_ = new ChangeNotetypeInfoWrapper(info);
|
this.info_ = new ChangeNotetypeInfoWrapper(info);
|
||||||
this.info = readable(this.info_, (set) => {
|
this.info = readable(this.info_, (set) => {
|
||||||
@ -168,7 +168,7 @@ export class ChangeNotetypeState {
|
|||||||
this.notetypesSetter(this.buildNotetypeList());
|
this.notetypesSetter(this.buildNotetypeList());
|
||||||
const newInfo = await getChangeNotetypeInfo(
|
const newInfo = await getChangeNotetypeInfo(
|
||||||
this.info_.input().oldNotetypeId,
|
this.info_.input().oldNotetypeId,
|
||||||
this.info_.input().newNotetypeId
|
this.info_.input().newNotetypeId,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.info_ = new ChangeNotetypeInfoWrapper(newInfo);
|
this.info_ = new ChangeNotetypeInfoWrapper(newInfo);
|
||||||
@ -215,7 +215,7 @@ export class ChangeNotetypeState {
|
|||||||
idx,
|
idx,
|
||||||
name: entry.name,
|
name: entry.name,
|
||||||
current: entry.id === currentId,
|
current: entry.id === currentId,
|
||||||
} as NotetypeListEntry)
|
} as NotetypeListEntry),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,11 +66,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
const insertButton = (button: SvelteComponent, position: Identifier = 0) =>
|
const insertButton = (button: SvelteComponent, position: Identifier = 0) =>
|
||||||
addComponent(button, (added, parent) =>
|
addComponent(button, (added, parent) =>
|
||||||
insertElement(added, parent, position)
|
insertElement(added, parent, position),
|
||||||
);
|
);
|
||||||
const appendButton = (button: SvelteComponent, position: Identifier = -1) =>
|
const appendButton = (button: SvelteComponent, position: Identifier = -1) =>
|
||||||
addComponent(button, (added, parent) =>
|
addComponent(button, (added, parent) =>
|
||||||
appendElement(added, parent, position)
|
appendElement(added, parent, position),
|
||||||
);
|
);
|
||||||
|
|
||||||
const showButton = (id: Identifier) =>
|
const showButton = (id: Identifier) =>
|
||||||
@ -80,7 +80,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
const toggleButton = (id: Identifier) =>
|
const toggleButton = (id: Identifier) =>
|
||||||
updateRegistration(
|
updateRegistration(
|
||||||
({ detach }) => detach.update((old: boolean): boolean => !old),
|
({ detach }) => detach.update((old: boolean): boolean => !old),
|
||||||
id
|
id,
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(api, {
|
Object.assign(api, {
|
||||||
|
@ -48,11 +48,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
const insertGroup = (group: SvelteComponent, position: Identifier = 0) =>
|
const insertGroup = (group: SvelteComponent, position: Identifier = 0) =>
|
||||||
addComponent(group, (added, parent) =>
|
addComponent(group, (added, parent) =>
|
||||||
insertElement(added, parent, position)
|
insertElement(added, parent, position),
|
||||||
);
|
);
|
||||||
const appendGroup = (group: SvelteComponent, position: Identifier = -1) =>
|
const appendGroup = (group: SvelteComponent, position: Identifier = -1) =>
|
||||||
addComponent(group, (added, parent) =>
|
addComponent(group, (added, parent) =>
|
||||||
appendElement(added, parent, position)
|
appendElement(added, parent, position),
|
||||||
);
|
);
|
||||||
|
|
||||||
const showGroup = (id: Identifier) =>
|
const showGroup = (id: Identifier) =>
|
||||||
@ -62,7 +62,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
const toggleGroup = (id: Identifier) =>
|
const toggleGroup = (id: Identifier) =>
|
||||||
updateRegistration(
|
updateRegistration(
|
||||||
({ detach }) => detach.update((old: boolean): boolean => !old),
|
({ detach }) => detach.update((old: boolean): boolean => !old),
|
||||||
id
|
id,
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(api, {
|
Object.assign(api, {
|
||||||
|
@ -32,11 +32,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
const insert = (group: SvelteComponent, position: Identifier = 0) =>
|
const insert = (group: SvelteComponent, position: Identifier = 0) =>
|
||||||
addComponent(group, (added, parent) =>
|
addComponent(group, (added, parent) =>
|
||||||
insertElement(added, parent, position)
|
insertElement(added, parent, position),
|
||||||
);
|
);
|
||||||
const append = (group: SvelteComponent, position: Identifier = -1) =>
|
const append = (group: SvelteComponent, position: Identifier = -1) =>
|
||||||
addComponent(group, (added, parent) =>
|
addComponent(group, (added, parent) =>
|
||||||
appendElement(added, parent, position)
|
appendElement(added, parent, position),
|
||||||
);
|
);
|
||||||
|
|
||||||
const show = (id: Identifier) =>
|
const show = (id: Identifier) =>
|
||||||
@ -46,7 +46,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
const toggle = (id: Identifier) =>
|
const toggle = (id: Identifier) =>
|
||||||
updateRegistration(
|
updateRegistration(
|
||||||
({ detach }) => detach.update((old: boolean): boolean => !old),
|
({ detach }) => detach.update((old: boolean): boolean => !old),
|
||||||
id
|
id,
|
||||||
);
|
);
|
||||||
|
|
||||||
Object.assign(api, { insert, append, show, hide, toggle });
|
Object.assign(api, { insert, append, show, hide, toggle });
|
||||||
|
@ -15,7 +15,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
registerShortcut(
|
registerShortcut(
|
||||||
(event: KeyboardEvent) => dispatch("action", { originalEvent: event }),
|
(event: KeyboardEvent) => dispatch("action", { originalEvent: event }),
|
||||||
keyCombination,
|
keyCombination,
|
||||||
target as any
|
target as any,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
@ -27,7 +27,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: KeyType): boolean =>
|
updateAllStateWithCallback((key: KeyType): boolean =>
|
||||||
updaterMap.get(key)!(event)
|
updaterMap.get(key)!(event),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
export function mergeTooltipAndShortcut(
|
export function mergeTooltipAndShortcut(
|
||||||
tooltip: string | undefined,
|
tooltip: string | undefined,
|
||||||
shortcutLabel: string | undefined
|
shortcutLabel: string | undefined,
|
||||||
): string | undefined {
|
): string | undefined {
|
||||||
if (!tooltip && !shortcutLabel) {
|
if (!tooltip && !shortcutLabel) {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -4,7 +4,7 @@ export type Identifier = string | number;
|
|||||||
|
|
||||||
export function findElement(
|
export function findElement(
|
||||||
collection: HTMLCollection,
|
collection: HTMLCollection,
|
||||||
idOrIndex: Identifier
|
idOrIndex: Identifier,
|
||||||
): [number, Element] | null {
|
): [number, Element] | null {
|
||||||
let result: [number, Element] | null = null;
|
let result: [number, Element] | null = null;
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ export function findElement(
|
|||||||
export function insertElement(
|
export function insertElement(
|
||||||
element: Element,
|
element: Element,
|
||||||
collection: Element,
|
collection: Element,
|
||||||
idOrIndex: Identifier
|
idOrIndex: Identifier,
|
||||||
): number {
|
): number {
|
||||||
const match = findElement(collection.children, idOrIndex);
|
const match = findElement(collection.children, idOrIndex);
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ export function insertElement(
|
|||||||
export function appendElement(
|
export function appendElement(
|
||||||
element: Element,
|
element: Element,
|
||||||
collection: Element,
|
collection: Element,
|
||||||
idOrIndex: Identifier
|
idOrIndex: Identifier,
|
||||||
): number {
|
): number {
|
||||||
const match = findElement(collection.children, idOrIndex);
|
const match = findElement(collection.children, idOrIndex);
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ export function appendElement(
|
|||||||
export function updateElement(
|
export function updateElement(
|
||||||
f: (element: Element) => void,
|
f: (element: Element) => void,
|
||||||
collection: Element,
|
collection: Element,
|
||||||
idOrIndex: Identifier
|
idOrIndex: Identifier,
|
||||||
): number {
|
): number {
|
||||||
const match = findElement(collection.children, idOrIndex);
|
const match = findElement(collection.children, idOrIndex);
|
||||||
|
|
||||||
|
@ -28,11 +28,11 @@ export interface RegistrationAPI<T extends Registration> {
|
|||||||
export interface DynamicRegistrationAPI<T> {
|
export interface DynamicRegistrationAPI<T> {
|
||||||
addComponent: (
|
addComponent: (
|
||||||
component: SvelteComponent,
|
component: SvelteComponent,
|
||||||
add: (added: Element, parent: Element) => number
|
add: (added: Element, parent: Element) => number,
|
||||||
) => void;
|
) => void;
|
||||||
updateRegistration: (
|
updateRegistration: (
|
||||||
update: (registration: T) => void,
|
update: (registration: T) => void,
|
||||||
position: Identifier
|
position: Identifier,
|
||||||
) => void;
|
) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,14 +41,14 @@ export function nodeIsElement(node: Node): node is Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function makeInterface<T extends Registration>(
|
export function makeInterface<T extends Registration>(
|
||||||
makeRegistration: () => T
|
makeRegistration: () => T,
|
||||||
): RegistrationAPI<T> {
|
): RegistrationAPI<T> {
|
||||||
const registrations: T[] = [];
|
const registrations: T[] = [];
|
||||||
const items = writable(registrations);
|
const items = writable(registrations);
|
||||||
|
|
||||||
function registerComponent(
|
function registerComponent(
|
||||||
index: number = registrations.length,
|
index: number = registrations.length,
|
||||||
registration = makeRegistration()
|
registration = makeRegistration(),
|
||||||
): T {
|
): T {
|
||||||
items.update((registrations) => {
|
items.update((registrations) => {
|
||||||
registrations.splice(index, 0, registration);
|
registrations.splice(index, 0, registration);
|
||||||
@ -64,13 +64,13 @@ export function makeInterface<T extends Registration>(
|
|||||||
function getDynamicInterface(elementRef: HTMLElement): DynamicRegistrationAPI<T> {
|
function getDynamicInterface(elementRef: HTMLElement): DynamicRegistrationAPI<T> {
|
||||||
function addComponent(
|
function addComponent(
|
||||||
component: SvelteComponent,
|
component: SvelteComponent,
|
||||||
add: (added: Element, parent: Element) => number
|
add: (added: Element, parent: Element) => number,
|
||||||
): void {
|
): void {
|
||||||
const registration = makeRegistration();
|
const registration = makeRegistration();
|
||||||
|
|
||||||
const callback = (
|
const callback = (
|
||||||
mutations: MutationRecord[],
|
mutations: MutationRecord[],
|
||||||
observer: MutationObserver
|
observer: MutationObserver,
|
||||||
): void => {
|
): void => {
|
||||||
for (const mutation of mutations) {
|
for (const mutation of mutations) {
|
||||||
for (const addedNode of mutation.addedNodes) {
|
for (const addedNode of mutation.addedNodes) {
|
||||||
@ -99,7 +99,7 @@ export function makeInterface<T extends Registration>(
|
|||||||
|
|
||||||
function updateRegistration(
|
function updateRegistration(
|
||||||
update: (registration: T) => void,
|
update: (registration: T) => void,
|
||||||
position: Identifier
|
position: Identifier,
|
||||||
): void {
|
): void {
|
||||||
const match = findElement(elementRef.children, position);
|
const match = findElement(elementRef.children, position);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import * as tr from "../lib/ftl";
|
|||||||
|
|
||||||
export async function getCongratsInfo(): Promise<Scheduler.CongratsInfoResponse> {
|
export async function getCongratsInfo(): Promise<Scheduler.CongratsInfoResponse> {
|
||||||
return Scheduler.CongratsInfoResponse.decode(
|
return Scheduler.CongratsInfoResponse.decode(
|
||||||
await postRequest("/_anki/congratsInfo", "")
|
await postRequest("/_anki/congratsInfo", ""),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ import { nightModeKey, touchDeviceKey, modalsKey } from "../components/context-k
|
|||||||
|
|
||||||
export async function deckOptions(
|
export async function deckOptions(
|
||||||
target: HTMLDivElement,
|
target: HTMLDivElement,
|
||||||
deckId: number
|
deckId: number,
|
||||||
): Promise<DeckOptionsPage> {
|
): Promise<DeckOptionsPage> {
|
||||||
const [info] = await Promise.all([
|
const [info] = await Promise.all([
|
||||||
getDeckOptionsInfo(deckId),
|
getDeckOptionsInfo(deckId),
|
||||||
|
@ -94,7 +94,7 @@ const exampleData = {
|
|||||||
function startingState(): DeckOptionsState {
|
function startingState(): DeckOptionsState {
|
||||||
return new DeckOptionsState(
|
return new DeckOptionsState(
|
||||||
123,
|
123,
|
||||||
DeckConfig.DeckConfigsForUpdate.fromObject(exampleData)
|
DeckConfig.DeckConfigsForUpdate.fromObject(exampleData),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +308,7 @@ test("aux data", () => {
|
|||||||
JSON.parse(new TextDecoder().decode((c.config as any).other)) as Record<
|
JSON.parse(new TextDecoder().decode((c.config as any).other)) as Record<
|
||||||
string,
|
string,
|
||||||
unknown
|
unknown
|
||||||
>
|
>,
|
||||||
);
|
);
|
||||||
expect(json).toStrictEqual([
|
expect(json).toStrictEqual([
|
||||||
// other deck comes first
|
// other deck comes first
|
||||||
|
@ -13,15 +13,15 @@ import { localeCompare } from "../lib/i18n";
|
|||||||
import type { DynamicSvelteComponent } from "../sveltelib/dynamicComponent";
|
import type { DynamicSvelteComponent } from "../sveltelib/dynamicComponent";
|
||||||
|
|
||||||
export async function getDeckOptionsInfo(
|
export async function getDeckOptionsInfo(
|
||||||
deckId: number
|
deckId: number,
|
||||||
): Promise<DeckConfig.DeckConfigsForUpdate> {
|
): Promise<DeckConfig.DeckConfigsForUpdate> {
|
||||||
return DeckConfig.DeckConfigsForUpdate.decode(
|
return DeckConfig.DeckConfigsForUpdate.decode(
|
||||||
await postRequest("/_anki/deckConfigsForUpdate", JSON.stringify({ deckId }))
|
await postRequest("/_anki/deckConfigsForUpdate", JSON.stringify({ deckId })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveDeckOptions(
|
export async function saveDeckOptions(
|
||||||
input: DeckConfig.UpdateDeckConfigsRequest
|
input: DeckConfig.UpdateDeckConfigsRequest,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const data: Uint8Array = DeckConfig.UpdateDeckConfigsRequest.encode(input).finish();
|
const data: Uint8Array = DeckConfig.UpdateDeckConfigsRequest.encode(input).finish();
|
||||||
await postRequest("/_anki/updateDeckConfigs", data);
|
await postRequest("/_anki/updateDeckConfigs", data);
|
||||||
@ -84,7 +84,7 @@ export class DeckOptionsState {
|
|||||||
});
|
});
|
||||||
this.selectedIdx = Math.max(
|
this.selectedIdx = Math.max(
|
||||||
0,
|
0,
|
||||||
this.configs.findIndex((c) => c.config.id === this.currentDeck.configId)
|
this.configs.findIndex((c) => c.config.id === this.currentDeck.configId),
|
||||||
);
|
);
|
||||||
this.v3Scheduler = data.v3Scheduler;
|
this.v3Scheduler = data.v3Scheduler;
|
||||||
this.haveAddons = data.haveAddons;
|
this.haveAddons = data.haveAddons;
|
||||||
@ -284,17 +284,17 @@ export class DeckOptionsState {
|
|||||||
|
|
||||||
private getParentLimits(): ParentLimits {
|
private getParentLimits(): ParentLimits {
|
||||||
const parentConfigs = this.configs.filter((c) =>
|
const parentConfigs = this.configs.filter((c) =>
|
||||||
this.currentDeck.parentConfigIds.includes(c.config.id)
|
this.currentDeck.parentConfigIds.includes(c.config.id),
|
||||||
);
|
);
|
||||||
const newCards = parentConfigs.reduce(
|
const newCards = parentConfigs.reduce(
|
||||||
(previous, current) =>
|
(previous, current) =>
|
||||||
Math.min(previous, current.config.config?.newPerDay ?? 0),
|
Math.min(previous, current.config.config?.newPerDay ?? 0),
|
||||||
2 ** 31
|
2 ** 31,
|
||||||
);
|
);
|
||||||
const reviews = parentConfigs.reduce(
|
const reviews = parentConfigs.reduce(
|
||||||
(previous, current) =>
|
(previous, current) =>
|
||||||
Math.min(previous, current.config.config?.reviewsPerDay ?? 0),
|
Math.min(previous, current.config.config?.reviewsPerDay ?? 0),
|
||||||
2 ** 31
|
2 ** 31,
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
newCards,
|
newCards,
|
||||||
|
@ -10,7 +10,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
export let resolve: (editable: HTMLElement) => void;
|
export let resolve: (editable: HTMLElement) => void;
|
||||||
export let mirror: (
|
export let mirror: (
|
||||||
editable: HTMLElement,
|
editable: HTMLElement,
|
||||||
params: { store: Writable<DocumentFragment> }
|
params: { store: Writable<DocumentFragment> },
|
||||||
) => void;
|
) => void;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ export interface DecoratedElementConstructor
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CustomElementArray<
|
export class CustomElementArray<
|
||||||
T extends CustomElementConstructor & WithTagName
|
T extends CustomElementConstructor & WithTagName,
|
||||||
> extends Array<T> {
|
> extends Array<T> {
|
||||||
push(...elements: T[]): number {
|
push(...elements: T[]): number {
|
||||||
for (const element of elements) {
|
for (const element of elements) {
|
||||||
|
@ -17,7 +17,7 @@ import Mathjax_svelte from "./Mathjax.svelte";
|
|||||||
function moveNodeOutOfElement(
|
function moveNodeOutOfElement(
|
||||||
element: Element,
|
element: Element,
|
||||||
node: Node,
|
node: Node,
|
||||||
placement: "beforebegin" | "afterend"
|
placement: "beforebegin" | "afterend",
|
||||||
): Node {
|
): Node {
|
||||||
element.removeChild(node);
|
element.removeChild(node);
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax
|
|||||||
return typeof block === "string" && block !== "false"
|
return typeof block === "string" && block !== "false"
|
||||||
? `\\[${text}\\]`
|
? `\\[${text}\\]`
|
||||||
: `\\(${text}\\)`;
|
: `\\(${text}\\)`;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,11 +114,12 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax
|
|||||||
.replace(
|
.replace(
|
||||||
mathjaxBlockDelimiterPattern,
|
mathjaxBlockDelimiterPattern,
|
||||||
(_match: string, text: string) =>
|
(_match: string, text: string) =>
|
||||||
`<anki-mathjax block="true">${text}</anki-mathjax>`
|
`<anki-mathjax block="true">${text}</anki-mathjax>`,
|
||||||
)
|
)
|
||||||
.replace(
|
.replace(
|
||||||
mathjaxInlineDelimiterPattern,
|
mathjaxInlineDelimiterPattern,
|
||||||
(_match: string, text: string) => `<anki-mathjax>${text}</anki-mathjax>`
|
(_match: string, text: string) =>
|
||||||
|
`<anki-mathjax>${text}</anki-mathjax>`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +162,7 @@ export const Mathjax: DecoratedElementConstructor = class Mathjax
|
|||||||
const context = new Map();
|
const context = new Map();
|
||||||
context.set(
|
context.set(
|
||||||
nightModeKey,
|
nightModeKey,
|
||||||
document.documentElement.classList.contains("night-mode")
|
document.documentElement.classList.contains("night-mode"),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.component = new Mathjax_svelte({
|
this.component = new Mathjax_svelte({
|
||||||
|
@ -32,7 +32,7 @@ function getEmptyIcon(style: HTMLStyleElement): [string, string] {
|
|||||||
export function convertMathjax(
|
export function convertMathjax(
|
||||||
input: string,
|
input: string,
|
||||||
nightMode: boolean,
|
nightMode: boolean,
|
||||||
fontSize: number
|
fontSize: number,
|
||||||
): [string, string] {
|
): [string, string] {
|
||||||
const style = getStyle(getCSS(nightMode, fontSize));
|
const style = getStyle(getCSS(nightMode, fontSize));
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
editor: { get: () => codeMirror },
|
editor: { get: () => codeMirror },
|
||||||
}
|
},
|
||||||
) as CodeMirrorAPI;
|
) as CodeMirrorAPI;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
<IconButton
|
<IconButton
|
||||||
tooltip={appendInParentheses(
|
tooltip={appendInParentheses(
|
||||||
tr.editingSetTextColor(),
|
tr.editingSetTextColor(),
|
||||||
shortcutLabel
|
shortcutLabel,
|
||||||
)}
|
)}
|
||||||
{disabled}
|
{disabled}
|
||||||
on:click={forecolorWrap}
|
on:click={forecolorWrap}
|
||||||
@ -60,7 +60,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
<IconButton
|
<IconButton
|
||||||
tooltip={appendInParentheses(
|
tooltip={appendInParentheses(
|
||||||
tr.editingChangeColor(),
|
tr.editingChangeColor(),
|
||||||
shortcutLabel
|
shortcutLabel,
|
||||||
)}
|
)}
|
||||||
{disabled}
|
{disabled}
|
||||||
widthMultiplier={0.5}
|
widthMultiplier={0.5}
|
||||||
|
@ -58,8 +58,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
direction: {
|
direction: {
|
||||||
get: () => $directionStore,
|
get: () => $directionStore,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
) as EditorFieldAPI
|
) as EditorFieldAPI,
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -168,7 +168,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
function updateField(index: number, content: string): void {
|
function updateField(index: number, content: string): void {
|
||||||
fieldSave.schedule(
|
fieldSave.schedule(
|
||||||
() => bridgeCommand(`key:${index}:${getNoteId()}:${content}`),
|
() => bridgeCommand(`key:${index}:${getNoteId()}:${content}`),
|
||||||
600
|
600,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -230,8 +230,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
fields: { get: () => fieldApis },
|
fields: { get: () => fieldApis },
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
@ -271,7 +271,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
on:focusout={() => {
|
on:focusout={() => {
|
||||||
$currentField = null;
|
$currentField = null;
|
||||||
bridgeCommand(
|
bridgeCommand(
|
||||||
`blur:${index}:${getNoteId()}:${get(fieldStores[index])}`
|
`blur:${index}:${getNoteId()}:${get(fieldStores[index])}`,
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
--label-color={cols[index] === "dupe"
|
--label-color={cols[index] === "dupe"
|
||||||
|
@ -23,7 +23,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMount(() =>
|
onMount(() =>
|
||||||
registerShortcut(toggle, keyCombination, editorField.element as HTMLElement)
|
registerShortcut(toggle, keyCombination, editorField.element as HTMLElement),
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
for (const decorated of decoratedElements) {
|
for (const decorated of decoratedElements) {
|
||||||
for (const element of fragment.querySelectorAll(
|
for (const element of fragment.querySelectorAll(
|
||||||
decorated.tagName
|
decorated.tagName,
|
||||||
) as NodeListOf<DecoratedElement>) {
|
) as NodeListOf<DecoratedElement>) {
|
||||||
element.undecorate();
|
element.undecorate();
|
||||||
}
|
}
|
||||||
@ -195,7 +195,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
},
|
},
|
||||||
surround(before: string, after: string) {
|
surround(before: string, after: string) {
|
||||||
richTextPromise.then((richText) =>
|
richTextPromise.then((richText) =>
|
||||||
wrapInternal(richText.getRootNode() as any, before, after, false)
|
wrapInternal(richText.getRootNode() as any, before, after, false),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
preventResubscription,
|
preventResubscription,
|
||||||
|
@ -30,7 +30,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
let tagTypes: TagType[];
|
let tagTypes: TagType[];
|
||||||
function tagsToTagTypes(tags: string[]): void {
|
function tagsToTagTypes(tags: string[]): void {
|
||||||
tagTypes = tags.map(
|
tagTypes = tags.map(
|
||||||
(tag: string): TagType => attachId(replaceWithUnicodeSeparator(tag))
|
(tag: string): TagType => attachId(replaceWithUnicodeSeparator(tag)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,8 +59,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
const data = await postRequest(
|
const data = await postRequest(
|
||||||
"/_anki/completeTag",
|
"/_anki/completeTag",
|
||||||
Tags.CompleteTagRequest.encode(
|
Tags.CompleteTagRequest.encode(
|
||||||
Tags.CompleteTagRequest.create({ input, matchLimit: 500 })
|
Tags.CompleteTagRequest.create({ input, matchLimit: 500 }),
|
||||||
).finish()
|
).finish(),
|
||||||
);
|
);
|
||||||
const response = Tags.CompleteTagResponse.decode(data);
|
const response = Tags.CompleteTagResponse.decode(data);
|
||||||
return response.tags;
|
return response.tags;
|
||||||
@ -86,7 +86,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
(names: string[]): string[] => {
|
(names: string[]): string[] => {
|
||||||
autocompleteDisabled = names.length === 0;
|
autocompleteDisabled = names.length === 0;
|
||||||
return names.map(replaceWithUnicodeSeparator);
|
return names.map(replaceWithUnicodeSeparator);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
async function enterBehavior(
|
async function enterBehavior(
|
||||||
index: number,
|
index: number,
|
||||||
start: number,
|
start: number,
|
||||||
end: number
|
end: number,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (autocomplete.hasSelected()) {
|
if (autocomplete.hasSelected()) {
|
||||||
autocomplete.chooseSelected();
|
autocomplete.chooseSelected();
|
||||||
@ -334,7 +334,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
function deselect() {
|
function deselect() {
|
||||||
tagTypes = tagTypes.map(
|
tagTypes = tagTypes.map(
|
||||||
(tag: TagType): TagType => ({ ...tag, selected: false })
|
(tag: TagType): TagType => ({ ...tag, selected: false }),
|
||||||
);
|
);
|
||||||
selectionAnchor = null;
|
selectionAnchor = null;
|
||||||
selectionFocus = null;
|
selectionFocus = null;
|
||||||
|
@ -127,7 +127,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
name = `${before.slice(0, -1)}${delimChar}${name.slice(
|
name = `${before.slice(0, -1)}${delimChar}${name.slice(
|
||||||
positionEnd,
|
positionEnd,
|
||||||
name.length
|
name.length,
|
||||||
)}`;
|
)}`;
|
||||||
|
|
||||||
await tick();
|
await tick();
|
||||||
@ -199,7 +199,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
const selection = document.getSelection();
|
const selection = document.getSelection();
|
||||||
event.clipboardData!.setData(
|
event.clipboardData!.setData(
|
||||||
"text/plain",
|
"text/plain",
|
||||||
replaceWithColons(selection!.toString())
|
replaceWithColons(selection!.toString()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
<IconButton
|
<IconButton
|
||||||
tooltip={appendInParentheses(
|
tooltip={appendInParentheses(
|
||||||
tr.editingAttachPicturesaudiovideo(),
|
tr.editingAttachPicturesaudiovideo(),
|
||||||
shortcutLabel
|
shortcutLabel,
|
||||||
)}
|
)}
|
||||||
iconSize={70}
|
iconSize={70}
|
||||||
{disabled}
|
{disabled}
|
||||||
@ -85,7 +85,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
on:click={() =>
|
on:click={() =>
|
||||||
$activeInput?.surround(
|
$activeInput?.surround(
|
||||||
"<anki-mathjax focusonmount>",
|
"<anki-mathjax focusonmount>",
|
||||||
"</anki-mathjax>"
|
"</anki-mathjax>",
|
||||||
)}
|
)}
|
||||||
on:mount={withButton(createShortcut)}
|
on:mount={withButton(createShortcut)}
|
||||||
>
|
>
|
||||||
@ -103,7 +103,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
on:click={() =>
|
on:click={() =>
|
||||||
$activeInput?.surround(
|
$activeInput?.surround(
|
||||||
'<anki-mathjax block="true" focusonmount>',
|
'<anki-mathjax block="true" focusonmount>',
|
||||||
"</anki-matjax>"
|
"</anki-matjax>",
|
||||||
)}
|
)}
|
||||||
on:mount={withButton(createShortcut)}
|
on:mount={withButton(createShortcut)}
|
||||||
>
|
>
|
||||||
@ -121,7 +121,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
on:click={() =>
|
on:click={() =>
|
||||||
$activeInput?.surround(
|
$activeInput?.surround(
|
||||||
"<anki-mathjax focusonmount>\\ce{",
|
"<anki-mathjax focusonmount>\\ce{",
|
||||||
"}</anki-mathjax>"
|
"}</anki-mathjax>",
|
||||||
)}
|
)}
|
||||||
on:mount={withButton(createShortcut)}
|
on:mount={withButton(createShortcut)}
|
||||||
>
|
>
|
||||||
|
@ -9,7 +9,7 @@ export function appendInParentheses(text: string, appendix: string): string {
|
|||||||
export function execCommand(
|
export function execCommand(
|
||||||
command: string,
|
command: string,
|
||||||
showUI?: boolean | undefined,
|
showUI?: boolean | undefined,
|
||||||
value?: string | undefined
|
value?: string | undefined,
|
||||||
): void {
|
): void {
|
||||||
document.execCommand(command, showUI, value);
|
document.execCommand(command, showUI, value);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
const nth =
|
const nth =
|
||||||
Array.prototype.indexOf.call(
|
Array.prototype.indexOf.call(
|
||||||
(element.parentNode! as Document | ShadowRoot).children,
|
(element.parentNode! as Document | ShadowRoot).children,
|
||||||
element
|
element,
|
||||||
) + 1;
|
) + 1;
|
||||||
return [`${tagName}:nth-child(${nth})`, ...tokens];
|
return [`${tagName}:nth-child(${nth})`, ...tokens];
|
||||||
} else {
|
} else {
|
||||||
@ -46,7 +46,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
1;
|
1;
|
||||||
return createPathRecursive(
|
return createPathRecursive(
|
||||||
[`${tagName}:nth-child(${nth})`, ...tokens],
|
[`${tagName}:nth-child(${nth})`, ...tokens],
|
||||||
element.parentElement
|
element.parentElement,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,7 +92,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
rule.style.setProperty(
|
rule.style.setProperty(
|
||||||
"height",
|
"height",
|
||||||
height < maxHeight ? `${height}px` : "auto",
|
height < maxHeight ? `${height}px` : "auto",
|
||||||
"important"
|
"important",
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// square or restricted by width
|
// square or restricted by width
|
||||||
@ -100,7 +100,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
rule.style.setProperty(
|
rule.style.setProperty(
|
||||||
"width",
|
"width",
|
||||||
width < maxWidth ? `${width}px` : "auto",
|
width < maxWidth ? `${width}px` : "auto",
|
||||||
"important"
|
"important",
|
||||||
);
|
);
|
||||||
|
|
||||||
rule.style.setProperty("height", "auto", "important");
|
rule.style.setProperty("height", "auto", "important");
|
||||||
@ -125,7 +125,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
images.push(image);
|
images.push(image);
|
||||||
const index = sheet.insertRule(
|
const index = sheet.insertRule(
|
||||||
`${createPath(image)} {}`,
|
`${createPath(image)} {}`,
|
||||||
sheet.cssRules.length
|
sheet.cssRules.length,
|
||||||
);
|
);
|
||||||
const rule = sheet.cssRules[index] as CSSStyleRule;
|
const rule = sheet.cssRules[index] as CSSStyleRule;
|
||||||
setImageRule(image, rule);
|
setImageRule(image, rule);
|
||||||
@ -151,7 +151,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
const mutationObserver = new MutationObserver((mutations) => {
|
const mutationObserver = new MutationObserver((mutations) => {
|
||||||
const addedImages = mutations.flatMap((mutation) =>
|
const addedImages = mutations.flatMap((mutation) =>
|
||||||
filterImages([...mutation.addedNodes])
|
filterImages([...mutation.addedNodes]),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const image of addedImages) {
|
for (const image of addedImages) {
|
||||||
@ -159,7 +159,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
}
|
}
|
||||||
|
|
||||||
const removedImages = mutations.flatMap((mutation) =>
|
const removedImages = mutations.flatMap((mutation) =>
|
||||||
filterImages([...mutation.removedNodes])
|
filterImages([...mutation.removedNodes]),
|
||||||
);
|
);
|
||||||
|
|
||||||
for (const image of removedImages) {
|
for (const image of removedImages) {
|
||||||
|
@ -15,7 +15,7 @@ export const $editorToolbar = new Promise(noop);
|
|||||||
export function pasteHTML(
|
export function pasteHTML(
|
||||||
html: string,
|
html: string,
|
||||||
internal: boolean,
|
internal: boolean,
|
||||||
extendedMode: boolean
|
extendedMode: boolean,
|
||||||
): void {
|
): void {
|
||||||
html = filterHTML(html, internal, extendedMode);
|
html = filterHTML(html, internal, extendedMode);
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ function setupNoteEditor(i18n: Promise<void>): Promise<OldEditorAdapter> {
|
|||||||
|
|
||||||
context.set(
|
context.set(
|
||||||
nightModeKey,
|
nightModeKey,
|
||||||
document.documentElement.classList.contains("night-mode")
|
document.documentElement.classList.contains("night-mode"),
|
||||||
);
|
);
|
||||||
|
|
||||||
i18n.then(() => {
|
i18n.then(() => {
|
||||||
|
@ -40,7 +40,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
addedData,
|
addedData,
|
||||||
graphRange,
|
graphRange,
|
||||||
dispatch,
|
dispatch,
|
||||||
$browserLinksSupported
|
$browserLinksSupported,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
targetYear,
|
targetYear,
|
||||||
nightMode,
|
nightMode,
|
||||||
revlogRange,
|
revlogRange,
|
||||||
calendarFirstDayOfWeek.set
|
calendarFirstDayOfWeek.set,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
[histogramData, tableData] = prepareData(
|
[histogramData, tableData] = prepareData(
|
||||||
gatherData(sourceData),
|
gatherData(sourceData),
|
||||||
dispatch,
|
dispatch,
|
||||||
$browserLinksSupported
|
$browserLinksSupported,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
graphRange,
|
graphRange,
|
||||||
$futureDueShowBacklog,
|
$futureDueShowBacklog,
|
||||||
dispatch,
|
dispatch,
|
||||||
$browserLinksSupported
|
$browserLinksSupported,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
intervalData,
|
intervalData,
|
||||||
range,
|
range,
|
||||||
dispatch,
|
dispatch,
|
||||||
$browserLinksSupported
|
$browserLinksSupported,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
bounds,
|
bounds,
|
||||||
graphData,
|
graphData,
|
||||||
graphRange,
|
graphRange,
|
||||||
showTime
|
showTime,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,25 +20,25 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
|
|
||||||
async function getGraphData(
|
async function getGraphData(
|
||||||
search: string,
|
search: string,
|
||||||
days: number
|
days: number,
|
||||||
): Promise<Stats.GraphsResponse> {
|
): Promise<Stats.GraphsResponse> {
|
||||||
return Stats.GraphsResponse.decode(
|
return Stats.GraphsResponse.decode(
|
||||||
await postRequest("/_anki/graphData", JSON.stringify({ search, days }))
|
await postRequest("/_anki/graphData", JSON.stringify({ search, days })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGraphPreferences(): Promise<Stats.GraphPreferences> {
|
async function getGraphPreferences(): Promise<Stats.GraphPreferences> {
|
||||||
return Stats.GraphPreferences.decode(
|
return Stats.GraphPreferences.decode(
|
||||||
await postRequest("/_anki/graphPreferences", JSON.stringify({}))
|
await postRequest("/_anki/graphPreferences", JSON.stringify({})),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setGraphPreferences(
|
async function setGraphPreferences(
|
||||||
prefs: PreferencePayload<Stats.GraphPreferences>
|
prefs: PreferencePayload<Stats.GraphPreferences>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await postRequest(
|
await postRequest(
|
||||||
"/_anki/setGraphPreferences",
|
"/_anki/setGraphPreferences",
|
||||||
Stats.GraphPreferences.encode(prefs).finish()
|
Stats.GraphPreferences.encode(prefs).finish(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,9 +58,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||||||
setGraphPreferences,
|
setGraphPreferences,
|
||||||
Stats.GraphPreferences.toObject.bind(Stats.GraphPreferences) as (
|
Stats.GraphPreferences.toObject.bind(Stats.GraphPreferences) as (
|
||||||
preferences: Stats.GraphPreferences,
|
preferences: Stats.GraphPreferences,
|
||||||
options: { defaults: boolean }
|
options: { defaults: boolean },
|
||||||
) => PreferenceRaw<Stats.GraphPreferences>
|
) => PreferenceRaw<Stats.GraphPreferences>,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
$: revlogRange = daysToRevlogRange($days);
|
$: revlogRange = daysToRevlogRange($days);
|
||||||
|
@ -51,7 +51,7 @@ export function buildHistogram(
|
|||||||
data: GraphData,
|
data: GraphData,
|
||||||
range: GraphRange,
|
range: GraphRange,
|
||||||
dispatch: SearchDispatch,
|
dispatch: SearchDispatch,
|
||||||
browserLinksSupported: boolean
|
browserLinksSupported: boolean,
|
||||||
): [HistogramData | null, TableDatum[]] {
|
): [HistogramData | null, TableDatum[]] {
|
||||||
// get min/max
|
// get min/max
|
||||||
const total = data.daysAdded.length;
|
const total = data.daysAdded.length;
|
||||||
@ -91,7 +91,7 @@ export function buildHistogram(
|
|||||||
|
|
||||||
const adjustedRange = scaleLinear().range([0.7, 0.3]);
|
const adjustedRange = scaleLinear().range([0.7, 0.3]);
|
||||||
const colourScale = scaleSequential((n) =>
|
const colourScale = scaleSequential((n) =>
|
||||||
interpolateBlues(adjustedRange(n)!)
|
interpolateBlues(adjustedRange(n)!),
|
||||||
).domain([xMax!, xMin!]);
|
).domain([xMax!, xMin!]);
|
||||||
|
|
||||||
const totalInPeriod = sum(bins, (bin) => bin.length);
|
const totalInPeriod = sum(bins, (bin) => bin.length);
|
||||||
@ -111,7 +111,7 @@ export function buildHistogram(
|
|||||||
function hoverText(
|
function hoverText(
|
||||||
bin: Bin<number, number>,
|
bin: Bin<number, number>,
|
||||||
cumulative: number,
|
cumulative: number,
|
||||||
_percent: number
|
_percent: number,
|
||||||
): string {
|
): string {
|
||||||
const day = dayLabel(bin.x0!, bin.x1!);
|
const day = dayLabel(bin.x0!, bin.x1!);
|
||||||
const cards = tr.statisticsCards({ cards: bin.length });
|
const cards = tr.statisticsCards({ cards: bin.length });
|
||||||
|
@ -97,7 +97,7 @@ export function renderButtons(
|
|||||||
svgElem: SVGElement,
|
svgElem: SVGElement,
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
origData: Stats.GraphsResponse,
|
origData: Stats.GraphsResponse,
|
||||||
range: GraphRange
|
range: GraphRange,
|
||||||
): void {
|
): void {
|
||||||
const sourceData = gatherData(origData, range);
|
const sourceData = gatherData(origData, range);
|
||||||
const data = [
|
const data = [
|
||||||
@ -129,7 +129,7 @@ export function renderButtons(
|
|||||||
const total = sum(groupData, (d) => d.count);
|
const total = sum(groupData, (d) => d.count);
|
||||||
const correct = sum(
|
const correct = sum(
|
||||||
groupData.filter((d) => d.buttonNum > 1),
|
groupData.filter((d) => d.buttonNum > 1),
|
||||||
(d) => d.count
|
(d) => d.count,
|
||||||
);
|
);
|
||||||
const percent = total ? ((correct / total) * 100).toFixed(2) : "0";
|
const percent = total ? ((correct / total) * 100).toFixed(2) : "0";
|
||||||
return { total, correct, percent };
|
return { total, correct, percent };
|
||||||
@ -170,8 +170,8 @@ export function renderButtons(
|
|||||||
}
|
}
|
||||||
return `${kind} \u200e(${totalCorrect(d).percent}%)`;
|
return `${kind} \u200e(${totalCorrect(d).percent}%)`;
|
||||||
}) as any)
|
}) as any)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -193,8 +193,8 @@ export function renderButtons(
|
|||||||
selection.transition(trans).call(
|
selection.transition(trans).call(
|
||||||
axisLeft(y)
|
axisLeft(y)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -207,7 +207,7 @@ export function renderButtons(
|
|||||||
.transition(trans)
|
.transition(trans)
|
||||||
.attr(
|
.attr(
|
||||||
"x",
|
"x",
|
||||||
(d: Datum) => xGroup(d.group)! + xButton(d.buttonNum.toString())!
|
(d: Datum) => xGroup(d.group)! + xButton(d.buttonNum.toString())!,
|
||||||
)
|
)
|
||||||
.attr("y", (d: Datum) => y(d.count)!)
|
.attr("y", (d: Datum) => y(d.count)!)
|
||||||
.attr("height", (d: Datum) => y(0)! - y(d.count)!)
|
.attr("height", (d: Datum) => y(0)! - y(d.count)!)
|
||||||
@ -225,7 +225,7 @@ export function renderButtons(
|
|||||||
.attr(
|
.attr(
|
||||||
"x",
|
"x",
|
||||||
(d: Datum) =>
|
(d: Datum) =>
|
||||||
xGroup(d.group)! + xButton(d.buttonNum.toString())!
|
xGroup(d.group)! + xButton(d.buttonNum.toString())!,
|
||||||
)
|
)
|
||||||
.attr("y", y(0)!)
|
.attr("y", y(0)!)
|
||||||
.attr("height", 0)
|
.attr("height", 0)
|
||||||
@ -233,8 +233,8 @@ export function renderButtons(
|
|||||||
(update) => update.call(updateBar),
|
(update) => update.call(updateBar),
|
||||||
(remove) =>
|
(remove) =>
|
||||||
remove.call((remove) =>
|
remove.call((remove) =>
|
||||||
remove.transition(trans).attr("height", 0).attr("y", y(0)!)
|
remove.transition(trans).attr("height", 0).attr("y", y(0)!),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// hover/tooltip
|
// hover/tooltip
|
||||||
|
@ -54,7 +54,7 @@ const Weekday = Stats.GraphPreferences.Weekday; /* enum */
|
|||||||
|
|
||||||
export function gatherData(
|
export function gatherData(
|
||||||
data: Stats.GraphsResponse,
|
data: Stats.GraphsResponse,
|
||||||
firstDayOfWeek: WeekdayType
|
firstDayOfWeek: WeekdayType,
|
||||||
): GraphData {
|
): GraphData {
|
||||||
const reviewCount = new Map<number, number>();
|
const reviewCount = new Map<number, number>();
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ export function gatherData(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const day = Math.ceil(
|
const day = Math.ceil(
|
||||||
((review.id as number) / 1000 - data.nextDayAtSecs) / 86400
|
((review.id as number) / 1000 - data.nextDayAtSecs) / 86400,
|
||||||
);
|
);
|
||||||
const count = reviewCount.get(day) ?? 0;
|
const count = reviewCount.get(day) ?? 0;
|
||||||
reviewCount.set(day, count + 1);
|
reviewCount.set(day, count + 1);
|
||||||
@ -86,7 +86,7 @@ export function renderCalendar(
|
|||||||
targetYear: number,
|
targetYear: number,
|
||||||
nightMode: boolean,
|
nightMode: boolean,
|
||||||
revlogRange: RevlogRange,
|
revlogRange: RevlogRange,
|
||||||
setFirstDayOfWeek: (d: number) => void
|
setFirstDayOfWeek: (d: number) => void,
|
||||||
): void {
|
): void {
|
||||||
const svg = select(svgElem);
|
const svg = select(svgElem);
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
@ -187,8 +187,8 @@ export function renderCalendar(
|
|||||||
.on("click", null)
|
.on("click", null)
|
||||||
.filter((d: number) =>
|
.filter((d: number) =>
|
||||||
[Weekday.SUNDAY, Weekday.MONDAY, Weekday.FRIDAY, Weekday.SATURDAY].includes(
|
[Weekday.SUNDAY, Weekday.MONDAY, Weekday.FRIDAY, Weekday.SATURDAY].includes(
|
||||||
d
|
d,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.on("click", (_event: MouseEvent, d: number) => setFirstDayOfWeek(d));
|
.on("click", (_event: MouseEvent, d: number) => setFirstDayOfWeek(d));
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ function countCards(cards: Cards.ICard[], separateInactive: boolean): Count[] {
|
|||||||
|
|
||||||
export function gatherData(
|
export function gatherData(
|
||||||
data: Stats.GraphsResponse,
|
data: Stats.GraphsResponse,
|
||||||
separateInactive: boolean
|
separateInactive: boolean,
|
||||||
): GraphData {
|
): GraphData {
|
||||||
const totalCards = data.cards.length;
|
const totalCards = data.cards.length;
|
||||||
const counts = countCards(data.cards, separateInactive);
|
const counts = countCards(data.cards, separateInactive);
|
||||||
@ -158,7 +158,7 @@ export interface TableDatum {
|
|||||||
export function renderCards(
|
export function renderCards(
|
||||||
svgElem: SVGElement,
|
svgElem: SVGElement,
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
sourceData: GraphData
|
sourceData: GraphData,
|
||||||
): TableDatum[] {
|
): TableDatum[] {
|
||||||
const summed = cumsum(sourceData.counts, (d: Count) => d[1]);
|
const summed = cumsum(sourceData.counts, (d: Count) => d[1]);
|
||||||
const data = Array.from(summed).map((n, idx) => {
|
const data = Array.from(summed).map((n, idx) => {
|
||||||
@ -200,12 +200,12 @@ export function renderCards(
|
|||||||
d.transition(trans).attrTween("d", (d) => {
|
d.transition(trans).attrTween("d", (d) => {
|
||||||
const interpolator = interpolate(
|
const interpolator = interpolate(
|
||||||
{ startAngle: 0, endAngle: 0 },
|
{ startAngle: 0, endAngle: 0 },
|
||||||
d
|
d,
|
||||||
);
|
);
|
||||||
return (t): string => arcGen(interpolator(t) as any) as string;
|
return (t): string => arcGen(interpolator(t) as any) as string;
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
x.range([bounds.marginLeft, bounds.width - bounds.marginRight]);
|
x.range([bounds.marginLeft, bounds.width - bounds.marginRight]);
|
||||||
|
@ -46,7 +46,7 @@ function makeQuery(start: number, end: number): string {
|
|||||||
function getAdjustedScaleAndTicks(
|
function getAdjustedScaleAndTicks(
|
||||||
min: number,
|
min: number,
|
||||||
max: number,
|
max: number,
|
||||||
desiredBars: number
|
desiredBars: number,
|
||||||
): [ScaleLinear<number, number, never>, number[]] {
|
): [ScaleLinear<number, number, never>, number[]] {
|
||||||
const prescale = scaleLinear().domain([min, max]).nice();
|
const prescale = scaleLinear().domain([min, max]).nice();
|
||||||
const ticks = prescale.ticks(desiredBars);
|
const ticks = prescale.ticks(desiredBars);
|
||||||
@ -70,7 +70,7 @@ function getAdjustedScaleAndTicks(
|
|||||||
export function prepareData(
|
export function prepareData(
|
||||||
data: GraphData,
|
data: GraphData,
|
||||||
dispatch: SearchDispatch,
|
dispatch: SearchDispatch,
|
||||||
browserLinksSupported: boolean
|
browserLinksSupported: boolean,
|
||||||
): [HistogramData | null, TableDatum[]] {
|
): [HistogramData | null, TableDatum[]] {
|
||||||
// get min/max
|
// get min/max
|
||||||
const allEases = data.eases;
|
const allEases = data.eases;
|
||||||
|
@ -66,7 +66,7 @@ export function gatherData(data: Stats.GraphsResponse): GraphData {
|
|||||||
const dueCounts = rollup(
|
const dueCounts = rollup(
|
||||||
due,
|
due,
|
||||||
(v) => v.length,
|
(v) => v.length,
|
||||||
(d) => d
|
(d) => d,
|
||||||
);
|
);
|
||||||
return { dueCounts, haveBacklog };
|
return { dueCounts, haveBacklog };
|
||||||
}
|
}
|
||||||
@ -95,7 +95,7 @@ export function buildHistogram(
|
|||||||
range: GraphRange,
|
range: GraphRange,
|
||||||
backlog: boolean,
|
backlog: boolean,
|
||||||
dispatch: SearchDispatch,
|
dispatch: SearchDispatch,
|
||||||
browserLinksSupported: boolean
|
browserLinksSupported: boolean,
|
||||||
): FutureDueResponse {
|
): FutureDueResponse {
|
||||||
const output = { histogramData: null, tableData: [] };
|
const output = { histogramData: null, tableData: [] };
|
||||||
// get min/max
|
// get min/max
|
||||||
@ -143,7 +143,7 @@ export function buildHistogram(
|
|||||||
|
|
||||||
const adjustedRange = scaleLinear().range([0.7, 0.3]);
|
const adjustedRange = scaleLinear().range([0.7, 0.3]);
|
||||||
const colourScale = scaleSequential((n) =>
|
const colourScale = scaleSequential((n) =>
|
||||||
interpolateGreens(adjustedRange(n)!)
|
interpolateGreens(adjustedRange(n)!),
|
||||||
).domain([xMin!, xMax!]);
|
).domain([xMin!, xMax!]);
|
||||||
|
|
||||||
const total = sum(bins as any, binValue);
|
const total = sum(bins as any, binValue);
|
||||||
@ -151,7 +151,7 @@ export function buildHistogram(
|
|||||||
function hoverText(
|
function hoverText(
|
||||||
bin: Bin<number, number>,
|
bin: Bin<number, number>,
|
||||||
cumulative: number,
|
cumulative: number,
|
||||||
_percent: number
|
_percent: number,
|
||||||
): string {
|
): string {
|
||||||
const days = dayLabel(bin.x0!, bin.x1!);
|
const days = dayLabel(bin.x0!, bin.x1!);
|
||||||
const cards = tr.statisticsCardsDue({
|
const cards = tr.statisticsCardsDue({
|
||||||
|
@ -56,7 +56,7 @@ export function defaultGraphBounds(): GraphBounds {
|
|||||||
|
|
||||||
export function setDataAvailable(
|
export function setDataAvailable(
|
||||||
svg: Selection<SVGElement, any, any, any>,
|
svg: Selection<SVGElement, any, any, any>,
|
||||||
available: boolean
|
available: boolean,
|
||||||
): void {
|
): void {
|
||||||
svg.select(".no-data")
|
svg.select(".no-data")
|
||||||
.attr("pointer-events", available ? "none" : "all")
|
.attr("pointer-events", available ? "none" : "all")
|
||||||
@ -67,7 +67,7 @@ export function setDataAvailable(
|
|||||||
|
|
||||||
export function millisecondCutoffForRange(
|
export function millisecondCutoffForRange(
|
||||||
range: GraphRange,
|
range: GraphRange,
|
||||||
nextDayAtSecs: number
|
nextDayAtSecs: number,
|
||||||
): number {
|
): number {
|
||||||
let days;
|
let days;
|
||||||
switch (range) {
|
switch (range) {
|
||||||
@ -96,5 +96,5 @@ export interface TableDatum {
|
|||||||
export type SearchEventMap = { search: { query: string } };
|
export type SearchEventMap = { search: { query: string } };
|
||||||
export type SearchDispatch = <EventKey extends Extract<keyof SearchEventMap, string>>(
|
export type SearchDispatch = <EventKey extends Extract<keyof SearchEventMap, string>>(
|
||||||
type: EventKey,
|
type: EventKey,
|
||||||
detail: SearchEventMap[EventKey]
|
detail: SearchEventMap[EventKey],
|
||||||
) => void;
|
) => void;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
],
|
],
|
||||||
{
|
{
|
||||||
controller: anki.RangeBox,
|
controller: anki.RangeBox,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -31,7 +31,7 @@ export interface HistogramData {
|
|||||||
hoverText: (
|
hoverText: (
|
||||||
bin: Bin<number, number>,
|
bin: Bin<number, number>,
|
||||||
cumulative: number,
|
cumulative: number,
|
||||||
percent: number
|
percent: number,
|
||||||
) => string;
|
) => string;
|
||||||
onClick: ((data: Bin<number, number>) => void) | null;
|
onClick: ((data: Bin<number, number>) => void) | null;
|
||||||
showArea: boolean;
|
showArea: boolean;
|
||||||
@ -43,7 +43,7 @@ export interface HistogramData {
|
|||||||
export function histogramGraph(
|
export function histogramGraph(
|
||||||
svgElem: SVGElement,
|
svgElem: SVGElement,
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
data: HistogramData | null
|
data: HistogramData | null,
|
||||||
): void {
|
): void {
|
||||||
const svg = select(svgElem);
|
const svg = select(svgElem);
|
||||||
const trans = svg.transition().duration(600) as any;
|
const trans = svg.transition().duration(600) as any;
|
||||||
@ -64,8 +64,8 @@ export function histogramGraph(
|
|||||||
axisBottom(x)
|
axisBottom(x)
|
||||||
.ticks(7)
|
.ticks(7)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0)
|
||||||
.tickFormat((data.xTickFormat ?? null) as any)
|
.tickFormat((data.xTickFormat ?? null) as any),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -81,8 +81,8 @@ export function histogramGraph(
|
|||||||
selection.transition(trans).call(
|
selection.transition(trans).call(
|
||||||
axisLeft(y)
|
axisLeft(y)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -118,8 +118,8 @@ export function histogramGraph(
|
|||||||
(update) => update.call(updateBar),
|
(update) => update.call(updateBar),
|
||||||
(remove) =>
|
(remove) =>
|
||||||
remove.call((remove) =>
|
remove.call((remove) =>
|
||||||
remove.transition(trans).attr("height", 0).attr("y", y(0)!)
|
remove.transition(trans).attr("height", 0).attr("y", y(0)!),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// cumulative area
|
// cumulative area
|
||||||
@ -135,8 +135,8 @@ export function histogramGraph(
|
|||||||
selection.transition(trans).call(
|
selection.transition(trans).call(
|
||||||
axisRight(yAreaScale)
|
axisRight(yAreaScale)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -154,12 +154,12 @@ export function histogramGraph(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.y0(bounds.height - bounds.marginBottom)
|
.y0(bounds.height - bounds.marginBottom)
|
||||||
.y1((d: any) => yAreaScale(d)!) as any
|
.y1((d: any) => yAreaScale(d)!) as any,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hoverData: [Bin<number, number>, number][] = data.bins.map(
|
const hoverData: [Bin<number, number>, number][] = data.bins.map(
|
||||||
(bin: Bin<number, number>, index: number) => [bin, areaData[index + 1]]
|
(bin: Bin<number, number>, index: number) => [bin, areaData[index + 1]],
|
||||||
);
|
);
|
||||||
|
|
||||||
// hover/tooltip
|
// hover/tooltip
|
||||||
|
@ -60,7 +60,7 @@ function gatherData(data: Stats.GraphsResponse, range: GraphRange): Hour[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const hour = Math.floor(
|
const hour = Math.floor(
|
||||||
(((review.id as number) / 1000 + data.localOffsetSecs) / 3600) % 24
|
(((review.id as number) / 1000 + data.localOffsetSecs) / 3600) % 24,
|
||||||
);
|
);
|
||||||
hours[hour].totalCount += 1;
|
hours[hour].totalCount += 1;
|
||||||
if (review.buttonChosen != 1) {
|
if (review.buttonChosen != 1) {
|
||||||
@ -75,7 +75,7 @@ export function renderHours(
|
|||||||
svgElem: SVGElement,
|
svgElem: SVGElement,
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
origData: Stats.GraphsResponse,
|
origData: Stats.GraphsResponse,
|
||||||
range: GraphRange
|
range: GraphRange,
|
||||||
): void {
|
): void {
|
||||||
const data = gatherData(origData, range);
|
const data = gatherData(origData, range);
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ export function renderHours(
|
|||||||
.paddingInner(0.1);
|
.paddingInner(0.1);
|
||||||
svg.select<SVGGElement>(".x-ticks")
|
svg.select<SVGGElement>(".x-ticks")
|
||||||
.call((selection) =>
|
.call((selection) =>
|
||||||
selection.transition(trans).call(axisBottom(x).tickSizeOuter(0))
|
selection.transition(trans).call(axisBottom(x).tickSizeOuter(0)),
|
||||||
)
|
)
|
||||||
.selectAll(".tick")
|
.selectAll(".tick")
|
||||||
.selectAll("text")
|
.selectAll("text")
|
||||||
@ -121,8 +121,8 @@ export function renderHours(
|
|||||||
selection.transition(trans).call(
|
selection.transition(trans).call(
|
||||||
axisLeft(y)
|
axisLeft(y)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -156,8 +156,8 @@ export function renderHours(
|
|||||||
(update) => update.call(updateBar),
|
(update) => update.call(updateBar),
|
||||||
(remove) =>
|
(remove) =>
|
||||||
remove.call((remove) =>
|
remove.call((remove) =>
|
||||||
remove.transition(trans).attr("height", 0).attr("y", y(0)!)
|
remove.transition(trans).attr("height", 0).attr("y", y(0)!),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
svg.select<SVGGElement>(".y2-ticks")
|
svg.select<SVGGElement>(".y2-ticks")
|
||||||
@ -166,8 +166,8 @@ export function renderHours(
|
|||||||
axisRight(yArea)
|
axisRight(yArea)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickFormat((n: any) => `${Math.round(n * 100)}%`)
|
.tickFormat((n: any) => `${Math.round(n * 100)}%`)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -185,7 +185,7 @@ export function renderHours(
|
|||||||
.y1((d: Hour) => {
|
.y1((d: Hour) => {
|
||||||
const correctRatio = d.correctCount! / d.totalCount!;
|
const correctRatio = d.correctCount! / d.totalCount!;
|
||||||
return yArea(isNaN(correctRatio) ? 0 : correctRatio)!;
|
return yArea(isNaN(correctRatio) ? 0 : correctRatio)!;
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
function tooltipText(d: Hour): string {
|
function tooltipText(d: Hour): string {
|
||||||
|
@ -29,7 +29,7 @@ export function graphs(
|
|||||||
search = "deck:current",
|
search = "deck:current",
|
||||||
days = 365,
|
days = 365,
|
||||||
controller = null as SvelteComponent | null,
|
controller = null as SvelteComponent | null,
|
||||||
} = {}
|
} = {},
|
||||||
): void {
|
): void {
|
||||||
const nightMode = checkNightMode();
|
const nightMode = checkNightMode();
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ export function gatherIntervalData(data: Stats.GraphsResponse): IntervalGraphDat
|
|||||||
export function intervalLabel(
|
export function intervalLabel(
|
||||||
daysStart: number,
|
daysStart: number,
|
||||||
daysEnd: number,
|
daysEnd: number,
|
||||||
cards: number
|
cards: number,
|
||||||
): string {
|
): string {
|
||||||
if (daysEnd - daysStart <= 1) {
|
if (daysEnd - daysStart <= 1) {
|
||||||
// singular
|
// singular
|
||||||
@ -79,7 +79,7 @@ export function prepareIntervalData(
|
|||||||
data: IntervalGraphData,
|
data: IntervalGraphData,
|
||||||
range: IntervalRange,
|
range: IntervalRange,
|
||||||
dispatch: SearchDispatch,
|
dispatch: SearchDispatch,
|
||||||
browserLinksSupported: boolean
|
browserLinksSupported: boolean,
|
||||||
): [HistogramData | null, TableDatum[]] {
|
): [HistogramData | null, TableDatum[]] {
|
||||||
// get min/max
|
// get min/max
|
||||||
const allIntervals = data.intervals;
|
const allIntervals = data.intervals;
|
||||||
@ -122,7 +122,7 @@ export function prepareIntervalData(
|
|||||||
|
|
||||||
const prescale = scaleLinear().domain([xMin!, xMax!]);
|
const prescale = scaleLinear().domain([xMin!, xMax!]);
|
||||||
const scale = scaleLinear().domain(
|
const scale = scaleLinear().domain(
|
||||||
(niceNecessary ? prescale.nice() : prescale).domain().map(increment)
|
(niceNecessary ? prescale.nice() : prescale).domain().map(increment),
|
||||||
);
|
);
|
||||||
|
|
||||||
const bins = histogram()
|
const bins = histogram()
|
||||||
@ -137,13 +137,13 @@ export function prepareIntervalData(
|
|||||||
|
|
||||||
const adjustedRange = scaleLinear().range([0.7, 0.3]);
|
const adjustedRange = scaleLinear().range([0.7, 0.3]);
|
||||||
const colourScale = scaleSequential((n) =>
|
const colourScale = scaleSequential((n) =>
|
||||||
interpolateBlues(adjustedRange(n)!)
|
interpolateBlues(adjustedRange(n)!),
|
||||||
).domain([xMax!, xMin!]);
|
).domain([xMax!, xMin!]);
|
||||||
|
|
||||||
function hoverText(
|
function hoverText(
|
||||||
bin: Bin<number, number>,
|
bin: Bin<number, number>,
|
||||||
_cumulative: number,
|
_cumulative: number,
|
||||||
percent: number
|
percent: number,
|
||||||
): string {
|
): string {
|
||||||
// const day = dayLabel(bin.x0!, bin.x1!);
|
// const day = dayLabel(bin.x0!, bin.x1!);
|
||||||
const interval = intervalLabel(bin.x0!, bin.x1!, bin.length);
|
const interval = intervalLabel(bin.x0!, bin.x1!, bin.length);
|
||||||
|
@ -65,7 +65,7 @@ export function gatherData(data: Stats.GraphsResponse): GraphData {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const day = Math.ceil(
|
const day = Math.ceil(
|
||||||
((review.id as number) / 1000 - data.nextDayAtSecs) / 86400
|
((review.id as number) / 1000 - data.nextDayAtSecs) / 86400,
|
||||||
);
|
);
|
||||||
const countEntry =
|
const countEntry =
|
||||||
reviewCount.get(day) ?? reviewCount.set(day, { ...empty }).get(day)!;
|
reviewCount.get(day) ?? reviewCount.set(day, { ...empty }).get(day)!;
|
||||||
@ -131,7 +131,7 @@ export function renderReviews(
|
|||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
sourceData: GraphData,
|
sourceData: GraphData,
|
||||||
range: GraphRange,
|
range: GraphRange,
|
||||||
showTime: boolean
|
showTime: boolean,
|
||||||
): TableDatum[] {
|
): TableDatum[] {
|
||||||
const svg = select(svgElem);
|
const svg = select(svgElem);
|
||||||
const trans = svg.transition().duration(600) as any;
|
const trans = svg.transition().duration(600) as any;
|
||||||
@ -178,7 +178,7 @@ export function renderReviews(
|
|||||||
x.range([bounds.marginLeft, bounds.width - bounds.marginRight]);
|
x.range([bounds.marginLeft, bounds.width - bounds.marginRight]);
|
||||||
svg.select<SVGGElement>(".x-ticks")
|
svg.select<SVGGElement>(".x-ticks")
|
||||||
.call((selection) =>
|
.call((selection) =>
|
||||||
selection.transition(trans).call(axisBottom(x).ticks(7).tickSizeOuter(0))
|
selection.transition(trans).call(axisBottom(x).ticks(7).tickSizeOuter(0)),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -207,8 +207,8 @@ export function renderReviews(
|
|||||||
axisLeft(y)
|
axisLeft(y)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0)
|
||||||
.tickFormat(yTickFormat as any)
|
.tickFormat(yTickFormat as any),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -222,19 +222,19 @@ export function renderReviews(
|
|||||||
const cappedRange = scaleLinear().range([0.3, 0.5]);
|
const cappedRange = scaleLinear().range([0.3, 0.5]);
|
||||||
const shiftedRange = scaleLinear().range([0.4, 0.7]);
|
const shiftedRange = scaleLinear().range([0.4, 0.7]);
|
||||||
const darkerGreens = scaleSequential((n) =>
|
const darkerGreens = scaleSequential((n) =>
|
||||||
interpolateGreens(shiftedRange(n)!)
|
interpolateGreens(shiftedRange(n)!),
|
||||||
).domain(x.domain() as any);
|
).domain(x.domain() as any);
|
||||||
const lighterGreens = scaleSequential((n) =>
|
const lighterGreens = scaleSequential((n) =>
|
||||||
interpolateGreens(cappedRange(n)!)
|
interpolateGreens(cappedRange(n)!),
|
||||||
).domain(x.domain() as any);
|
).domain(x.domain() as any);
|
||||||
const reds = scaleSequential((n) => interpolateReds(cappedRange(n)!)).domain(
|
const reds = scaleSequential((n) => interpolateReds(cappedRange(n)!)).domain(
|
||||||
x.domain() as any
|
x.domain() as any,
|
||||||
);
|
);
|
||||||
const oranges = scaleSequential((n) => interpolateOranges(cappedRange(n)!)).domain(
|
const oranges = scaleSequential((n) => interpolateOranges(cappedRange(n)!)).domain(
|
||||||
x.domain() as any
|
x.domain() as any,
|
||||||
);
|
);
|
||||||
const purples = scaleSequential((n) => interpolatePurples(cappedRange(n)!)).domain(
|
const purples = scaleSequential((n) => interpolatePurples(cappedRange(n)!)).domain(
|
||||||
x.domain() as any
|
x.domain() as any,
|
||||||
);
|
);
|
||||||
|
|
||||||
function binColor(idx: BinIndex): ScaleSequential<string> {
|
function binColor(idx: BinIndex): ScaleSequential<string> {
|
||||||
@ -317,8 +317,8 @@ export function renderReviews(
|
|||||||
(update) => update.call((d) => updateBar(d, barNum)),
|
(update) => update.call((d) => updateBar(d, barNum)),
|
||||||
(remove) =>
|
(remove) =>
|
||||||
remove.call((remove) =>
|
remove.call((remove) =>
|
||||||
remove.transition(trans).attr("height", 0).attr("y", y(0)!)
|
remove.transition(trans).attr("height", 0).attr("y", y(0)!),
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -337,8 +337,8 @@ export function renderReviews(
|
|||||||
axisRight(yAreaScale)
|
axisRight(yAreaScale)
|
||||||
.ticks(bounds.height / 50)
|
.ticks(bounds.height / 50)
|
||||||
.tickFormat(yTickFormat as any)
|
.tickFormat(yTickFormat as any)
|
||||||
.tickSizeOuter(0)
|
.tickSizeOuter(0),
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
|
|
||||||
@ -356,12 +356,12 @@ export function renderReviews(
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.y0(bounds.height - bounds.marginBottom)
|
.y0(bounds.height - bounds.marginBottom)
|
||||||
.y1((d: any) => yAreaScale(d)!) as any
|
.y1((d: any) => yAreaScale(d)!) as any,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const hoverData: [Bin<number, number>, number][] = bins.map(
|
const hoverData: [Bin<number, number>, number][] = bins.map(
|
||||||
(bin: Bin<number, number>, index: number) => [bin, areaData[index + 1]]
|
(bin: Bin<number, number>, index: number) => [bin, areaData[index + 1]],
|
||||||
);
|
);
|
||||||
|
|
||||||
// hover/tooltip
|
// hover/tooltip
|
||||||
|
@ -74,7 +74,7 @@ export function gatherData(data: Stats.GraphsResponse): TodayData {
|
|||||||
const againCount = answerCount - correctCount;
|
const againCount = answerCount - correctCount;
|
||||||
let againCountText = tr.statisticsTodayAgainCount();
|
let againCountText = tr.statisticsTodayAgainCount();
|
||||||
againCountText += ` ${againCount} (${((againCount / answerCount) * 100).toFixed(
|
againCountText += ` ${againCount} (${((againCount / answerCount) * 100).toFixed(
|
||||||
2
|
2,
|
||||||
)}%)`;
|
)}%)`;
|
||||||
const typeCounts = tr.statisticsTodayTypeCounts({
|
const typeCounts = tr.statisticsTodayTypeCounts({
|
||||||
learnCount,
|
learnCount,
|
||||||
|
@ -17,7 +17,7 @@ type FilterMethod = (element: Element) => void;
|
|||||||
|
|
||||||
function filterAttributes(
|
function filterAttributes(
|
||||||
attributePredicate: (attributeName: string) => boolean,
|
attributePredicate: (attributeName: string) => boolean,
|
||||||
element: Element
|
element: Element,
|
||||||
): void {
|
): void {
|
||||||
for (const attr of [...element.attributes]) {
|
for (const attr of [...element.attributes]) {
|
||||||
const attrName = attr.name.toUpperCase();
|
const attrName = attr.name.toUpperCase();
|
||||||
@ -37,7 +37,7 @@ const allow =
|
|||||||
(element: Element): void =>
|
(element: Element): void =>
|
||||||
filterAttributes(
|
filterAttributes(
|
||||||
(attributeName: string) => attrs.includes(attributeName),
|
(attributeName: string) => attrs.includes(attributeName),
|
||||||
element
|
element,
|
||||||
);
|
);
|
||||||
|
|
||||||
function unwrapElement(element: Element): void {
|
function unwrapElement(element: Element): void {
|
||||||
|
@ -7,7 +7,7 @@ export function removeNode(element: Node): void {
|
|||||||
|
|
||||||
function iterateElement(
|
function iterateElement(
|
||||||
filter: (node: Node) => void,
|
filter: (node: Node) => void,
|
||||||
fragment: DocumentFragment | Element
|
fragment: DocumentFragment | Element,
|
||||||
): void {
|
): void {
|
||||||
for (const child of [...fragment.childNodes]) {
|
for (const child of [...fragment.childNodes]) {
|
||||||
filter(child);
|
filter(child);
|
||||||
|
@ -51,9 +51,9 @@ const filterStyling =
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const filterStylingNightMode = filterStyling(
|
export const filterStylingNightMode = filterStyling(
|
||||||
allowPropertiesBlockValues(stylingNightMode)
|
allowPropertiesBlockValues(stylingNightMode),
|
||||||
);
|
);
|
||||||
export const filterStylingLightMode = filterStyling(
|
export const filterStylingLightMode = filterStyling(
|
||||||
allowPropertiesBlockValues(stylingLightMode)
|
allowPropertiesBlockValues(stylingLightMode),
|
||||||
);
|
);
|
||||||
export const filterStylingInternal = filterStyling(blockProperties(stylingInternal));
|
export const filterStylingInternal = filterStyling(blockProperties(stylingInternal));
|
||||||
|
@ -106,7 +106,7 @@ const isListItem = (element: Element): element is HTMLLIElement =>
|
|||||||
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);
|
||||||
|
|
||||||
|
@ -21,19 +21,19 @@ function toFluentNumber(num: number): FluentNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatArgs(
|
function formatArgs(
|
||||||
args: Record<string, FluentVariable>
|
args: Record<string, FluentVariable>,
|
||||||
): Record<string, FluentVariable> {
|
): Record<string, FluentVariable> {
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(args).map(([key, value]) => [
|
Object.entries(args).map(([key, value]) => [
|
||||||
key,
|
key,
|
||||||
typeof value === "number" ? toFluentNumber(value) : value,
|
typeof value === "number" ? toFluentNumber(value) : value,
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMessage(
|
export function getMessage(
|
||||||
key: string,
|
key: string,
|
||||||
args: Record<string, FluentVariable> = {}
|
args: Record<string, FluentVariable> = {},
|
||||||
): string | null {
|
): string | null {
|
||||||
for (const bundle of bundles) {
|
for (const bundle of bundles) {
|
||||||
const msg = bundle.getMessage(key);
|
const msg = bundle.getMessage(key);
|
||||||
|
@ -43,7 +43,7 @@ let langs: string[] = [];
|
|||||||
|
|
||||||
export function toLocaleString(
|
export function toLocaleString(
|
||||||
date: Date,
|
date: Date,
|
||||||
options?: Intl.DateTimeFormatOptions
|
options?: Intl.DateTimeFormatOptions,
|
||||||
): string {
|
): string {
|
||||||
return date.toLocaleDateString(langs, options);
|
return date.toLocaleDateString(langs, options);
|
||||||
}
|
}
|
||||||
@ -51,7 +51,7 @@ export function toLocaleString(
|
|||||||
export function localeCompare(
|
export function localeCompare(
|
||||||
first: string,
|
first: string,
|
||||||
second: string,
|
second: string,
|
||||||
options?: Intl.CollatorOptions
|
options?: Intl.CollatorOptions,
|
||||||
): number {
|
): number {
|
||||||
return first.localeCompare(second, langs, options);
|
return first.localeCompare(second, langs, options);
|
||||||
}
|
}
|
||||||
|
@ -23,13 +23,13 @@ export const checkModifiers =
|
|||||||
(
|
(
|
||||||
matches: boolean,
|
matches: boolean,
|
||||||
currentModifier: Modifier,
|
currentModifier: Modifier,
|
||||||
currentIndex: number
|
currentIndex: number,
|
||||||
): boolean =>
|
): boolean =>
|
||||||
matches &&
|
matches &&
|
||||||
(optional.includes(currentModifier as Modifier) ||
|
(optional.includes(currentModifier as Modifier) ||
|
||||||
event.getModifierState(platformModifiers[currentIndex]) ===
|
event.getModifierState(platformModifiers[currentIndex]) ===
|
||||||
required.includes(currentModifier)),
|
required.includes(currentModifier)),
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
export async function postRequest(
|
export async function postRequest(
|
||||||
path: string,
|
path: string,
|
||||||
body: string | Uint8Array,
|
body: string | Uint8Array,
|
||||||
headers: Record<string, string> = {}
|
headers: Record<string, string> = {},
|
||||||
): Promise<Uint8Array> {
|
): Promise<Uint8Array> {
|
||||||
if (body instanceof Uint8Array) {
|
if (body instanceof Uint8Array) {
|
||||||
headers["Content-type"] = "application/octet-stream";
|
headers["Content-type"] = "application/octet-stream";
|
||||||
|
@ -21,7 +21,7 @@ export function unwrapOptionalNumber(
|
|||||||
| Generic.OptionalInt32
|
| Generic.OptionalInt32
|
||||||
| Generic.OptionalUInt32
|
| Generic.OptionalUInt32
|
||||||
| null
|
| null
|
||||||
| undefined
|
| undefined,
|
||||||
): number | undefined {
|
): number | undefined {
|
||||||
if (msg && msg !== null) {
|
if (msg && msg !== null) {
|
||||||
if (msg.val !== null) {
|
if (msg.val !== null) {
|
||||||
|
@ -8,7 +8,7 @@ const prohibit = () => false;
|
|||||||
export function registerPackage(
|
export function registerPackage(
|
||||||
name: string,
|
name: string,
|
||||||
entries: Record<string, unknown>,
|
entries: Record<string, unknown>,
|
||||||
deprecation?: Record<string, string>
|
deprecation?: Record<string, string>,
|
||||||
): void {
|
): void {
|
||||||
const pack = deprecation
|
const pack = deprecation
|
||||||
? new Proxy(entries, {
|
? new Proxy(entries, {
|
||||||
@ -36,7 +36,7 @@ function hasPackages(...names: string[]): boolean {
|
|||||||
const libraries = listPackages();
|
const libraries = listPackages();
|
||||||
return names.reduce(
|
return names.reduce(
|
||||||
(accu: boolean, name: string) => accu && libraries.includes(name),
|
(accu: boolean, name: string) => accu && libraries.includes(name),
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,5 +53,5 @@ registerPackage(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
[immediatelyDeprecated.name]: "Do not use this function",
|
[immediatelyDeprecated.name]: "Do not use this function",
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
@ -47,7 +47,7 @@ function splitKeyCombinationString(keyCombinationString: string): string[][] {
|
|||||||
function toPlatformString(keyCombination: string[]): string {
|
function toPlatformString(keyCombination: string[]): string {
|
||||||
return (
|
return (
|
||||||
modifiersToPlatformString(
|
modifiersToPlatformString(
|
||||||
keyCombination.slice(0, -1).filter(isRequiredModifier)
|
keyCombination.slice(0, -1).filter(isRequiredModifier),
|
||||||
) + keyToPlatformString(keyCombination[keyCombination.length - 1])
|
) + keyToPlatformString(keyCombination[keyCombination.length - 1])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -80,11 +80,11 @@ function removeTrailing(modifier: string): string {
|
|||||||
|
|
||||||
// function checkModifiers(event: KeyboardEvent, modifiers: string[]): boolean {
|
// function checkModifiers(event: KeyboardEvent, modifiers: string[]): boolean {
|
||||||
function separateRequiredOptionalModifiers(
|
function separateRequiredOptionalModifiers(
|
||||||
modifiers: string[]
|
modifiers: string[],
|
||||||
): [Modifier[], Modifier[]] {
|
): [Modifier[], Modifier[]] {
|
||||||
const [requiredModifiers, otherModifiers] = partition(
|
const [requiredModifiers, otherModifiers] = partition(
|
||||||
isRequiredModifier,
|
isRequiredModifier,
|
||||||
modifiers
|
modifiers,
|
||||||
);
|
);
|
||||||
|
|
||||||
const optionalModifiers = otherModifiers.map(removeTrailing);
|
const optionalModifiers = otherModifiers.map(removeTrailing);
|
||||||
@ -104,7 +104,7 @@ function keyToCode(key: string): number {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function keyCombinationToCheck(
|
function keyCombinationToCheck(
|
||||||
keyCombination: string[]
|
keyCombination: string[],
|
||||||
): (event: KeyboardEvent) => boolean {
|
): (event: KeyboardEvent) => boolean {
|
||||||
const keyCode = keyToCode(keyCombination[keyCombination.length - 1]);
|
const keyCode = keyToCode(keyCombination[keyCombination.length - 1]);
|
||||||
const modifiers = keyCombination.slice(0, -1);
|
const modifiers = keyCombination.slice(0, -1);
|
||||||
@ -147,7 +147,7 @@ function innerShortcut(
|
|||||||
export function registerShortcut(
|
export function registerShortcut(
|
||||||
callback: (event: KeyboardEvent) => void,
|
callback: (event: KeyboardEvent) => void,
|
||||||
keyCombinationString: string,
|
keyCombinationString: string,
|
||||||
target: EventTarget | Document = document
|
target: EventTarget | Document = document,
|
||||||
): () => void {
|
): () => void {
|
||||||
const [check, ...restChecks] =
|
const [check, ...restChecks] =
|
||||||
splitKeyCombinationString(keyCombinationString).map(keyCombinationToCheck);
|
splitKeyCombinationString(keyCombinationString).map(keyCombinationToCheck);
|
||||||
|
@ -107,7 +107,7 @@ export function studiedToday(cards: number, secs: number): string {
|
|||||||
|
|
||||||
function i18nFuncForUnit(
|
function i18nFuncForUnit(
|
||||||
unit: TimespanUnit,
|
unit: TimespanUnit,
|
||||||
short: boolean
|
short: boolean,
|
||||||
): ({ amount: number }) => string {
|
): ({ amount: number }) => string {
|
||||||
if (short) {
|
if (short) {
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
|
@ -22,7 +22,7 @@ export function wrapInternal(
|
|||||||
root: DocumentOrShadowRoot,
|
root: DocumentOrShadowRoot,
|
||||||
front: string,
|
front: string,
|
||||||
back: string,
|
back: string,
|
||||||
plainText: boolean
|
plainText: boolean,
|
||||||
): void {
|
): void {
|
||||||
const selection = root.getSelection()!;
|
const selection = root.getSelection()!;
|
||||||
const range = selection.getRangeAt(0);
|
const range = selection.getRangeAt(0);
|
||||||
@ -41,7 +41,7 @@ export function wrapInternal(
|
|||||||
if (
|
if (
|
||||||
!span.innerHTML &&
|
!span.innerHTML &&
|
||||||
/* 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",
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
moveCursorPastPostfix(selection, back);
|
moveCursorPastPostfix(selection, back);
|
||||||
|
@ -6,13 +6,13 @@ import { postRequest } from "../lib/postrequest";
|
|||||||
|
|
||||||
async function getNextStates(): Promise<Scheduler.NextCardStates> {
|
async function getNextStates(): Promise<Scheduler.NextCardStates> {
|
||||||
return Scheduler.NextCardStates.decode(
|
return Scheduler.NextCardStates.decode(
|
||||||
await postRequest("/_anki/nextCardStates", "")
|
await postRequest("/_anki/nextCardStates", ""),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setNextStates(
|
async function setNextStates(
|
||||||
key: string,
|
key: string,
|
||||||
states: Scheduler.NextCardStates
|
states: Scheduler.NextCardStates,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const data: Uint8Array = Scheduler.NextCardStates.encode(states).finish();
|
const data: Uint8Array = Scheduler.NextCardStates.encode(states).finish();
|
||||||
await postRequest("/_anki/setNextCardStates", data, { key });
|
await postRequest("/_anki/setNextCardStates", data, { key });
|
||||||
@ -20,7 +20,7 @@ async function setNextStates(
|
|||||||
|
|
||||||
export async function mutateNextCardStates(
|
export async function mutateNextCardStates(
|
||||||
key: string,
|
key: string,
|
||||||
mutator: (states: Scheduler.NextCardStates) => void
|
mutator: (states: Scheduler.NextCardStates) => void,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const states = await getNextStates();
|
const states = await getNextStates();
|
||||||
mutator(states);
|
mutator(states);
|
||||||
|
@ -11,7 +11,7 @@ function injectPreloadLink(href: string, as: string): void {
|
|||||||
|
|
||||||
export function allImagesLoaded(): Promise<void[]> {
|
export function allImagesLoaded(): Promise<void[]> {
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
Array.from(document.getElementsByTagName("img")).map(imageLoaded)
|
Array.from(document.getElementsByTagName("img")).map(imageLoaded),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ function extractImageSrcs(html: string): string[] {
|
|||||||
tmpl.innerHTML = html;
|
tmpl.innerHTML = html;
|
||||||
const fragment = tmpl.content;
|
const fragment = tmpl.content;
|
||||||
const srcs = [...fragment.querySelectorAll("img[src]")].map(
|
const srcs = [...fragment.querySelectorAll("img[src]")].map(
|
||||||
(img) => (img as HTMLImageElement).src
|
(img) => (img as HTMLImageElement).src,
|
||||||
);
|
);
|
||||||
return srcs;
|
return srcs;
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ export function getTypedAnswer(): string | null {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _runHook(
|
function _runHook(
|
||||||
hooks: Array<Callback>
|
hooks: Array<Callback>,
|
||||||
): Promise<PromiseSettledResult<void | Promise<void>>[]> {
|
): Promise<PromiseSettledResult<void | Promise<void>>[]> {
|
||||||
const promises: (Promise<void> | void)[] = [];
|
const promises: (Promise<void> | void)[] = [];
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ const renderError =
|
|||||||
}
|
}
|
||||||
return `<div>Invalid ${type} on card: ${errorMessage}\n${errorStack}</div>`.replace(
|
return `<div>Invalid ${type} on card: ${errorMessage}\n${errorStack}</div>`.replace(
|
||||||
/\n/g,
|
/\n/g,
|
||||||
"<br>"
|
"<br>",
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ export async function _updateQA(
|
|||||||
html: string,
|
html: string,
|
||||||
_unusused: unknown,
|
_unusused: unknown,
|
||||||
onupdate: Callback,
|
onupdate: Callback,
|
||||||
onshown: Callback
|
onshown: Callback,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
onUpdateHook.length = 0;
|
onUpdateHook.length = 0;
|
||||||
onUpdateHook.push(onupdate);
|
onUpdateHook.push(onupdate);
|
||||||
@ -152,8 +152,8 @@ export function _showQuestion(q: string, a: string, bodyclass: string): void {
|
|||||||
}
|
}
|
||||||
// preload images
|
// preload images
|
||||||
allImagesLoaded().then(() => preloadAnswerImages(q, a));
|
allImagesLoaded().then(() => preloadAnswerImages(q, a));
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,8 +177,8 @@ export function _showAnswer(a: string, bodyclass: string): void {
|
|||||||
},
|
},
|
||||||
function () {
|
function () {
|
||||||
/* noop */
|
/* noop */
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ function formatText(text: string): string {
|
|||||||
for (const keyword of ["type", "fields"]) {
|
for (const keyword of ["type", "fields"]) {
|
||||||
newText = newText.replace(
|
newText = newText.replace(
|
||||||
new RegExp(`\\b${keyword.toUpperCase()}\\b`, "g"),
|
new RegExp(`\\b${keyword.toUpperCase()}\\b`, "g"),
|
||||||
keyword
|
keyword,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return newText;
|
return newText;
|
||||||
|
@ -9,6 +9,6 @@
|
|||||||
// ensure node can run the resulting code
|
// ensure node can run the resulting code
|
||||||
"noEmitHelpers": false,
|
"noEmitHelpers": false,
|
||||||
"importHelpers": false,
|
"importHelpers": false,
|
||||||
"module": "commonjs",
|
"module": "commonjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ const languageServiceHost: ts.LanguageServiceHost = {
|
|||||||
},
|
},
|
||||||
getLength: () => text.length,
|
getLength: () => text.length,
|
||||||
getChangeRange: (
|
getChangeRange: (
|
||||||
_oldSnapshot: ts.IScriptSnapshot
|
_oldSnapshot: ts.IScriptSnapshot,
|
||||||
): ts.TextChangeRange | undefined => {
|
): ts.TextChangeRange | undefined => {
|
||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
@ -140,7 +140,7 @@ function readFile(file) {
|
|||||||
async function compileSingleSvelte(
|
async function compileSingleSvelte(
|
||||||
input: SvelteInput,
|
input: SvelteInput,
|
||||||
binDir: string,
|
binDir: string,
|
||||||
genDir: string
|
genDir: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const preprocessOptions = preprocess({
|
const preprocessOptions = preprocess({
|
||||||
scss: {
|
scss: {
|
||||||
@ -215,7 +215,7 @@ async function extractArgsAndData(args: string[]): Promise<Args> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function extractSvelteAndDeps(
|
async function extractSvelteAndDeps(
|
||||||
files: string[]
|
files: string[],
|
||||||
): Promise<[SvelteInput[], InputFile[]]> {
|
): Promise<[SvelteInput[], InputFile[]]> {
|
||||||
const svelte: SvelteInput[] = [];
|
const svelte: SvelteInput[] = [];
|
||||||
const deps: InputFile[] = [];
|
const deps: InputFile[] = [];
|
||||||
@ -249,7 +249,7 @@ function remapBinToSrcDir(file: string): string {
|
|||||||
async function compileSvelte(
|
async function compileSvelte(
|
||||||
svelte: SvelteInput[],
|
svelte: SvelteInput[],
|
||||||
binDir: string,
|
binDir: string,
|
||||||
genDir: string
|
genDir: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const file of svelte) {
|
for (const file of svelte) {
|
||||||
await compileSingleSvelte(file, binDir, genDir);
|
await compileSingleSvelte(file, binDir, genDir);
|
||||||
|
@ -8,6 +8,6 @@
|
|||||||
// ensure node can run the resulting code
|
// ensure node can run the resulting code
|
||||||
"noEmitHelpers": false,
|
"noEmitHelpers": false,
|
||||||
"importHelpers": false,
|
"importHelpers": false,
|
||||||
"module": "commonjs",
|
"module": "commonjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,13 @@ interface AsyncReactiveData<T, E> {
|
|||||||
|
|
||||||
function useAsyncReactive<T, E>(
|
function useAsyncReactive<T, E>(
|
||||||
asyncFunction: () => Promise<T>,
|
asyncFunction: () => Promise<T>,
|
||||||
dependencies: [Readable<unknown>, ...Readable<unknown>[]]
|
dependencies: [Readable<unknown>, ...Readable<unknown>[]],
|
||||||
): AsyncReactiveData<T, E> {
|
): AsyncReactiveData<T, E> {
|
||||||
const promise = derived(
|
const promise = derived(
|
||||||
dependencies,
|
dependencies,
|
||||||
(_, set: (value: Promise<T> | null) => void): void => set(asyncFunction()),
|
(_, set: (value: Promise<T> | null) => void): void => set(asyncFunction()),
|
||||||
// initialize with null to avoid duplicate fetch on init
|
// initialize with null to avoid duplicate fetch on init
|
||||||
null
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const value = derived(
|
const value = derived(
|
||||||
@ -25,7 +25,7 @@ function useAsyncReactive<T, E>(
|
|||||||
($promise, set: (value: T) => void): void => {
|
($promise, set: (value: T) => void): void => {
|
||||||
$promise?.then((value: T) => set(value));
|
$promise?.then((value: T) => set(value));
|
||||||
},
|
},
|
||||||
null
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const error = derived(
|
const error = derived(
|
||||||
@ -34,7 +34,7 @@ function useAsyncReactive<T, E>(
|
|||||||
$promise?.catch((error: E) => set(error));
|
$promise?.catch((error: E) => set(error));
|
||||||
return (): void => set(null);
|
return (): void => set(null);
|
||||||
},
|
},
|
||||||
null
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const loading = derived(
|
const loading = derived(
|
||||||
@ -43,7 +43,7 @@ function useAsyncReactive<T, E>(
|
|||||||
$promise?.finally(() => set(false));
|
$promise?.finally(() => set(false));
|
||||||
return (): void => set(true);
|
return (): void => set(true);
|
||||||
},
|
},
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
return { value, error, loading };
|
return { value, error, loading };
|
||||||
|
@ -8,7 +8,7 @@ type ContextProperty<T> = [
|
|||||||
// this typing is a lie insofar that calling get
|
// this typing is a lie insofar that calling get
|
||||||
// outside of the component's context will return undefined
|
// outside of the component's context will return undefined
|
||||||
() => T,
|
() => T,
|
||||||
() => boolean
|
() => boolean,
|
||||||
];
|
];
|
||||||
|
|
||||||
function contextProperty<T>(key: symbol): ContextProperty<T> {
|
function contextProperty<T>(key: symbol): ContextProperty<T> {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
import type { SvelteComponentDev } from "svelte/internal";
|
import type { SvelteComponentDev } from "svelte/internal";
|
||||||
|
|
||||||
export interface DynamicSvelteComponent<
|
export interface DynamicSvelteComponent<
|
||||||
T extends typeof SvelteComponentDev = typeof SvelteComponentDev
|
T extends typeof SvelteComponentDev = typeof SvelteComponentDev,
|
||||||
> {
|
> {
|
||||||
component: T;
|
component: T;
|
||||||
[k: string]: unknown;
|
[k: string]: unknown;
|
||||||
@ -12,9 +12,9 @@ export interface DynamicSvelteComponent<
|
|||||||
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 };
|
||||||
|
@ -15,7 +15,7 @@ const config = {
|
|||||||
interface DOMMirror {
|
interface DOMMirror {
|
||||||
mirror(
|
mirror(
|
||||||
element: Element,
|
element: Element,
|
||||||
params: { store: Writable<DocumentFragment> }
|
params: { store: Writable<DocumentFragment> },
|
||||||
): { destroy(): void };
|
): { destroy(): void };
|
||||||
preventResubscription(): () => void;
|
preventResubscription(): () => void;
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ function getDOMMirror(): DOMMirror {
|
|||||||
|
|
||||||
function mirror(
|
function mirror(
|
||||||
element: Element,
|
element: Element,
|
||||||
{ store }: { store: Writable<DocumentFragment> }
|
{ store }: { store: Writable<DocumentFragment> },
|
||||||
): { destroy(): void } {
|
): { destroy(): void } {
|
||||||
function saveHTMLToStore(): void {
|
function saveHTMLToStore(): void {
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
@ -80,7 +80,7 @@ function getDOMMirror(): DOMMirror {
|
|||||||
} else {
|
} else {
|
||||||
element.removeEventListener("blur", subscribe);
|
element.removeEventListener("blur", subscribe);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -14,7 +14,7 @@ export interface NodeStore<T extends Node> extends Writable<T> {
|
|||||||
|
|
||||||
export function nodeStore<T extends Node>(
|
export function nodeStore<T extends Node>(
|
||||||
node?: T,
|
node?: T,
|
||||||
preprocess: (node: T) => void = noop
|
preprocess: (node: T) => void = noop,
|
||||||
): NodeStore<T> {
|
): NodeStore<T> {
|
||||||
const subscribers: Set<Subscriber<T>> = new Set();
|
const subscribers: Set<Subscriber<T>> = new Set();
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ export type PreferenceRaw<T> = {
|
|||||||
|
|
||||||
function createPreference<T>(
|
function createPreference<T>(
|
||||||
initialValue: T,
|
initialValue: T,
|
||||||
savePreferences: () => void
|
savePreferences: () => void,
|
||||||
): CustomStore<T> {
|
): CustomStore<T> {
|
||||||
const { subscribe, set, update } = writable(initialValue);
|
const { subscribe, set, update } = writable(initialValue);
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ function createPreference<T>(
|
|||||||
function preparePreferences<T>(
|
function preparePreferences<T>(
|
||||||
Preferences: T,
|
Preferences: T,
|
||||||
setter: (payload: PreferencePayload<T>) => Promise<void>,
|
setter: (payload: PreferencePayload<T>) => Promise<void>,
|
||||||
toObject: (preferences: T, options: { defaults: boolean }) => PreferenceRaw<T>
|
toObject: (preferences: T, options: { defaults: boolean }) => PreferenceRaw<T>,
|
||||||
): PreferenceStore<T> {
|
): PreferenceStore<T> {
|
||||||
const preferences: Partial<PreferenceStore<T>> = {};
|
const preferences: Partial<PreferenceStore<T>> = {};
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ function preparePreferences<T>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(
|
for (const [key, value] of Object.entries(
|
||||||
toObject(Preferences, { defaults: true })
|
toObject(Preferences, { defaults: true }),
|
||||||
)) {
|
)) {
|
||||||
preferences[key] = createPreference(value, savePreferences);
|
preferences[key] = createPreference(value, savePreferences);
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ function preparePreferences<T>(
|
|||||||
export async function getPreferences<T>(
|
export async function getPreferences<T>(
|
||||||
getter: () => Promise<T>,
|
getter: () => Promise<T>,
|
||||||
setter: (payload: PreferencePayload<T>) => Promise<void>,
|
setter: (payload: PreferencePayload<T>) => Promise<void>,
|
||||||
toObject: (preferences: T, options: { defaults: boolean }) => PreferenceRaw<T>
|
toObject: (preferences: T, options: { defaults: boolean }) => PreferenceRaw<T>,
|
||||||
): Promise<PreferenceStore<T>> {
|
): Promise<PreferenceStore<T>> {
|
||||||
const initialPreferences = await getter();
|
const initialPreferences = await getter();
|
||||||
return preparePreferences(initialPreferences, setter, toObject);
|
return preparePreferences(initialPreferences, setter, toObject);
|
||||||
|
@ -13,7 +13,7 @@ export function shortcut(
|
|||||||
action: (event: KeyboardEvent) => void;
|
action: (event: KeyboardEvent) => void;
|
||||||
keyCombination: string;
|
keyCombination: string;
|
||||||
target?: EventTarget;
|
target?: EventTarget;
|
||||||
}
|
},
|
||||||
): { destroy: () => void } {
|
): { destroy: () => void } {
|
||||||
const deregister = registerShortcut(action, keyCombination, target ?? document);
|
const deregister = registerShortcut(action, keyCombination, target ?? document);
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ interface StoreAccessors {
|
|||||||
function storeSubscribe<T>(
|
function storeSubscribe<T>(
|
||||||
store: Readable<T>,
|
store: Readable<T>,
|
||||||
callback: (value: T) => void,
|
callback: (value: T) => void,
|
||||||
start = true
|
start = true,
|
||||||
): StoreAccessors {
|
): StoreAccessors {
|
||||||
function subscribe(): Unsubscriber {
|
function subscribe(): Unsubscriber {
|
||||||
return store.subscribe(callback);
|
return store.subscribe(callback);
|
||||||
|
Loading…
Reference in New Issue
Block a user