From 84bd17d88c22cba7f924dd44b081a1e7aec631f2 Mon Sep 17 00:00:00 2001 From: Philipp Stadler <a51820432@unet.univie.ac.at> Date: Sat, 20 Jul 2024 16:46:13 +0000 Subject: [PATCH] feat!: lazy load notice text and add field for custom credits --- .gitignore | 4 +- .proxyrc.js | 5 +- NOTICE => KA_TEMPLATES_NOTICE | 4 +- Makefile | 1 + build/__init__.py | 0 make/dist.mk | 4 +- make/global.mk | 3 + make/hanzi-data.mk | 11 ++ make/html.mk | 4 +- make/jsonp.mk | 10 ++ make/node.mk | 3 +- package.json | 3 +- src/components/data.ts | 141 ++++++++++++++++++ src/components/global.css | 1 - src/components/hanzi-data/index.ts | 113 +------------- src/components/init.ts | 2 + src/components/load-text.ts | 15 ++ src/components/notice.ts | 12 ++ src/components/notice/notice.css | 7 - src/components/notice/notice.html | 115 -------------- src/templates/bijective/.template-spec.yaml | 6 +- src/templates/bijective/backward/back.html | 10 +- src/templates/bijective/forward/back.html | 10 +- src/templates/facts/.template-spec.yaml | 6 +- src/templates/facts/q_a/back.html | 10 +- src/templates/hanzi/.template-spec.yaml | 4 +- src/templates/hanzi/write/back.html | 10 +- src/templates/molaoshi/.template-spec.yaml | 4 +- src/templates/molaoshi/hear/back.html | 10 +- .../molaoshi/identify_radical/back.html | 10 +- .../identify_radical_traditional/back.html | 10 +- src/templates/molaoshi/read_hanzi/back.html | 10 +- .../molaoshi/read_hanzi_traditional/back.html | 10 +- src/templates/molaoshi/read_pinyin/back.html | 10 +- src/templates/molaoshi/speak/back.html | 10 +- src/templates/molaoshi/write/back.html | 10 +- yarn.lock | 5 + 37 files changed, 338 insertions(+), 265 deletions(-) rename NOTICE => KA_TEMPLATES_NOTICE (96%) delete mode 100644 build/__init__.py create mode 100644 make/jsonp.mk create mode 100644 src/components/data.ts create mode 100644 src/components/load-text.ts create mode 100644 src/components/notice.ts delete mode 100644 src/components/notice/notice.css delete mode 100644 src/components/notice/notice.html diff --git a/.gitignore b/.gitignore index 406c7f3..0d27342 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 0a15292..99c30f0 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 8858497..324be84 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 aa385f2..73dd755 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 e69de29..0000000 diff --git a/make/dist.mk b/make/dist.mk index 74d6557..e232b76 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 31f7fd8..bd0af77 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 2c21846..42349f6 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 8978fc0..92054d6 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 0000000..9e8f4a8 --- /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 a842561..02a53cb 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 d3b308e..d16de44 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 0000000..5b2dca1 --- /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 d132e03..36b1480 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 a1f1b8c..eeaee84 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 99d463f..70d7373 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 0000000..2dfbb32 --- /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 0000000..1fca444 --- /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 4c8e028..0000000 --- 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 2067e20..0000000 --- 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 ed45670..0074aaa 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 84534fb..0a666c0 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 afbae1a..94470eb 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 fe384c1..b7796d5 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 1ac8a07..6d92af2 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 0908f30..ce7c245 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 b176010..e9f44e3 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 5f982c7..3530da7 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 a32ec6f..fe25e69 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 0d1a17e..f9830e1 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 7a642be..315c6ec 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 a16bcfd..4039302 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 e95f0c0..ad1accf 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 71d7131..c892d71 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 b80aea9..5fc56e8 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 6417876..66e7c23 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 f2dd074..1609067 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" -- GitLab