Skip to content

Commit 53574f0

Browse files
committed
startup scripts
1 parent 296bd00 commit 53574f0

File tree

12 files changed

+260
-31
lines changed

12 files changed

+260
-31
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('Hello from startupScript1.js');
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
console.log('Hello from startupScript2.js');

jsEngine/Settings.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

jsEngine/api/Internal.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,13 @@ export class InternalAPI {
124124
obsidian: Obsidian,
125125
};
126126
}
127+
128+
/**
129+
* Runs all startup scripts defined in the plugins settings.
130+
*/
131+
public async executeStartupScripts(): Promise<void> {
132+
for (const script of this.apiInstance.plugin.settings.startupScripts ?? []) {
133+
await this.executeFileSimple(script);
134+
}
135+
}
127136
}

jsEngine/main.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ import { Engine } from 'jsEngine/engine/Engine';
55
import { JSFileSelectModal } from 'jsEngine/fileRunner/JSFileSelectModal';
66
import { JsMDRC } from 'jsEngine/JsMDRC';
77
import { MessageManager } from 'jsEngine/messages/MessageManager';
8-
import type { JsEnginePluginSettings } from 'jsEngine/Settings';
9-
import { JS_ENGINE_DEFAULT_SETTINGS } from 'jsEngine/Settings';
8+
import type { JsEnginePluginSettings } from 'jsEngine/settings/Settings';
9+
import { JS_ENGINE_DEFAULT_SETTINGS, JsEnginePluginSettingTab } from 'jsEngine/settings/Settings';
1010
import { Validators } from 'jsEngine/utils/Validators';
1111
import type { App, PluginManifest } from 'obsidian';
1212
import { Plugin } from 'obsidian';
1313

1414
export default class JsEnginePlugin extends Plugin {
15-
settings: JsEnginePluginSettings | undefined;
15+
settings!: JsEnginePluginSettings;
1616
messageManager: MessageManager;
1717
jsEngine: Engine;
1818
api: API;
@@ -30,7 +30,7 @@ export default class JsEnginePlugin extends Plugin {
3030
async onload(): Promise<void> {
3131
await this.loadSettings();
3232

33-
// this.addSettingTab(new JsEnginePluginSettingTab(this.app, this));
33+
this.addSettingTab(new JsEnginePluginSettingTab(this.app, this));
3434

3535
this.messageManager.initStatusBarItem();
3636

@@ -48,6 +48,10 @@ export default class JsEnginePlugin extends Plugin {
4848
},
4949
});
5050

51+
this.app.workspace.onLayoutReady(() => {
52+
void this.api.internal.executeStartupScripts();
53+
});
54+
5155
await this.registerCodeMirrorMode();
5256
}
5357

jsEngine/obsidian-ex.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ declare module 'obsidian' {
99
getPlugin: (plugin: string) => Plugin;
1010
};
1111
}
12+
13+
interface MenuItem {
14+
setWarning(warn: boolean): void;
15+
}
1216
}
1317

1418
export {};

jsEngine/settings/Settings.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type JsEnginePlugin from 'jsEngine/main';
2+
import { StartupScriptsModal } from 'jsEngine/settings/StartupScriptModal';
3+
import type { App } from 'obsidian';
4+
import { PluginSettingTab, Setting } from 'obsidian';
5+
6+
export interface JsEnginePluginSettings {
7+
startupScripts?: string[];
8+
}
9+
10+
export const JS_ENGINE_DEFAULT_SETTINGS: JsEnginePluginSettings = {
11+
startupScripts: [],
12+
};
13+
14+
export class JsEnginePluginSettingTab extends PluginSettingTab {
15+
plugin: JsEnginePlugin;
16+
17+
constructor(app: App, plugin: JsEnginePlugin) {
18+
super(app, plugin);
19+
this.plugin = plugin;
20+
}
21+
22+
display(): void {
23+
this.containerEl.empty();
24+
25+
if (!this.plugin.settings) {
26+
return;
27+
}
28+
29+
// this.containerEl.createEl('p', { text: 'Currently Empty, but there will be stuff here later.' });
30+
31+
new Setting(this.containerEl).setName('Startup scripts').addButton(button => {
32+
button.setButtonText('Manage').onClick(() => {
33+
new StartupScriptsModal(this.plugin).open();
34+
});
35+
});
36+
}
37+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import type JsEnginePlugin from 'jsEngine/main';
2+
import StartupScripts from 'jsEngine/settings/StartupScripts.svelte';
3+
import { Modal } from 'obsidian';
4+
import { mount, unmount } from 'svelte';
5+
6+
export class StartupScriptsModal extends Modal {
7+
plugin: JsEnginePlugin;
8+
component?: ReturnType<typeof StartupScripts>;
9+
10+
constructor(plugin: JsEnginePlugin) {
11+
super(plugin.app);
12+
this.plugin = plugin;
13+
}
14+
15+
onOpen(): void {
16+
this.contentEl.empty();
17+
18+
this.component = mount(StartupScripts, {
19+
target: this.contentEl,
20+
props: {
21+
modal: this,
22+
startupScripts: this.plugin.settings.startupScripts ?? [],
23+
},
24+
});
25+
}
26+
27+
onClose(): void {
28+
if (this.component) {
29+
unmount(this.component);
30+
}
31+
}
32+
33+
save(startupScripts: string[]): void {
34+
this.plugin.settings.startupScripts = startupScripts;
35+
void this.plugin.saveSettings();
36+
}
37+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<script lang="ts">
2+
import { JSFileSelectModal } from 'jsEngine/fileRunner/JSFileSelectModal';
3+
import Button from 'jsEngine/utils/Button.svelte';
4+
import ModalButtonGroup from 'jsEngine/utils/ModalButtonGroup.svelte';
5+
import type { StartupScriptsModal } from './StartupScriptModal';
6+
import { ButtonStyleType } from 'jsEngine/utils/Util';
7+
import { Menu } from 'obsidian';
8+
import Icon from 'jsEngine/utils/Icon.svelte';
9+
10+
let {
11+
startupScripts: initialStartupScripts,
12+
modal,
13+
}: {
14+
startupScripts: string[];
15+
modal: StartupScriptsModal;
16+
} = $props();
17+
18+
let startupScripts = $state(initialStartupScripts);
19+
20+
function addScript() {
21+
new JSFileSelectModal(modal.plugin, async selected => {
22+
startupScripts.push(selected.path);
23+
}).open();
24+
}
25+
26+
function save() {
27+
modal.save($state.snapshot(startupScripts));
28+
modal.close();
29+
}
30+
31+
function cancel() {
32+
modal.close();
33+
}
34+
35+
function contextMenu(e: MouseEvent, index: number) {
36+
let menu = new Menu();
37+
if (index > 0) {
38+
menu.addItem(item => {
39+
item.setTitle('Move up');
40+
item.setIcon('arrow-up');
41+
item.onClick(() => {
42+
const temp = startupScripts[index - 1];
43+
startupScripts[index - 1] = startupScripts[index];
44+
startupScripts[index] = temp;
45+
});
46+
});
47+
}
48+
if (index < startupScripts.length - 1) {
49+
menu.addItem(item => {
50+
item.setTitle('Move down');
51+
item.setIcon('arrow-down');
52+
item.onClick(() => {
53+
const temp = startupScripts[index + 1];
54+
startupScripts[index + 1] = startupScripts[index];
55+
startupScripts[index] = temp;
56+
});
57+
});
58+
}
59+
60+
menu.addItem(item => {
61+
item.setTitle('Remove');
62+
item.setIcon('x');
63+
item.setWarning(true);
64+
item.onClick(() => {
65+
startupScripts.splice(index, 1);
66+
});
67+
});
68+
69+
menu.showAtMouseEvent(e);
70+
}
71+
</script>
72+
73+
<div>
74+
<div class="js-engine-list">
75+
{#each startupScripts as script, i}
76+
<div class="js-engine-list-item">
77+
<span>{script}</span>
78+
<Button onclick={e => contextMenu(e, i)} variant={ButtonStyleType.PLAIN} tooltip="Edit">
79+
<Icon iconName="ellipsis-vertical" />
80+
</Button>
81+
</div>
82+
{/each}
83+
</div>
84+
85+
<Button onclick={() => addScript()}>Add startup script</Button>
86+
87+
<ModalButtonGroup>
88+
<Button onclick={() => save()} variant={ButtonStyleType.PRIMARY} tooltip="Save changes">Save</Button>
89+
<Button onclick={() => cancel()} tooltip="Revert changes">Cancel</Button>
90+
</ModalButtonGroup>
91+
</div>

jsEngine/utils/Icon.svelte

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<!--adapted from @joethei's code: https://github.com/joethei/obsidian-rss/blob/master/src/view/IconComponent.svelte-->
2+
<!--adapted from @javalent's code: https://discord.com/channels/686053708261228577/840286264964022302/902949764209987654-->
3+
<script lang="ts">
4+
import { setIcon } from 'obsidian';
5+
6+
const {
7+
iconName = '',
8+
}: {
9+
iconName?: string;
10+
} = $props();
11+
12+
let iconEl: HTMLElement | undefined = $state();
13+
14+
$effect(() => (iconEl ? setIcon(iconEl, iconName) : undefined));
15+
</script>
16+
17+
{#if iconName.length > 0}
18+
<div class="js-engine-icon-wrapper" bind:this={iconEl}></div>
19+
{/if}

0 commit comments

Comments
 (0)