diff --git a/.gitignore b/.gitignore index 406c7f3af33e3247873f2458a5c1ff7cbbc16f9c..0d273426683ad888797b2024a6b8624292a8ba81 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ node_modules -dist +/dist *.build-in-progress .parcel-cache yarn-error.log @@ -11,7 +11,7 @@ __pycache__ *.d.mk /templates /*.apkg -hanzi-data +/hanzi-data .data-test-ok .html-test-ok .lint-ok diff --git a/.proxyrc.js b/.proxyrc.js index 0a15292e7532ffb693160d8293f77c9ef29bd528..99c30f0a80dbef107486860f475b04c41f10e3f2 100644 --- a/.proxyrc.js +++ b/.proxyrc.js @@ -5,7 +5,6 @@ module.exports = function (app) { if (!('BUILD_PREFIX' in process.env)) { throw new Error(`Dunno where the chardata at, what BUILD_PREFIX?`) } - const dir = `${process.env.BUILD_PREFIX}hanzi-data` - app.use("/hanzi-data", serveStatic(dir)) - console.error(('ok configured at '), dir) + app.use(`/${process.env.BUILD_PREFIX}`, serveStatic(process.env.BUILD_PREFIX)) + console.error(`data at /${process.env.BUILD_PREFIX}`) } diff --git a/NOTICE b/KA_TEMPLATES_NOTICE similarity index 96% rename from NOTICE rename to KA_TEMPLATES_NOTICE index 8858497880070dce8226ca7366cb301232179a54..324be8451fabe49dfc55fdae61ab16c385fea26b 100644 --- a/NOTICE +++ b/KA_TEMPLATES_NOTICE @@ -1,5 +1,5 @@ -sinologie-anki-pack -Copyright (c) 2024–Present Sinologie Anki Pack Contributors +card-templates by kartenaale +Copyright (c) 2024–Present Kartenaale You are free to use, share and modify everything in the repository. diff --git a/Makefile b/Makefile index aa385f20e7b2831761b5d2796a62223d694c7903..73dd75521bb58270871847555e4b3a3b72a2a56f 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,7 @@ make/defs.mk \ make/src-common.mk \ make/node.mk \ make/hanzi-data.mk \ +make/jsonp.mk \ make/html.mk \ make/eslint.mk \ make/dist.mk \ diff --git a/build/__init__.py b/build/__init__.py deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/make/dist.mk b/make/dist.mk index 74d6557b5c5a3c2cf78dc80b4e8d031ee61fc5b3..e232b76ce60ee5b37e52249b3fca8679b2b346f0 100644 --- a/make/dist.mk +++ b/make/dist.mk @@ -1,6 +1,6 @@ RELEASE_TAR := $(BUILD_PREFIX)card-templates-$(shell grep '"version":' package.json -m 1 | cut -d '"' -f 4).tar.gz -RELEASE_INCLUDE_SRC := LICENSE NOTICE -RELEASE_INCLUDE_ARTIFACTS := $(HANZI_DATA) $(BUILT_TEMPLATE_HTMLS) $(BUILT_TEMPLATE_SPECS) +RELEASE_INCLUDE_SRC := +RELEASE_INCLUDE_ARTIFACTS := $(HANZI_DATA) $(BUILT_TEMPLATE_HTMLS) $(BUILT_TEMPLATE_SPECS) $(JSONP_OUTPUT) RELEASE_CONTENT_SRC := $(addprefix $(RELEASE_DIR)/,$(RELEASE_INCLUDE_SRC)) RELEASE_CONTENT_ARTIFACTS := $(patsubst $(BUILD_PREFIX)%,$(RELEASE_DIR)/%,$(RELEASE_INCLUDE_ARTIFACTS)) RELEASE_CONTENT := $(RELEASE_CONTENT_SRC) $(RELEASE_CONTENT_ARTIFACTS) diff --git a/make/global.mk b/make/global.mk index 31f7fd800e88d85bc7a55a01421069653a432db3..bd0af77d7e1567f9f87dda027a60c428ad5e6d62 100644 --- a/make/global.mk +++ b/make/global.mk @@ -23,4 +23,7 @@ deepclean: rm -f $(MOSTLY_CLEAN) $(CLEAN) rm -rf $(MOSTLY_CLEAN_DIRS) $(CLEAN_DIRS) $(DEEP_CLEAN_DIRS) +.PHONY: install +install: install-data + .DEFAULT_GOAL := all diff --git a/make/hanzi-data.mk b/make/hanzi-data.mk index 2c218463f7ffd1940ed4e8538f3fc11e684fdf1e..42349f6fa83ceb9667f98158636281ca2d069465 100644 --- a/make/hanzi-data.mk +++ b/make/hanzi-data.mk @@ -7,12 +7,23 @@ TS_SRC += $(SRC_DATA_TESTS_TS) $(BUILD_TS_SOURCES) MOSTLY_CLEAN += $(DATA_TEST_OK_FLAG) MOSTLY_CLEAN_DIRS += $(HANZI_DATA) +# hanzi data is installed here +ANKI_COL_DIR := $(HOME)/.local/share/Anki2/Main +ANKI_COL_WAL := $(ANKI_COL_DIR)/collection.anki2-wal + .PHONY: data data: $(HANZI_DATA) .PHONY: test-data test-data: $(DATA_TEST_OK_FLAG) +# debug only: this will overwrite existing data, +# alternatively delete js files and reimport anki package +.PHONY: install-data +install-data: $(HANZI_DATA) + $(if $(wildcard $(ANKI_COL_WAL)), $(error Cannot install while Anki is open)) + cp -f $(HANZI_DATA)/*.js $(ANKI_COL_DIR)/collection.media/ + $(HANZI_DATA): \ $(GEN_HANZI_DATA) \ $(wildcard build/gen-hanzi-data/pools/simplified/*.txt) \ diff --git a/make/html.mk b/make/html.mk index 8978fc002a6ca4ed1871c1317ef132e3d8a61e79..92054d6a1164abcc6f773cca3ca6c19929ec4a42 100644 --- a/make/html.mk +++ b/make/html.mk @@ -22,7 +22,7 @@ DEEP_CLEAN_DIRS += .parcel-cache dist html: $(BUILT_TEMPLATE_HTMLS) $(BUILT_TEMPLATE_SPECS) .PHONY: dev -dev: $(PARCEL) $(HANZI_DATA) +dev: $(PARCEL) $(HANZI_DATA) $(JSONP_OUTPUT) $(PARCEL) serve $(PARCEL_DEV_ENTRY_HTMLS) --config=./$(PARCEL_DEV_CONFIG) .PHONY: test-html @@ -35,7 +35,7 @@ $(HTML_TEST_OK_FLAG): $(JEST) $(HANZI_DATA) $(SRC_TEMPLATE_TESTS) $(SRC_TEMPLATE # no parcel plugin or config required for production builds, Anki handles the # tags -$(BUILT_TEMPLATE_HTMLS) &: $(HANZI_DATA) $(PARCEL) $(TEMPLATE_FILES) $(SRC_COMMON_TS) +$(BUILT_TEMPLATE_HTMLS) &: $(HANZI_DATA) $(JSONP_OUTPUT) $(PARCEL) $(TEMPLATE_FILES) $(SRC_COMMON_TS) @$(and $(BUILD_PREFIX),mkdir -p $(BUILD_PREFIX)) $(PARCEL) build --no-source-maps --dist-dir=$(BUILD_PREFIX)templates $(SRC_TEMPLATE_HTMLS) # set moddat even for files that did not need to be updated (to avoid redundant rebuilds) diff --git a/make/jsonp.mk b/make/jsonp.mk new file mode 100644 index 0000000000000000000000000000000000000000..9e8f4a84b7dcadd99368508e7a2eb01e2e8e6bf4 --- /dev/null +++ b/make/jsonp.mk @@ -0,0 +1,10 @@ +JSONP_INPUT := KA_TEMPLATES_NOTICE +JSONP_OUTPUT := $(foreach I,$(JSONP_INPUT),$(BUILD_PREFIX)$(I).js) + +MOSTLY_CLEAN += $(JSONP_OUTPUT) + +.PHONY: jsonp +jsonp: $(JSONP_OUTPUT) + +$(JSONP_OUTPUT): $(BUILD_PREFIX)%.js: % $(JSONP) + $(JSONP) --fn hd $< -f $@ diff --git a/make/node.mk b/make/node.mk index a842561bd36b4dddb82aee3c0e500689dc16faff..02a53cb4ec90a7a475499fd700eac93468d9f548 100644 --- a/make/node.mk +++ b/make/node.mk @@ -2,7 +2,8 @@ PARCEL := node_modules/.bin/parcel ESLINT := node_modules/.bin/eslint JEST := node_modules/.bin/jest TSC := node_modules/.bin/tsc -NODE_BINS := $(PARCEL) $(ESLINT) $(JEST) $(TSC) +JSONP := node_modules/.bin/to-static-jsonp +NODE_BINS := $(PARCEL) $(ESLINT) $(JEST) $(TSC) $(JSONP) GEN_HANZI_DATA := $(BUILD_PREFIX)build/gen-hanzi-data/run BUILD_TS_SOURCES := $(shell find build -name '*.ts') diff --git a/package.json b/package.json index d3b308ec9e62ec30d95c28d4521789171b5e20f5..d16de447c089f202f98426a365337269c7abad28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "kartenaale-card-templates", - "version": "1.0.2", + "version": "2.0.0", "description": "HTML and data for Anki cards", "repository": "https://gitlab.phaidra.org/kartenaale/card-templates", "author": "Philipp Stadler <hello@phstadler.com>", @@ -24,6 +24,7 @@ "parcel-transformer-anki-tags": "0.0.1", "posthtml-include": "^2.0.1", "serve-static": "^1.15.0", + "to-static-jsonp": "^1.0.1", "ts-jest": "^29.2.3", "typescript": "*", "typescript-eslint": "^7.16.1" diff --git a/src/components/data.ts b/src/components/data.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b2dca1503ee4757b62944d2df4f3d2133540f59 --- /dev/null +++ b/src/components/data.ts @@ -0,0 +1,141 @@ +import { readFile } from 'fs/promises' + +export interface GetDataOpts { + /** + * The JS file to load for the data, e.g. `hanzi-data/_hdA.js'. + * + * Directories are handled in testing, but only the basename is considered in + * Anki, which does not support directories. + */ + path: string + /** + * First argument to the JSONP callback before the actual data. + */ + key: string +} + +const jsonpCallbackFnName = 'hd' +/** keys against functions to call on resolve. */ +const jsonpWaiters = new Map<string, Array<(unknown) => void>>() +const cached: Record<string, Readonly<unknown>> = {} +const canAccessFilesystem = typeof document === 'undefined' + +/** + * Fetches JSONP data with the specified key. + * + * For a key of A, will fetch `_hdA.js`, assuming it contains a function call + * to `hd`, with the key as the first param and the data (unknown type) as the + * second. + * + * Unsafe because it is up to the caller to cast to a concrete correct type. + */ +export async function getDataUnsafe ( + opts: GetDataOpts +): Promise<Readonly<unknown>> { + const { key } = opts + let data: Readonly<unknown> + if (key in cached) { + data = cached[key] + } else if (canAccessFilesystem) { + // read directly from disk when running in test and skip the cache + data = await fetchNonBrowser(opts) + } else { + // in production and parcel use a JSONP-like API because everything else + // failed in AnkiDroid + data = await fetchJsonp(opts) + // caching helps a lot with load speed since the same character often + // occurs multiple times on the same card + cached[key] = data + } + return data +} + +/** + * Fetches the JSONP via direct filesystem access (for tests). + */ +async function fetchNonBrowser (opts: GetDataOpts): Promise<Readonly<unknown>> { + if (!('BUILD_PREFIX' in process.env)) { + throw new Error('Dunno where the data at, what BUILD_PREFIX?') + } + const path = `${process.env.BUILD_PREFIX}${opts.path}` + const jsonp = await readFile(path, { encoding: 'utf-8' }) + const data = JSON.parse(jsonp.substring( + `${jsonpCallbackFnName}(${JSON.stringify(opts.key)},`.length, + jsonp.length - ')'.length + )) + // just for testing: we want to catch accidental modifications of data that + // would be shared if this were production + Object.freeze(data) + return data +} + +/** + * Callback for the JSONP scripts with the data. + * + * Raw JSON would not work with AnkiDroid, which does not support XHR/fetch, + * but allows scripts. + * + * In AnkiDroid, every card gets a fresh window, but desktop and Anki Web + * preserved the callback from the last call. If window already contains a + * callback, it works to just overwrite the old callback here that is no longer + * needed. See #298 for details. + */ +if (!canAccessFilesystem) { + window[jsonpCallbackFnName] = (char: string, data: Readonly<unknown>) => { + (jsonpWaiters.get(char) ?? []).forEach(w => { + // careful: every consumer gets an identical object, don't modify + w(data) + }) + jsonpWaiters.delete(char) + } +} + +/** + * Registers a waiter for the specified key. + * + * It will be removed automatically after the data has been received. + */ +function registerJsonpWaiter ( + char: string, + callback: (data: Readonly<unknown>) => void +): void { + jsonpWaiters.set( + char, + [...(jsonpWaiters.get(char) ?? []), callback] + ) +} + +/** + * Fetches data over the network for the specified key. + */ +async function fetchJsonp (opts: GetDataOpts): Promise<Readonly<unknown>> { + return await new Promise((resolve, reject) => { + const url = process.env.NODE_ENV === 'production' + // No directories for Anki media possible, for prod use just filename + ? opts.path.split('/').pop()! + // For testing in parcel it works better to have a subpath that we can + // exclude from parcel. + : `/${process.env.BUILD_PREFIX}${opts.path}` + if (document.querySelector(`script[src="${url}"]`) !== null) { + // already being fetched, append to the list of existing waiters + registerJsonpWaiter(opts.key, resolve) + } else { + // no fetch in flight, inject a new script tag + const script = document.createElement('script') + registerJsonpWaiter( + opts.key, + data => { + script.remove() + resolve(data) + } + ) + script.async = true + script.src = url + script.onerror = () => { + script.remove() + reject(new Error(`No character data available for ${opts.key}`)) + } + document.body.appendChild(script) + } + }) +} diff --git a/src/components/global.css b/src/components/global.css index d132e03427a64c71596fdfef1681d441ba881847..36b148013e32751aad08916299e2a594b504d26c 100644 --- a/src/components/global.css +++ b/src/components/global.css @@ -1,7 +1,6 @@ @import url(./theme.css); @import url(./debug/debug.css); @import url(./fira.css); -@import url(./notice/notice.css); @import url(./tts/tts.css); @import url(./write/write.css); @import url(./answer-details.css); diff --git a/src/components/hanzi-data/index.ts b/src/components/hanzi-data/index.ts index a1f1b8ce10d61ef8e194ade01f56b94b42c179d3..eeaee842a134cdfce4fff2dd2504bb7dab750ed0 100644 --- a/src/components/hanzi-data/index.ts +++ b/src/components/hanzi-data/index.ts @@ -1,6 +1,6 @@ import type { HanziData } from '../../../src-common/hanzi-data' +import { getDataUnsafe } from '../data' import { lookup } from './lut' -import { readFile } from 'fs/promises' export interface GetHanziDataOpts { char: string @@ -23,13 +23,6 @@ export async function getHanziProp ( return data[prop] ?? lookup(data, prop) } -const dataFilePrefix = '_hd' -const jsonpCallbackFnName = 'hd' -/** chars against functions to call on resolve. */ -const jsonpWaiters = new Map<string, Array<(HanziData) => void>>() -const cached: Record<string, Readonly<HanziData>> = {} -const canAccessFilesystem = typeof document === 'undefined' - export async function getHanziData ( { char, kind }: GetHanziDataOpts ): Promise<Readonly<HanziData>> { @@ -37,20 +30,7 @@ export async function getHanziData ( throw new Error(`Can only get data for single chars, got: ${char}`) } - let data: Readonly<HanziData> - if (char in cached) { - data = cached[char] - } else if (canAccessFilesystem) { - // read directly from disk when running in test and skip the cache - data = await fetchNonBrowser(char) - } else { - // in production and parcel use a JSONP-like API because everything else - // failed in AnkiDroid - data = await fetchJsonp(char) - // caching helps a lot with load speed since the same character often - // occurs multiple times on the same card - cached[char] = data - } + const data = (await getDataUnsafe({ path: `hanzi-data/_hd${char}.js`, key: char })) as Readonly<HanziData> if (kind === GetHanziDataKind.TRADITIONAL && data.trad !== undefined) { // data in the cache is read-only => make a fresh copy with trad overrides return { @@ -60,92 +40,3 @@ export async function getHanziData ( } return data } - -async function fetchNonBrowser (char: string): Promise<HanziData> { - if (!('BUILD_PREFIX' in process.env)) { - throw new Error('Dunno where the chardata at, what BUILD_PREFIX?') - } - const dir = `${process.env.BUILD_PREFIX}hanzi-data` - const path = `${dir}/${dataFilePrefix}${char}.js` - const jsonp = await readFile(path, { encoding: 'utf-8' }) - const data = JSON.parse(jsonp.substring( - 'hd("A",'.length, - jsonp.length - ')'.length - )) - // just for testing: we want to catch accidental modifications of data that - // would be shared if this were production - Object.freeze(data) - return data -} - -/** - * Callback for the JSONP scripts with the data. - * - * Raw JSON would not work with AnkiDroid, which does not support XHR/fetch, - * but allows scripts. - * - * In AnkiDroid, every card gets a fresh window, but desktop and Anki Web - * preserved the callback from the last call. If window already contains a - * callback, it works to just overwrite the old callback here that is no longer - * needed. See #298 for details. - */ -if (!canAccessFilesystem) { - window[jsonpCallbackFnName] = (char: string, data: HanziData) => { - (jsonpWaiters.get(char) ?? []).forEach(w => { - // careful: every consumer gets an identical object, don't modify - w(data) - }) - jsonpWaiters.delete(char) - } -} - -/** - * Registers a waiter for the specified char. - * - * It will be removed automatically after the data has been received. - */ -function registerJsonpWaiter ( - char: string, - callback: (data: HanziData) => void -): void { - jsonpWaiters.set( - char, - [...(jsonpWaiters.get(char) ?? []), callback] - ) -} - -/** - * Fetches the character data (strokes, SVG, etc.) for the specified character. - */ -async function fetchJsonp (char: string): Promise<Readonly<HanziData>> { - return await new Promise((resolve, reject) => { - const prefix = process.env.NODE_ENV === 'production' - // No directories for Anki media possible, for prod use just filename - ? '' - // For testing in parcel it works better to have a subpath that we can - // exclude from parcel. - : '/hanzi-data/' - const url = `${prefix}${dataFilePrefix}${char}.js` - if (document.querySelector(`script[src="${url}"]`) !== null) { - // already being fetched, append to the list of existing waiters - registerJsonpWaiter(char, resolve) - } else { - // no fetch in flight, inject a new script tag - const script = document.createElement('script') - registerJsonpWaiter( - char, - data => { - script.remove() - resolve(data) - } - ) - script.async = true - script.src = url - script.onerror = () => { - script.remove() - reject(new Error(`No character data available for ${char}`)) - } - document.body.appendChild(script) - } - }) -} diff --git a/src/components/init.ts b/src/components/init.ts index 99d463f9a7fe4806a5b310222662fc626e12c99d..70d73738200dfc5626fc9f910d93750c4d791128 100644 --- a/src/components/init.ts +++ b/src/components/init.ts @@ -1,4 +1,5 @@ import { init as initHanziData } from './hanzi-data/init' +import { initNotice } from './notice' import { init as initTts } from './tts/init' import { init as initWrite } from './write/init' @@ -9,4 +10,5 @@ export async function init (within: HTMLElement | null): Promise<void> { await initHanziData(within) initTts(within) await initWrite(within) + await initNotice(within) } diff --git a/src/components/load-text.ts b/src/components/load-text.ts new file mode 100644 index 0000000000000000000000000000000000000000..2dfbb32ab149922f7e1d814605921c61f304f209 --- /dev/null +++ b/src/components/load-text.ts @@ -0,0 +1,15 @@ +import { getDataUnsafe } from "./data"; + +export async function loadText(filename: string): Promise<string> { + const data = await getDataUnsafe({ path: filename + '.js', key: filename }) + if (typeof data !== 'string') { + throw new Error(`${filename} loaded, but is not text`) + } + return toHtml(data) +} + +function toHtml(raw: string): string { + return raw.split(/[\n-]{2,}/).map(p => `<p>${ + p.replace(/([a-z]+:\/\/[/a-zA-Z-.]+[/a-zA-Z])/g, '<a href="$1">$1</a>') + }</p>`).join('') +} diff --git a/src/components/notice.ts b/src/components/notice.ts new file mode 100644 index 0000000000000000000000000000000000000000..1fca444916d2c6bd35a59f27be0cb55518ce5047 --- /dev/null +++ b/src/components/notice.ts @@ -0,0 +1,12 @@ +import { loadText } from "./load-text" + +export async function initNotice(within: HTMLElement) { + within.querySelectorAll('[notice-file]').forEach( + async el => { + const noticeFile = el.getAttribute('notice-file') ?? '' + if (noticeFile !== '') { + el.innerHTML = await loadText(noticeFile) + } + } + ) +} diff --git a/src/components/notice/notice.css b/src/components/notice/notice.css deleted file mode 100644 index 4c8e028e579098a384dddbfc75d2c7bf8982a906..0000000000000000000000000000000000000000 --- a/src/components/notice/notice.css +++ /dev/null @@ -1,7 +0,0 @@ -.notice-contents { - text-align: justify; -} - -.notice-contents ul { - list-style-type: none; -} diff --git a/src/components/notice/notice.html b/src/components/notice/notice.html deleted file mode 100644 index 2067e20b2e55c1fdfe1129b63d9e4c9bd5e7853b..0000000000000000000000000000000000000000 --- a/src/components/notice/notice.html +++ /dev/null @@ -1,115 +0,0 @@ -<details class="answer-details"> - <summary> - <span class="answer-details-more">About this deck…</span> - <span class="answer-details-less">Hide notice…</span> - </summary> - <aside class="notice-contents"> - <p> - The code that makes this deck work is open source software available on - <a href="https://gitlab.phaidra.org/kartenaale/sinologie-anki-pack">University of Vienna GitLab</a>. - <br>Check out releases for more decks and updates, or file an issue if - you are experiencing issues or if you want to contribute. - </p> - <p> - Deck: Chinese Cultural Spaces<br> - - Special thanks go out to Chris for making this deck!<br> - - Please respect the rights of the lecturer that provided the content, as well as - of the photographers that made the images. Share the deck only with your fellow - students. - </p> - <p> - Decks: Chinesisch lernen für die Sinologie, Band 1&2<br> - - Stefanie Yu kindly gave permission to make an Anki version of her vocabulary on - Quizlet that can be freely shared among students of the University of Vienna. - It is available with releases of this project on GitLab, and you are welcome to - improve on it and share your improvements with other students.<br> - - The vocabulary and some additional content like stroke names are taken from the - book "Chinesisch lernen für die Sinologie, Band 1" by Xia Baige and Wolfgang - Zeidl. Xia Baige kindly gave permission to use their work in this Anki deck. - The book itself is available at Universität Wien.<br> - - Please respect the rights of the original authors and share content from - Sinologie Anki Pack only with your fellow students. - </p> - <p> - Deck: Introduction to Chinese Cultural History<br> - - This deck includes content from the slides of the lecture _Introduction to - Chinese Cultural History_ at Universität Wien, held by Dr. Rossella Ferrari.<br> - - A separate part of the deck heavily relies on content from _The Columbia - Companion to Modern Chinese Literature_.<br> - - Please respect the rights of the original authors and share this deck only with - your fellow students. - </p> - <p> - Deck: Einführung in die politische Geschichte Chinas<br> - - This deck includes content from the slides of the lecture _Einführung in die - politische Geschichte Chinas_ at Universität Wien, held by Dr. Christian Göbel.<br> - - Please respect the rights of the original authors and share this deck only with - your fellow students. - </p> - <p> - Deck: Wirtschaftliche Entwicklung Chinas<br> - - This deck includes content from the slides of the lecture - _Wirtschaftliche Entwicklung Chinas_ at Universität Wien, held by Dr. - Christian Göbel.<br> - - Please respect the rights of the original authors and share this deck only with - your fellow students. - </p> - <p> - German and Chinese radical names are taken from the German version of - Wikipedia. A hearty thank you to all authors and maintainers. - </p> - <p> - This product includes software from the hanzi-writer project (MIT). - <br>Copyright (c) 2014 David Chanin. - <br><a href="https://github.com/chanind/hanzi-writer">https://github.com/chanind/hanzi-writer</a> - </p> - <p> - COPYING notice from the hanzi-writer project: - - Hanzi Writer uses data from the excellent Make Me a Hanzi project and fonts from Arphic. You can redistribute - and/or - modify the font data under the terms of the Arphic Public License as published by Arphic Technology Co., Ltd. You - should - have received a copy of this license (the directory "APL") in the data folder of this repository; if not, see - http://ftp.gnu.org/non-gnu/chinese-fonts-truetype/LICENSE. - - Arphic PL KaitiM GB and UKai Copyright 1999 Arphic Technology Co., Ltd.; licensed under the Arphic Public License - http://www.arphic.com.tw/en/home/index - - Make Me a Hanzi Copyright 1999 Arphic Technology Co., Ltd., copyright 2016 Shaunak Kishore; licensed under the - Arphic - Public License https://github.com/skishore/makemeahanzi - - </p> - <p> - This product includes software from the cnchar project (MIT). - <br>Copyright (c) 2017 - present theajack <theajack@qq.com> - <br><a href="https://github.com/theajack/cnchar">https://github.com/theajack/cnchar</a> - </p> - <p> - This product includes software from the hanzi-tool project (MIT). - <br>Copyright (c) 2012-2014 Jeremiah Daneil de la Rouviere - <br><a href="https://github.com/ginsudev/hanzi">https://github.com/ginsudev/hanzi</a> - </p> - <p> - This project also would not have been possible without these projects and - the teams behind them: - </p> - <ul> - <li>Anki (<a href="https://apps.ankiweb.net/">https://apps.ankiweb.net/</a>)</li> - <li>parcel (<a href="https://parceljs.org/">https://parceljs.org/</a>)</li> - </ul> - </aside> -</details> \ No newline at end of file diff --git a/src/templates/bijective/.template-spec.yaml b/src/templates/bijective/.template-spec.yaml index ed45670a2d8a25a4528788b12ec8e6095e18541a..0074aaa735dc1301e5b5b4288a5815cf301f802a 100644 --- a/src/templates/bijective/.template-spec.yaml +++ b/src/templates/bijective/.template-spec.yaml @@ -1,4 +1,4 @@ -template_version: 2024-02-28 22:00:00+00:00 +template_version: 2024-07-20 10:00:00+00:00 note_type: id: 2024-01-05 03:00:00+00:00 @@ -6,6 +6,7 @@ note_type: fields: - A - B + - Credits card_types: - name: Forward @@ -13,4 +14,5 @@ card_types: - name: Backward template: backward -resource_paths: [] +resource_paths: +- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js' diff --git a/src/templates/bijective/backward/back.html b/src/templates/bijective/backward/back.html index 84534fbef4bf17dc733bf2504a2833cf24a1529d..0a666c0ab64c60d4fa57dcd28fd9de644ddb151d 100644 --- a/src/templates/bijective/backward/back.html +++ b/src/templates/bijective/backward/back.html @@ -9,7 +9,15 @@ {{A}} </div> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Suppress speech output on AnkiDroid if globally enabled --> diff --git a/src/templates/bijective/forward/back.html b/src/templates/bijective/forward/back.html index afbae1a920ec242f9d2fed054e70b5a6d895e16a..94470ebf9ed5260c4f74c702b345851cf53b9099 100644 --- a/src/templates/bijective/forward/back.html +++ b/src/templates/bijective/forward/back.html @@ -9,7 +9,15 @@ {{B}} </div> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Suppress speech output on AnkiDroid if globally enabled --> diff --git a/src/templates/facts/.template-spec.yaml b/src/templates/facts/.template-spec.yaml index fe384c1e79bf439cf2299d42295600564245698c..b7796d519b44f2a55493e046fbdf9b868b5aee27 100644 --- a/src/templates/facts/.template-spec.yaml +++ b/src/templates/facts/.template-spec.yaml @@ -1,4 +1,4 @@ -template_version: 2024-02-28 22:00:00+00:00 +template_version: 2024-07-20 10:00:00+00:00 note_type: id: 2024-01-04 03:00:00+00:00 @@ -6,9 +6,11 @@ note_type: fields: - Front - Back + - Credits card_types: - name: Q/A template: q_a -resource_paths: [] +resource_paths: +- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js' diff --git a/src/templates/facts/q_a/back.html b/src/templates/facts/q_a/back.html index 1ac8a0788f6fcbe64b2bd300a560d7e6648180a2..6d92af2b0881f59c639a45dcda3f84e3cf63852c 100644 --- a/src/templates/facts/q_a/back.html +++ b/src/templates/facts/q_a/back.html @@ -9,7 +9,15 @@ {{Back}} </div> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Suppress speech output on AnkiDroid if globally enabled --> diff --git a/src/templates/hanzi/.template-spec.yaml b/src/templates/hanzi/.template-spec.yaml index 0908f3094ee9c9766d2a2330c2fa076da85480a9..ce7c24504118c0f2a31d8c2dea3eb0f4407a2856 100644 --- a/src/templates/hanzi/.template-spec.yaml +++ b/src/templates/hanzi/.template-spec.yaml @@ -1,4 +1,4 @@ -template_version: 2024-03-20 10:00:00+00:00 +template_version: 2024-07-20 10:00:00+00:00 note_type: id: 2024-02-21 12:00:00+00:00 @@ -17,6 +17,7 @@ note_type: - Notes (Back) - Traditional - Simplified + - Credits card_types: - name: Schreiben @@ -24,3 +25,4 @@ card_types: resource_paths: - '{{BUILD_PREFIX}}hanzi-data' +- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js' diff --git a/src/templates/hanzi/write/back.html b/src/templates/hanzi/write/back.html index b176010e465ffba032bb66d8f77781403597df87..e9f44e384d35819b4676ad2a1f6fe08a457137e2 100644 --- a/src/templates/hanzi/write/back.html +++ b/src/templates/hanzi/write/back.html @@ -14,7 +14,15 @@ <dd><span class="hanzi-print is-large">{{Hanzi}}</span></dd> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Suppress speech output on AnkiDroid if globally enabled --> diff --git a/src/templates/molaoshi/.template-spec.yaml b/src/templates/molaoshi/.template-spec.yaml index 5f982c729ae2c0b918880490d4f06b90c13f0568..3530da756a7ef3eeee041d72706f865b313eed00 100644 --- a/src/templates/molaoshi/.template-spec.yaml +++ b/src/templates/molaoshi/.template-spec.yaml @@ -1,4 +1,4 @@ -template_version: 2024-06-14 12:00:00+00:00 +template_version: 2024-07-20 10:00:00+00:00 note_type: id: 2024-02-20 12:00:00+00:00 @@ -22,6 +22,7 @@ note_type: - Schreiben anlegen - Zhuyin - Lesen (繁體字) anlegen + - Credits card_types: - name: Hören @@ -43,3 +44,4 @@ card_types: resource_paths: - '{{BUILD_PREFIX}}hanzi-data' +- '{{BUILD_PREFIX}}KA_TEMPLATES_NOTICE.js' diff --git a/src/templates/molaoshi/hear/back.html b/src/templates/molaoshi/hear/back.html index a32ec6f63bf33e981ed055582dc2699bd5198b39..fe25e69b89582b12fae40d1cc40290552081d831 100644 --- a/src/templates/molaoshi/hear/back.html +++ b/src/templates/molaoshi/hear/back.html @@ -54,7 +54,15 @@ </details> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Repeat only relevant text on the back side on AnkiDroid, not all of it --> diff --git a/src/templates/molaoshi/identify_radical/back.html b/src/templates/molaoshi/identify_radical/back.html index 0d1a17ecb421718485288e2dd8bfa750e56f1128..f9830e1ab08c0a1135b30538a4a78e992de7fa30 100644 --- a/src/templates/molaoshi/identify_radical/back.html +++ b/src/templates/molaoshi/identify_radical/back.html @@ -21,7 +21,15 @@ <dd hanzi-data="{{text:简体字}}" hanzi-prop="count"></dd> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Suppress speech output on AnkiDroid if globally enabled --> diff --git a/src/templates/molaoshi/identify_radical_traditional/back.html b/src/templates/molaoshi/identify_radical_traditional/back.html index 7a642befa6dfc17535bd8a3ccd20f3cb490a1449..315c6ec517b717c266cb324fdf7d4ff5f15c812c 100644 --- a/src/templates/molaoshi/identify_radical_traditional/back.html +++ b/src/templates/molaoshi/identify_radical_traditional/back.html @@ -21,7 +21,15 @@ <dd hanzi-data="{{text:繁體字}}" hanzi-kind="traditional" hanzi-prop="count"></dd> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <!-- Suppress speech output on AnkiDroid if globally enabled --> diff --git a/src/templates/molaoshi/read_hanzi/back.html b/src/templates/molaoshi/read_hanzi/back.html index a16bcfd82015db00e0c4a68db99b5cd33cca6372..403930242edcfe6606be7a672c5bb492a8a0af62 100644 --- a/src/templates/molaoshi/read_hanzi/back.html +++ b/src/templates/molaoshi/read_hanzi/back.html @@ -65,7 +65,15 @@ </details> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <script type="module"> diff --git a/src/templates/molaoshi/read_hanzi_traditional/back.html b/src/templates/molaoshi/read_hanzi_traditional/back.html index e95f0c09f4724f97995ec50a8f97f1cb7687c350..ad1accf8fb30ceac066995f4852eac25c17223b9 100644 --- a/src/templates/molaoshi/read_hanzi_traditional/back.html +++ b/src/templates/molaoshi/read_hanzi_traditional/back.html @@ -65,7 +65,15 @@ </details> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <script type="module"> diff --git a/src/templates/molaoshi/read_pinyin/back.html b/src/templates/molaoshi/read_pinyin/back.html index 71d713190f6f8922fb89900810f4e786aeaa8caf..c892d71d0b90b98d082e401010f8452c8697b753 100644 --- a/src/templates/molaoshi/read_pinyin/back.html +++ b/src/templates/molaoshi/read_pinyin/back.html @@ -70,7 +70,15 @@ </details> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <script type="module"> diff --git a/src/templates/molaoshi/speak/back.html b/src/templates/molaoshi/speak/back.html index b80aea9a7b0f06770e7a3c6d5944612bb0a5e33a..5fc56e8441bc212007ffff6107c6f9d138fe992c 100644 --- a/src/templates/molaoshi/speak/back.html +++ b/src/templates/molaoshi/speak/back.html @@ -70,7 +70,15 @@ </details> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <script type="module"> diff --git a/src/templates/molaoshi/write/back.html b/src/templates/molaoshi/write/back.html index 6417876fcdb6ba973116beaa957fc184cc5d7695..66e7c23bace84db5de587d36655443a297c2a1ef 100644 --- a/src/templates/molaoshi/write/back.html +++ b/src/templates/molaoshi/write/back.html @@ -70,7 +70,15 @@ </details> </dl> - <include src="src/components/notice/notice.html"></include> + <details class="answer-details"> + <summary> + <span class="answer-details-more">Über das Pack…</span> + <span class="answer-details-less">Info verbergen…</span> + </summary> + + {{Credits}} + <div notice-file="KA_TEMPLATES_NOTICE"></div> + </details> </div> <script type="module"> diff --git a/yarn.lock b/yarn.lock index f2dd0746d86b3062da77a11c5edbdece13299ce8..160906743abf56abf36f35c21042b0139615f271 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4174,6 +4174,11 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +to-static-jsonp@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-static-jsonp/-/to-static-jsonp-1.0.1.tgz#bf6cda4746e01c44cf63112470ce183df2ca18c2" + integrity sha512-Q+32t6Or6MwXGtcTmnOoexZJNAVVDhWZX31aTdYc4lEMyG9RzGvYNfH4O5h5OBZJh6Lxf3wiQ98VzKXwB+Vrmg== + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"