diff --git a/.changeset/tricky-chefs-cry.md b/.changeset/tricky-chefs-cry.md
new file mode 100644
index 0000000..4a76aa6
--- /dev/null
+++ b/.changeset/tricky-chefs-cry.md
@@ -0,0 +1,5 @@
+---
+'anki-templates': patch
+---
+
+feat(tf): optimize experience of `items` in mobile (优化移动端`items` 字段体验)
diff --git a/README.md b/README.md
index cc57907..49a5b35 100644
--- a/README.md
+++ b/README.md
@@ -39,9 +39,9 @@ Note: When all options are empty, the template will behave as a basic Q&A templa
Notes for `items`
-- All sub-questions should be in an unordered list format
-- Each sub-question must begin with "T:" or "F:", indicating whether the sub-question is true or false
-- Pay special attention to ensuring "T/F" is followed by an English half-width colon
+- All sub-questions should meet the format constriant
+- Each sub-question must begin with a line "T===" or "F===", indicating whether the sub-question is true or false
+- Pay special attention to ensuring "T/F" is followed by three or more equal signs
| Field name | Description |
| ---------- | ------------------------------------------------------------------------------------------------------------- |
diff --git a/release.json b/release.json
index 051f821..5f5a10a 100644
--- a/release.json
+++ b/release.json
@@ -44,7 +44,7 @@
{
"fields": {
"question": "This is the stem of the question. It supports various content formats in Anki, including bold, formulas, etc.",
- "items": "
- T: All sub-questions should be in an unordered list format
- T: Each sub-question must begin with \"T:\" or \"F:\", indicating whether the sub-question is true or false
- T: Pay special attention to ensuring \"T/F\" is followed by an English half-width colon
",
+ "items": "T===
All sub-questions should meet the format constriant
T===
Each sub-question must begin with a line \"T===\" or \"F===\", indicating whether the sub-question is true or false
T===
Pay special attention to ensuring \"T/F\" is followed by three or more equal signs",
"note": "note"
}
}
diff --git a/src/utils/extract-tf-items.ts b/src/utils/extract-tf-items.ts
index 4d5459e..5f301f0 100644
--- a/src/utils/extract-tf-items.ts
+++ b/src/utils/extract-tf-items.ts
@@ -1,3 +1,7 @@
+function isBrNode(node?: Node | null): node is HTMLBRElement {
+ return node?.nodeType === Node.ELEMENT_NODE && node.nodeName === 'BR';
+}
+
export interface TfItem {
node: HTMLDivElement;
answer: boolean;
@@ -7,6 +11,40 @@ export function extractTfItems(field: HTMLElement): TfItem[] {
if (!field) {
return [];
}
+ const textContent = field.textContent?.trim();
+ if (!textContent) {
+ return [];
+ }
+ if (!/^[TF]={3,}/.test(textContent)) {
+ return extractTfItemsLegacy(field);
+ }
+
+ const items: TfItem[] = [];
+ const childNodes = Array.from(field.childNodes);
+ for (const node of childNodes) {
+ const childText = node.textContent || '';
+ const match = childText.match(/^(T|F)={3,}/);
+ const last = items[items.length - 1];
+ if (match) {
+ items.push({
+ answer: match[1] === 'T',
+ node: document.createElement('div'),
+ });
+ if (last) {
+ while (isBrNode(last.node.lastChild)) {
+ last.node.lastChild.remove();
+ }
+ }
+ } else {
+ if (last && !(last.node.childNodes.length === 0 && isBrNode(node))) {
+ last.node.appendChild(node);
+ }
+ }
+ }
+ return items;
+}
+
+export function extractTfItemsLegacy(field: HTMLElement): TfItem[] {
const itemNodes = field.querySelector('ul')?.querySelectorAll(':scope > li');
if (!itemNodes?.length) {
return [];