diff --git a/src/app.tsx b/src/app.tsx index e2a47c8..33ce025 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -4,7 +4,10 @@ import { render } from 'preact' import { LogseqDayjsState } from './extensions/dayjs_logseq_plugin' import { dayjs } from './context' -import { renderTemplateInBlock, renderTemplateView, renderView } from './logic' +import { + renderTemplateInBlock, renderTemplateView, renderView, + templateMacroStringForBlock, templateMacroStringForPage, +} from './logic' import { indexOfNth, lockOn, p, sleep, cleanMacroArg, parseReference, isEmptyString, @@ -270,62 +273,32 @@ async function main() { function registerBlockContextCopyCommand(label: string, commandName: string) { logseq.Editor.registerBlockContextMenuItem( label, async (e) => { - const block = await logseq.Editor.getBlock(e.uuid) - if (!block) { + const macro = await templateMacroStringForBlock(e.uuid) + if (!macro) { console.debug(p`Assertion error: block should exists`, e.uuid) return } - const templateName = PropertiesUtils.getProperty( - block, PropertiesUtils.templateProperty - ).text - let templateRef = templateName - if (!templateRef) { - const uuidExisted = PropertiesUtils.hasProperty(block.content, PropertiesUtils.idProperty) - if (!uuidExisted) - logseq.Editor.upsertBlockProperty(e.uuid, PropertiesUtils.idProperty, e.uuid) - templateRef = `((${e.uuid}))` - } - - let command = RendererMacro.command(commandName).arg(templateRef) - - const templateUsage = PropertiesUtils.getTemplateUsageString(block, {cleanMarkers: true}) - if (templateUsage) - command = command.arg(templateUsage, {raw: true}) - window.focus() // need to make an interactions with clipboard - await navigator.clipboard.writeText(command.toString()) + await navigator.clipboard.writeText(macro) - await logseq.UI.showMsg('Copied to clipboard', - 'success', {timeout: 5000}) + await logseq.UI.showMsg('Copied to clipboard', 'success', {timeout: 5000}) }) } function registerPageContextCopyCommand(label: string, commandName: string) { logseq.App.registerPageMenuItem( label, async ({ page: pageName }) => { - const pageRefString = `[[${pageName}]]` - const pageRef = parseReference(pageRefString)! - const page = await getPage(pageRef) - if (!page) { + const command = await templateMacroStringForPage(pageName) + if (!command) { console.debug(p`Assertion error: page should exists`, pageName) return } - let command = RendererMacro.command(commandName).arg(pageRefString) - - const block = await getPageFirstBlock(pageRef) - if (block) { - const templateUsage = PropertiesUtils.getTemplateUsageString(block, {cleanMarkers: true}) - if (templateUsage) - command = command.arg(templateUsage, {raw: true}) - } - window.focus() // need to make an interactions with clipboard await navigator.clipboard.writeText(command.toString()) - await logseq.UI.showMsg('Copied to clipboard', - 'success', {timeout: 5000}) + await logseq.UI.showMsg('Copied to clipboard', 'success', {timeout: 5000}) }) } diff --git a/src/logic.ts b/src/logic.ts index 1b7a186..5639dbd 100644 --- a/src/logic.ts +++ b/src/logic.ts @@ -444,3 +444,48 @@ export async function renderView( const argsContext = ArgsContext.create(template.name, args) await _renderTemplateView(slot, blockUUID, template, rawCode, argsContext) } + +export async function templateMacroStringForBlock(uuid: string, isView: boolean = false): Promise { + const block = await logseq.Editor.getBlock(uuid) + if (!block) + return '' + + const templateName = PropertiesUtils.getProperty( + block, PropertiesUtils.templateProperty + ).text + let templateRef = templateName + if (!templateRef) { + const uuidExisted = PropertiesUtils.hasProperty(block.content, PropertiesUtils.idProperty) + if (!uuidExisted) + await logseq.Editor.upsertBlockProperty(uuid, PropertiesUtils.idProperty, uuid) + templateRef = `((${uuid}))` + } + + const commandName = isView ? 'template-view' : 'template' + let command = RendererMacro.command(commandName).arg(templateRef) + + const templateUsage = Template.getUsageString(block, {cleanMarkers: true}) + if (templateUsage) + command = command.arg(templateUsage, {raw: true}) + + return command.toString() +} +export async function templateMacroStringForPage(name: string, isView: boolean = false): Promise { + const pageRefString = `[[${name}]]` + const pageRef = parseReference(pageRefString)! + const page = await getPage(pageRef) + if (!page) + return '' + + const commandName = isView ? 'template-view' : 'template' + let command = RendererMacro.command(commandName).arg(pageRefString) + + const block = await getPageFirstBlock(pageRef) + if (block) { + const templateUsage = Template.getUsageString(block, {cleanMarkers: true}) + if (templateUsage) + command = command.arg(templateUsage, {raw: true}) + } + + return command.toString() +} diff --git a/src/template.ts b/src/template.ts index 7d73ec1..5d8d485 100644 --- a/src/template.ts +++ b/src/template.ts @@ -7,7 +7,7 @@ import { RenderError } from './errors' import { getTemplateTagsContext } from './tags' import { p, IBlockNode, walkBlockTree, coerceToBool, LogseqReferenceAccessType, - PropertiesUtils, Properties + PropertiesUtils, Properties, unquote } from './utils' @@ -51,6 +51,8 @@ export interface ITemplate { } export class Template implements ITemplate { + static readonly carriagePositionMarker = '{|}' + public block: BlockEntity public name: string public includingParent: boolean @@ -58,6 +60,37 @@ export class Template implements ITemplate { private _initialized: boolean + static getUsageString( + block: BlockEntity, + opts: { cleanMarkers?: boolean } = {cleanMarkers: false}, + ): string { + let usage = PropertiesUtils.getProperty( + block, PropertiesUtils.templateUsageProperty + ).text + if (!usage) + return '' + + usage = Template.cleanUsageString(usage, { cleanMarkers: opts.cleanMarkers }) + + return usage + } + static cleanUsageString( + value: string, + opts: { cleanMarkers?: boolean } = {cleanMarkers: false}, + ) { + // value can be `quoted` or ``double quoted`` + value = unquote(value, '``') + value = unquote(value, '``') + + if (opts.cleanMarkers) { + // supports only two markers, so left intact any others + value = value.replace(Template.carriagePositionMarker, '') + value = value.replace(Template.carriagePositionMarker, '') + } + + return value + } + constructor( block: BlockEntity, args: { name?: string, diff --git a/src/ui/insert.tsx b/src/ui/insert.tsx index f28d401..aee52d1 100644 --- a/src/ui/insert.tsx +++ b/src/ui/insert.tsx @@ -5,6 +5,7 @@ import fuzzysort from 'fuzzysort' import './insert.css' import { PropertiesUtils, RendererMacro, setEditingCursorSelection, sleep, unquote } from '../utils' +import { Template } from '../template' export const isMacOS = navigator.userAgent.toUpperCase().indexOf('MAC') >= 0 @@ -47,7 +48,7 @@ async function prepareDataLogic(): Promise { else if (lowerLabel === 'template') item.label = 'Template' - item.usage = PropertiesUtils.cleanTemplateUsageString(item.usage, {cleanMarkers: false}) + item.usage = Template.cleanUsageString(item.usage, {cleanMarkers: false}) return item }) @@ -139,8 +140,8 @@ async function insertLogic( const selectionPositions = [] as number[] for (const marker of [ - PropertiesUtils.carriagePositionMarker, - PropertiesUtils.carriagePositionMarker, + Template.carriagePositionMarker, + Template.carriagePositionMarker, ]) { const position = content.indexOf(marker) if (position !== -1) { diff --git a/src/utils/logseq.ts b/src/utils/logseq.ts index 2418be4..0986178 100644 --- a/src/utils/logseq.ts +++ b/src/utils/logseq.ts @@ -376,8 +376,6 @@ export class PropertiesUtils { static readonly templateUsageProperty = 'template-usage' static readonly includingParentProperty = 'template-including-parent' - static readonly carriagePositionMarker = '{|}' - static propertyContentFormat = f`\n?^[^\\S]*${'name'}::.*$` static propertyRestrictedChars = '\\s:;,^@#~"`/|\\(){}[\\]' @@ -404,41 +402,6 @@ export class PropertiesUtils { ) } - static getTemplateUsageString( - block: BlockEntity, - opts: { - cleanMarkers?: boolean - } = {cleanMarkers: false} - ): string { - let usage = PropertiesUtils.getProperty( - block, PropertiesUtils.templateUsageProperty - ).text - if (!usage) - return '' - - usage = PropertiesUtils.cleanTemplateUsageString(usage, { cleanMarkers: opts.cleanMarkers }) - - return usage - } - static cleanTemplateUsageString( - value: string, - opts: { - cleanMarkers?: boolean - } = {cleanMarkers: false} - ) { - // value can be `quoted` or ``double quoted`` - value = unquote(value, '``') - value = unquote(value, '``') - - if (opts.cleanMarkers) { - // supports only two markers, so left intact any others - value = value.replace(PropertiesUtils.carriagePositionMarker, '') - value = value.replace(PropertiesUtils.carriagePositionMarker, '') - } - - return value - } - static getProperty(obj: BlockEntity | PageEntity, name: string): LogseqProperty { const nameCamelCased = PropertiesUtils.toCamelCase(name) @@ -607,7 +570,7 @@ export class Macro { } export class RendererMacro extends Macro { - static command(name: string) { + static command(name: string): RendererMacro { return new RendererMacro(name) }