add: update content from template
This commit is contained in:
parent
f211b62959
commit
8463a27ca8
|
|
@ -65,6 +65,7 @@ editor-toolbar-settings-openAsTab = Open as tab
|
|||
editor-toolbar-settings-openAsWindow = Open as window
|
||||
editor-toolbar-settings-showInLibrary = Show in Library
|
||||
editor-toolbar-settings-insertTemplate = Insert template
|
||||
editor-toolbar-settings-refreshTemplates = Update content from templates (Beta)
|
||||
editor-toolbar-settings-copyLink = Copy link (L{ $line })
|
||||
editor-toolbar-settings-copyLinkAtSection = Copy link (Sec. { $section })
|
||||
editor-toolbar-settings-openParent = Open Attachment
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ editor-toolbar-settings-openAsTab = Open as tab
|
|||
editor-toolbar-settings-openAsWindow = Open as window
|
||||
editor-toolbar-settings-showInLibrary = Show in Library
|
||||
editor-toolbar-settings-insertTemplate = Inserisci template
|
||||
editor-toolbar-settings-refreshTemplates = Update content from templates (Beta)
|
||||
editor-toolbar-settings-copyLink = Copia link (L{ $line })
|
||||
editor-toolbar-settings-copyLinkAtSection = Copia link (Sec. { $section })
|
||||
editor-toolbar-settings-openParent = Apri allegato
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ editor-toolbar-settings-openAsTab = Open as tab
|
|||
editor-toolbar-settings-openAsWindow = Open as window
|
||||
editor-toolbar-settings-showInLibrary = Show in Library
|
||||
editor-toolbar-settings-insertTemplate=Вставить шаблон
|
||||
editor-toolbar-settings-refreshTemplates = Update content from templates (Beta)
|
||||
editor-toolbar-settings-copyLink = Копировать Ссылку (L{ $line })
|
||||
editor-toolbar-settings-copyLinkAtSection = Копировать Ссылку (Sec. { $section })
|
||||
editor-toolbar-settings-openParent=Открыть вложение
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ editor-toolbar-settings-openAsTab = Open as tab
|
|||
editor-toolbar-settings-openAsWindow = Open as window
|
||||
editor-toolbar-settings-showInLibrary = Show in Library
|
||||
editor-toolbar-settings-insertTemplate = Insert template
|
||||
editor-toolbar-settings-refreshTemplates = Update content from templates (Beta)
|
||||
editor-toolbar-settings-copyLink = Copy link (L{ $line })
|
||||
editor-toolbar-settings-copyLinkAtSection =Copy link (Sec. { $section })
|
||||
editor-toolbar-settings-openParent = Eki Aç
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ editor-toolbar-settings-openAsTab = 在标签页中打开
|
|||
editor-toolbar-settings-openAsWindow = 在窗口中打开
|
||||
editor-toolbar-settings-showInLibrary = 在文库中显示
|
||||
editor-toolbar-settings-insertTemplate=插入模板
|
||||
editor-toolbar-settings-refreshTemplates = 更新模板生成内容 (Beta)
|
||||
editor-toolbar-settings-copyLink=复制行(L{ $line })
|
||||
editor-toolbar-settings-copyLinkAtSection=复制节(Sec. { $section })
|
||||
editor-toolbar-settings-openParent=打开附件
|
||||
|
|
|
|||
|
|
@ -83,6 +83,14 @@ Pragmas are lines start with `// @`. They have special effect and will not be re
|
|||
|
||||
Let the compiler know you are using markdown. Otherwise the template will be processed as HTML.
|
||||
|
||||
### `// @use-update`
|
||||
|
||||
Allow the generated content to be updated using the `Update content from templates` in the note editor.
|
||||
The generated content will be wrapped in separators with a YAML metadata section for update.
|
||||
This is a beta feature and can be changed/removed in the future.
|
||||
|
||||
> The template with this pragma should not contain any separator (`---` or `<hr>`) in the content.
|
||||
|
||||
### `// @author`
|
||||
|
||||
Mark the code belongs to you. Your GitHub account or your email.
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ import {
|
|||
replace,
|
||||
moveHeading,
|
||||
updateHeadingTextAtLine,
|
||||
getLineCount,
|
||||
} from "./utils/editor";
|
||||
import {
|
||||
addLineToNote,
|
||||
|
|
@ -153,6 +154,7 @@ const editor = {
|
|||
getLineAtCursor,
|
||||
getSectionAtCursor,
|
||||
getPositionAtLine,
|
||||
getLineCount,
|
||||
getTextBetween,
|
||||
getTextBetweenLines,
|
||||
moveHeading,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import { config } from "../../../package.json";
|
||||
import { getPrefJSON, registerPrefObserver, setPref, unregisterPrefObserver } from "../../utils/prefs";
|
||||
import {
|
||||
getPrefJSON,
|
||||
registerPrefObserver,
|
||||
setPref,
|
||||
unregisterPrefObserver,
|
||||
} from "../../utils/prefs";
|
||||
import { waitUtilAsync } from "../../utils/wait";
|
||||
import { PluginCEBase } from "../base";
|
||||
import { ContextPane } from "./contextPane";
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import { getPref, setPref } from "./utils/prefs";
|
|||
import { closeRelationWorker } from "./utils/relation";
|
||||
import { registerNoteLinkSection } from "./modules/workspace/link";
|
||||
import { showUserGuide } from "./modules/userGuide";
|
||||
import { refreshTemplatesInNote } from "./modules/template/refresh";
|
||||
|
||||
async function onStartup() {
|
||||
await Promise.all([
|
||||
|
|
@ -234,6 +235,8 @@ const onUpdateTemplatePicker = updateTemplatePicker;
|
|||
|
||||
const onImportTemplateFromClipboard = importTemplateFromClipboard;
|
||||
|
||||
const onRefreshTemplatesInNote = refreshTemplatesInNote;
|
||||
|
||||
const onShowImageViewer = showImageViewer;
|
||||
|
||||
const onShowExportNoteOptions = showExportNoteOptions;
|
||||
|
|
@ -269,6 +272,7 @@ export default {
|
|||
onShowTemplatePicker,
|
||||
onUpdateTemplatePicker,
|
||||
onImportTemplateFromClipboard,
|
||||
onRefreshTemplatesInNote,
|
||||
onShowImageViewer,
|
||||
onShowExportNoteOptions,
|
||||
onShowSyncDiff,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { getNoteLink } from "../../utils/link";
|
|||
import { getString } from "../../utils/locale";
|
||||
import { openLinkCreator } from "../../utils/linkCreator";
|
||||
import { slice } from "../../utils/str";
|
||||
import { refreshTemplatesInNote } from "../template/refresh";
|
||||
|
||||
export async function initEditorToolbar(editor: Zotero.EditorInstance) {
|
||||
const noteItem = editor._item;
|
||||
|
|
@ -122,6 +123,13 @@ async function getMenuData(editor: Zotero.EditorInstance) {
|
|||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
id: makeId("settings-refreshTemplates"),
|
||||
text: getString("editor.toolbar.settings.refreshTemplates"),
|
||||
callback: (e) => {
|
||||
addon.hooks.onRefreshTemplatesInNote(e.editor);
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "splitter",
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import YAML = require("yamljs");
|
||||
import { itemPicker } from "../../utils/itemPicker";
|
||||
import { getString } from "../../utils/locale";
|
||||
import { fill, slice } from "../../utils/str";
|
||||
|
|
@ -114,7 +115,7 @@ async function runTextTemplate(
|
|||
const { targetNoteId, dryRun } = options;
|
||||
const targetNoteItem = Zotero.Items.get(targetNoteId || -1);
|
||||
const sharedObj = {};
|
||||
return await runTemplate(
|
||||
let renderedString = await runTemplate(
|
||||
key,
|
||||
"targetNoteItem, sharedObj",
|
||||
[targetNoteItem, sharedObj],
|
||||
|
|
@ -122,6 +123,15 @@ async function runTextTemplate(
|
|||
dryRun,
|
||||
},
|
||||
);
|
||||
|
||||
const templateText = addon.api.template.getTemplateText(key);
|
||||
// Find if any line starts with // @use-refresh using regex
|
||||
if (/\/\/ @use-refresh/.test(templateText)) {
|
||||
renderedString = wrapYAMLData(renderedString, {
|
||||
template: key,
|
||||
});
|
||||
}
|
||||
return renderedString;
|
||||
}
|
||||
|
||||
async function runItemTemplate(
|
||||
|
|
@ -208,10 +218,20 @@ async function runItemTemplate(
|
|||
);
|
||||
|
||||
const html = results.join("\n");
|
||||
return await addon.api.convert.note2html(copyImageRefNotes, {
|
||||
let renderedString = await addon.api.convert.note2html(copyImageRefNotes, {
|
||||
targetNoteItem,
|
||||
html,
|
||||
});
|
||||
|
||||
const templateText = addon.api.template.getTemplateText(key);
|
||||
// Find if any line starts with // @use-refresh using regex
|
||||
if (/\/\/ @use-refresh/.test(templateText)) {
|
||||
renderedString = wrapYAMLData(renderedString, {
|
||||
template: key,
|
||||
items: Array.from(items.map((item) => item.libraryKey)),
|
||||
});
|
||||
}
|
||||
return renderedString;
|
||||
}
|
||||
|
||||
async function getItemTemplateData() {
|
||||
|
|
@ -259,3 +279,10 @@ async function getItemTemplateData() {
|
|||
}
|
||||
return await itemPicker();
|
||||
}
|
||||
|
||||
function wrapYAMLData(str: string, data: any) {
|
||||
const yamlContent = YAML.stringify(data, 4);
|
||||
return `<hr>
|
||||
<pre>${yamlContent}</pre>${str}
|
||||
<hr>`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,78 @@
|
|||
import YAML = require("yamljs");
|
||||
import { htmlUnescape } from "../../utils/str";
|
||||
|
||||
export { refreshTemplatesInNote };
|
||||
|
||||
async function refreshTemplatesInNote(editor: Zotero.EditorInstance) {
|
||||
const lines = addon.api.note.getLinesInNote(editor._item);
|
||||
let startIndex = -1;
|
||||
const matchedIndexPairs: { from: number; to: number }[] = [];
|
||||
|
||||
function isTemplateWrapperStart(index: number) {
|
||||
return (
|
||||
index < lines.length - 1 &&
|
||||
lines[index].trim() === "<hr>" &&
|
||||
lines[index + 1].trim().startsWith("<pre>") &&
|
||||
lines[index + 1].includes("template: ")
|
||||
);
|
||||
}
|
||||
|
||||
function isTemplateWrapperEnd(index: number) {
|
||||
return startIndex >= 0 && lines[index].trim() === "<hr>";
|
||||
}
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
// Match: 1. current line is <hr>; 2. next line is <pre> and contains template key; 3. then contains any number of lines; until end with <hr> line
|
||||
if (isTemplateWrapperStart(i)) {
|
||||
startIndex = i;
|
||||
continue;
|
||||
}
|
||||
if (isTemplateWrapperEnd(i)) {
|
||||
matchedIndexPairs.push({ from: startIndex, to: i });
|
||||
startIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
let indexOffset = 0;
|
||||
for (const { from, to } of matchedIndexPairs) {
|
||||
const yamlContent = htmlUnescape(
|
||||
lines[from + 1].replace("<pre>", "").replace("</pre>", ""),
|
||||
{ excludeLineBreak: true },
|
||||
);
|
||||
const { template, items } = YAML.parse(yamlContent) as {
|
||||
template: string;
|
||||
items?: string[];
|
||||
};
|
||||
let html = "";
|
||||
if (template.toLowerCase().startsWith("[item]")) {
|
||||
html = await addon.api.template.runItemTemplate(template, {
|
||||
targetNoteId: editor._item.id,
|
||||
itemIds: items
|
||||
?.map((id) => {
|
||||
const [libraryID, key] = id.split("/");
|
||||
return Zotero.Items.getIDFromLibraryAndKey(Number(libraryID), key);
|
||||
})
|
||||
.filter((id) => !!id) as number[],
|
||||
});
|
||||
} else {
|
||||
html = await addon.api.template.runTextTemplate(template, {
|
||||
targetNoteId: editor._item.id,
|
||||
});
|
||||
}
|
||||
const currentLineCount = addon.api.editor.getLineCount(editor);
|
||||
addon.api.editor.del(
|
||||
editor,
|
||||
addon.api.editor.getPositionAtLine(editor, from + indexOffset, "start"),
|
||||
addon.api.editor.getPositionAtLine(editor, to + indexOffset + 1, "start"),
|
||||
);
|
||||
const position = addon.api.editor.getPositionAtLine(
|
||||
editor,
|
||||
from + indexOffset,
|
||||
"start",
|
||||
);
|
||||
addon.api.editor.insert(editor, html, position);
|
||||
|
||||
const newLineCount = addon.api.editor.getLineCount(editor);
|
||||
indexOffset -= currentLineCount - newLineCount;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ export {
|
|||
getSectionAtCursor,
|
||||
getPositionAtLine,
|
||||
getPositionAtCursor,
|
||||
getLineCount,
|
||||
getURLAtCursor,
|
||||
updateImageDimensionsAtCursor,
|
||||
updateURLAtCursor,
|
||||
|
|
@ -251,6 +252,10 @@ function getPositionAtLine(
|
|||
);
|
||||
}
|
||||
|
||||
function getLineCount(editor: Zotero.EditorInstance) {
|
||||
return getEditorCore(editor).view.docView.children.length;
|
||||
}
|
||||
|
||||
function getURLAtCursor(editor: Zotero.EditorInstance) {
|
||||
const core = getEditorCore(editor);
|
||||
return core.pluginState.link.getHref(core.view.state);
|
||||
|
|
|
|||
|
|
@ -127,13 +127,20 @@ export function htmlEscape(doc: Document, str: string) {
|
|||
return div.innerHTML.replace(/"/g, """).replace(/'/g, "'");
|
||||
}
|
||||
|
||||
export function htmlUnescape(str: string) {
|
||||
const map = {
|
||||
export function htmlUnescape(
|
||||
str: string,
|
||||
options: {
|
||||
excludeLineBreak?: boolean;
|
||||
} = {},
|
||||
) {
|
||||
const map: Record<string, string> = {
|
||||
" ": " ",
|
||||
""": '"',
|
||||
"'": "'",
|
||||
"\n": "",
|
||||
};
|
||||
if (!options.excludeLineBreak) {
|
||||
map["\n"] = "";
|
||||
}
|
||||
const re = new RegExp(Object.keys(map).join("|"), "g");
|
||||
return str.replace(re, function (match) {
|
||||
return map[match as keyof typeof map];
|
||||
|
|
|
|||
Loading…
Reference in New Issue