Skip to content

Commit

Permalink
feat: support for executing scripts from NTB callouts
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisgurney committed Nov 26, 2024
1 parent fb70acb commit ce141f1
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 49 deletions.
18 changes: 6 additions & 12 deletions src/Settings/NoteToolbarSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,12 @@ export const RELEASES_URL = 'https://github.com/chrisgurney/obsidian-note-toolba
export const COMMAND_DOES_NOT_EXIST = 'COMMAND_DOES_NOT_EXIST';

export const SCRIPT_ATTRIBUTE_MAP: Record<string, string> = {
'expression': 'expr',
'sourceFile': 'src',
'sourceFunction': 'func',
'sourceArgs': 'args',
'outputContainer': 'callout',
'outputFile': 'dest',
'expr': 'expression',
'src': 'sourceFile',
'func': 'sourceFunction',
'args': 'sourceArgs',
'callout': 'outputContainer',
'dest': 'outputFile',
'expression': 'data-expr',
'sourceFile': 'data-src',
'sourceFunction': 'data-func',
'sourceArgs': 'data-args',
'outputContainer': 'data-callout',
'outputFile': 'data-dest'
};

export const LINK_OPTIONS = {
Expand Down
14 changes: 7 additions & 7 deletions src/Utils/ImportExport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ async function exportToCalloutList(
}
else {
const encodedValue = escapeAttribute(String(value));
return encodedValue ? `data-${SCRIPT_ATTRIBUTE_MAP[key]}="${encodedValue}"` : '';
return encodedValue ? `${SCRIPT_ATTRIBUTE_MAP[key]}="${encodedValue}"` : '';
}
})
.join(' ');
Expand Down Expand Up @@ -351,12 +351,12 @@ export async function importFromCallout(
const element = doc.body.firstElementChild;
scriptConfig = {
pluginFunction: dataUriValue,
expression: element?.getAttribute(`data-${SCRIPT_ATTRIBUTE_MAP['expression']}`) ?? undefined,
sourceFile: element?.getAttribute(`data-${SCRIPT_ATTRIBUTE_MAP['sourceFile']}`) ?? undefined,
sourceFunction: element?.getAttribute(`data-${SCRIPT_ATTRIBUTE_MAP['sourceFunction']}`) ?? undefined,
sourceArgs: element?.getAttribute(`data-${SCRIPT_ATTRIBUTE_MAP['sourceArgs']}`) ?? undefined,
outputContainer: element?.getAttribute(`data-${SCRIPT_ATTRIBUTE_MAP['outputContainer']}`) ?? undefined,
outputFile: element?.getAttribute(`data-${SCRIPT_ATTRIBUTE_MAP['outputFile']}`) ?? undefined,
expression: element?.getAttribute(SCRIPT_ATTRIBUTE_MAP['expression']) ?? undefined,
sourceFile: element?.getAttribute(SCRIPT_ATTRIBUTE_MAP['sourceFile']) ?? undefined,
sourceFunction: element?.getAttribute(SCRIPT_ATTRIBUTE_MAP['sourceFunction']) ?? undefined,
sourceArgs: element?.getAttribute(SCRIPT_ATTRIBUTE_MAP['sourceArgs']) ?? undefined,
outputContainer: element?.getAttribute(SCRIPT_ATTRIBUTE_MAP['outputContainer']) ?? undefined,
outputFile: element?.getAttribute(SCRIPT_ATTRIBUTE_MAP['outputFile']) ?? undefined,
} as ScriptConfig;
}
break;
Expand Down
91 changes: 61 additions & 30 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CachedMetadata, Editor, FrontMatterCache, ItemView, MarkdownFileInfo, MarkdownView, MarkdownViewModeType, Menu, MenuItem, MenuPositionDef, Notice, Platform, Plugin, TFile, TFolder, WorkspaceLeaf, addIcon, debounce, getIcon, setIcon, setTooltip } from 'obsidian';
import { NoteToolbarSettingTab } from 'Settings/UI/NoteToolbarSettingTab';
import { ToolbarSettings, NoteToolbarSettings, PositionType, ItemType, CalloutAttr, t, ToolbarItemSettings, ToolbarStyle, RibbonAction, VIEW_TYPE_WHATS_NEW, ScriptConfig, LINK_OPTIONS } from 'Settings/NoteToolbarSettings';
import { ToolbarSettings, NoteToolbarSettings, PositionType, ItemType, CalloutAttr, t, ToolbarItemSettings, ToolbarStyle, RibbonAction, VIEW_TYPE_WHATS_NEW, ScriptConfig, LINK_OPTIONS, SCRIPT_ATTRIBUTE_MAP } from 'Settings/NoteToolbarSettings';
import { calcComponentVisToggles, calcItemVisToggles, debugLog, isValidUri, putFocusInMenu, getLinkUiDest, isViewCanvas, insertTextAtCursor, getUUID } from 'Utils/Utils';
import ToolbarSettingsModal from 'Settings/UI/Modals/ToolbarSettingsModal';
import { WhatsNewView } from 'Settings/UI/Views/WhatsNewView';
Expand Down Expand Up @@ -860,15 +860,39 @@ export default class NoteToolbarPlugin extends Plugin {
let dataEl = clickedItemEl?.nextElementSibling;
if (dataEl) {
// make sure it's a valid attribute, and get its value
let attribute = Object.values(CalloutAttr).find(attr => dataEl?.hasAttribute(attr));
const attribute = Object.values(CalloutAttr).find(attr => dataEl?.hasAttribute(attr));
attribute ? e.preventDefault() : undefined; // prevent callout code block from opening
let value = attribute ? dataEl?.getAttribute(attribute) : null;
const value = attribute ? dataEl?.getAttribute(attribute) : null;

switch (attribute) {
case CalloutAttr.Command:
case CalloutAttr.CommandNtb:
this.handleLinkCommand(value);
break;
case CalloutAttr.Dataview:
case CalloutAttr.JsEngine:
case CalloutAttr.Templater:
const scriptConfig = {
pluginFunction: value,
expression: dataEl?.getAttribute(SCRIPT_ATTRIBUTE_MAP['expression']) ?? undefined,
sourceFile: dataEl?.getAttribute(SCRIPT_ATTRIBUTE_MAP['sourceFile']) ?? undefined,
sourceFunction: dataEl?.getAttribute(SCRIPT_ATTRIBUTE_MAP['sourceFunction']) ?? undefined,
sourceArgs: dataEl?.getAttribute(SCRIPT_ATTRIBUTE_MAP['sourceArgs']) ?? undefined,
outputContainer: dataEl?.getAttribute(SCRIPT_ATTRIBUTE_MAP['outputContainer']) ?? undefined,
outputFile: dataEl?.getAttribute(SCRIPT_ATTRIBUTE_MAP['outputFile']) ?? undefined,
} as ScriptConfig;
switch (attribute) {
case CalloutAttr.Dataview:
this.handleLinkScript(ItemType.Dataview, scriptConfig);
break;
case CalloutAttr.JsEngine:
this.handleLinkScript(ItemType.JsEngine, scriptConfig);
break;
case CalloutAttr.Templater:
this.handleLinkScript(ItemType.Templater, scriptConfig);
break;
}
break;
case CalloutAttr.Folder:
case CalloutAttr.FolderNtb:
this.handleLinkFolder(value);
Expand Down Expand Up @@ -966,6 +990,15 @@ export default class NoteToolbarPlugin extends Plugin {
await this.handleLink(item.uuid, item.link, item.linkAttr.type, item.linkAttr.commandId, event, file);
}

/**
* Handles the provided script item, based on the provided configuration.
*/
async handleItemScript(toolbarItem: ToolbarItemSettings | undefined) {
if (toolbarItem && toolbarItem?.scriptConfig) {
await this.handleLinkScript(toolbarItem.linkAttr.type, toolbarItem.scriptConfig);
}
}

/**
* Handles the link provided.
* @param uuid ID of the item
Expand Down Expand Up @@ -1024,7 +1057,7 @@ export default class NoteToolbarPlugin extends Plugin {
case ItemType.Templater:
this.updateAdapters();
if (this.settings.scriptingEnabled) {
(file && (file !== activeFile)) ? await this.handleLinkInSidebar(toolbarItem, file) : await this.handleScriptItem(toolbarItem);
(file && (file !== activeFile)) ? await this.handleLinkInSidebar(toolbarItem, file) : await this.handleItemScript(toolbarItem);
}
else {
new Notice(t('notice.error-scripting-not-enabled'));
Expand Down Expand Up @@ -1067,33 +1100,31 @@ export default class NoteToolbarPlugin extends Plugin {
}

/**
* Handles the provided script item, based on the provided configuration.
* Executes the provided script using the provided configuration.
* @param type type of script.
* @param scriptConfig ScriptConfig to execute.
*/
async handleScriptItem(toolbarItem: ToolbarItemSettings | undefined) {
if (toolbarItem) {
type ScriptType = Extract<keyof typeof LINK_OPTIONS, ItemType.Dataview | ItemType.JsEngine | ItemType.Templater>;
if (toolbarItem?.scriptConfig) {
const adapter = this.getAdapterForItemType(toolbarItem.linkAttr.type);
if (!adapter) {
new Notice(t('notice.error-scripting-plugin-not-enabled', { plugin: LINK_OPTIONS[toolbarItem.linkAttr.type as ScriptType] }));
return;
}
let result;
switch (toolbarItem.linkAttr.type) {
case ItemType.Dataview:
result = await this.dvAdapter?.use(toolbarItem?.scriptConfig);
break;
case ItemType.JsEngine:
result = await this.jsAdapter?.use(toolbarItem?.scriptConfig);
break;
case ItemType.Templater:
result = await this.tpAdapter?.use(toolbarItem?.scriptConfig);
break;
}
result ? insertTextAtCursor(this.app, result) : undefined;
await this.app.commands.executeCommandById('editor:focus');
}
async handleLinkScript(type: ItemType, scriptConfig: ScriptConfig) {
type ScriptType = Extract<keyof typeof LINK_OPTIONS, ItemType.Dataview | ItemType.JsEngine | ItemType.Templater>;
const adapter = this.getAdapterForItemType(type);
if (!adapter) {
new Notice(t('notice.error-scripting-plugin-not-enabled', { plugin: LINK_OPTIONS[type as ScriptType] }));
return;
}
let result;
switch (type) {
case ItemType.Dataview:
result = await this.dvAdapter?.use(scriptConfig);
break;
case ItemType.JsEngine:
result = await this.jsAdapter?.use(scriptConfig);
break;
case ItemType.Templater:
result = await this.tpAdapter?.use(scriptConfig);
break;
}
result ? insertTextAtCursor(this.app, result) : undefined;
await this.app.commands.executeCommandById('editor:focus');
}

/**
Expand Down Expand Up @@ -1127,7 +1158,7 @@ export default class NoteToolbarPlugin extends Plugin {
case ItemType.Dataview:
case ItemType.JsEngine:
case ItemType.Templater:
await this.handleScriptItem(toolbarItem);
await this.handleItemScript(toolbarItem);
break;
}
sidebarTab.detach();
Expand Down

0 comments on commit ce141f1

Please sign in to comment.