Skip to content

Commit 0d86969

Browse files
committed
markdown builder list and clear all messages button
1 parent e75a8b1 commit 0d86969

File tree

8 files changed

+196
-72
lines changed

8 files changed

+196
-72
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ This plugin for Obsidian allows you to run JavaScript from within your notes usi
44

55
## Usage
66

7-
Start by creating a code block with the `js-engine` plugin.
8-
Inside the code block you can write what ever JavaScript code that you want.
7+
Start by creating a code block with the `js-engine` plugin.
8+
Inside the code block you can write what ever JavaScript code that you want.
99
The plugin will run the JavaScript and render the returned value in place of the code block.
1010

1111
## API Docs

exampleVault/Test.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,26 @@ blockquote.createParagraph("This is another test paragraph.")
4242
callout.createTable(["Column 1", "Column 2"], [
4343
["data 1", "**data 2**"],
4444
["data 3", "data 4"],
45-
]);
45+
])
46+
47+
callout.addText('And now a list.')
48+
49+
let list = callout.createList(false)
50+
list.addText('test')
51+
list.createTable(["Column 1", "Column 2"], [
52+
["data 1", "**data 2**"],
53+
["data 3", "data 4"],
54+
])
55+
56+
let sublist = list.createList(true)
57+
sublist.addText('sub list')
58+
sublist.addCode('this is some code')
59+
60+
list.addText('another Element')
61+
62+
let sublist2 = list.createList(false)
63+
sublist2.addText('another sub list')
64+
4665
4766
return markdownBuilder
4867
```
@@ -166,5 +185,5 @@ return reactive;
166185
const el = container.createEl("button", {text: "Click me"})
167186
el.addEventListener("click", () => {
168187
new obsidian.Notice("Hello")
169-
});
170-
```
188+
});
189+
```

jsEngine/api/MarkdownAPI.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
CodeBlockElement,
77
CodeElement,
88
HeadingElement,
9+
ListElement,
910
ParagraphElement,
1011
TableElement,
1112
TextElement,
@@ -141,4 +142,13 @@ export class MarkdownAPI {
141142
public createTable(header: string[], body: string[][]): TableElement {
142143
return new TableElement(header, body);
143144
}
145+
146+
/**
147+
* Creates a new markdown list element.
148+
*
149+
* @param ordered whether the list should be ordered or not (use 1. or -)
150+
*/
151+
createList(ordered: boolean): ListElement {
152+
return new ListElement(ordered);
153+
}
144154
}

jsEngine/api/markdown/AbstractMarkdownElementContainer.ts

Lines changed: 103 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ export abstract class AbstractMarkdownElementContainer extends AbstractMarkdownE
102102
this.addElement(element);
103103
return element;
104104
}
105+
106+
createList(ordered: boolean): ListElement {
107+
const element = new ListElement(ordered);
108+
this.addElement(element);
109+
return element;
110+
}
105111
}
106112

107113
// --------------------------------------------
@@ -166,6 +172,85 @@ export class CodeElement extends AbstractMarkdownLiteral {
166172
}
167173
}
168174

175+
/**
176+
* Represents a markdown table.
177+
*/
178+
export class TableElement extends AbstractMarkdownLiteral {
179+
header: string[];
180+
body: string[][];
181+
182+
constructor(header: string[], body: string[][]) {
183+
super();
184+
185+
this.header = header;
186+
this.body = body;
187+
}
188+
189+
public toString(): string {
190+
const rows = this.body.length;
191+
if (rows === 0) {
192+
return '';
193+
}
194+
195+
const columns = this.header.length;
196+
if (columns === 0) {
197+
return '';
198+
}
199+
for (const row of this.body) {
200+
if (row.length !== columns) {
201+
throw new Error('Table rows are do not contain the same number of columns.');
202+
}
203+
}
204+
205+
const longestStringInColumns: number[] = [];
206+
207+
for (let i = 0; i < columns; i++) {
208+
let longestStringInColumn = 0;
209+
210+
if (this.header[i].length > longestStringInColumn) {
211+
longestStringInColumn = this.header[i].length;
212+
}
213+
for (const row of this.body) {
214+
if (row[i].length > longestStringInColumn) {
215+
longestStringInColumn = row[i].length;
216+
}
217+
}
218+
219+
longestStringInColumns.push(longestStringInColumn);
220+
}
221+
222+
let table = '';
223+
224+
// build header
225+
table += '|';
226+
for (let j = 0; j < columns; j++) {
227+
let element = this.header[j];
228+
element += ' '.repeat(longestStringInColumns[j] - element.length);
229+
table += ' ' + element + ' |';
230+
}
231+
table += '\n';
232+
// build divider
233+
table += '|';
234+
for (let j = 0; j < columns; j++) {
235+
table += ' ' + '-'.repeat(longestStringInColumns[j]) + ' |';
236+
}
237+
table += '\n';
238+
239+
// build body
240+
for (let i = 0; i < rows; i++) {
241+
table += '|';
242+
for (let j = 0; j < columns; j++) {
243+
let element = this.body[i][j];
244+
element += ' '.repeat(longestStringInColumns[j] - element.length);
245+
table += ' ' + element + ' |';
246+
}
247+
table += '\n';
248+
}
249+
250+
return table;
251+
}
252+
}
253+
169254
// --------------------------------------------
170255
// NON LITERALS
171256
// --------------------------------------------
@@ -271,85 +356,36 @@ export class CalloutElement extends AbstractMarkdownElementContainer {
271356
}
272357
}
273358

274-
/**
275-
* Represents a markdown table.
276-
*/
277-
export class TableElement extends AbstractMarkdownElementContainer {
278-
header: string[];
279-
body: string[][];
359+
export class ListElement extends AbstractMarkdownElementContainer {
360+
ordered: boolean;
280361

281-
constructor(header: string[], body: string[][]) {
362+
constructor(ordered: boolean) {
282363
super();
283364

284-
this.header = header;
285-
this.body = body;
365+
this.ordered = ordered;
286366
}
287367

288368
public allowElement(_: AbstractMarkdownElement): boolean {
289369
return true;
290370
}
291371

292-
public toString(): string {
293-
const rows = this.body.length;
294-
if (rows === 0) {
295-
return '';
296-
}
297-
298-
const columns = this.header.length;
299-
if (columns === 0) {
300-
return '';
301-
}
302-
for (const row of this.body) {
303-
if (row.length !== columns) {
304-
throw new Error('Table rows are do not contain the same number of columns.');
305-
}
372+
private getPrefix(i: number): string {
373+
if (this.ordered) {
374+
return `${i + 1}. `;
375+
} else {
376+
return `- `;
306377
}
378+
}
307379

308-
const longestStringInColumns: number[] = [];
309-
310-
for (let i = 0; i < columns; i++) {
311-
let longestStringInColumn = 0;
312-
313-
if (this.header[i].length > longestStringInColumn) {
314-
longestStringInColumn = this.header[i].length;
315-
}
316-
for (const row of this.body) {
317-
if (row[i].length > longestStringInColumn) {
318-
longestStringInColumn = row[i].length;
380+
public toString(): string {
381+
return this.markdownElements
382+
.map((x, i) => {
383+
if (x instanceof ListElement) {
384+
return `\t${x.toString().replaceAll('\n', '\n\t')}`;
319385
}
320-
}
321-
322-
longestStringInColumns.push(longestStringInColumn);
323-
}
324-
325-
let table = '';
326386

327-
// build header
328-
table += '|';
329-
for (let j = 0; j < columns; j++) {
330-
let element = this.header[j];
331-
element += ' '.repeat(longestStringInColumns[j] - element.length);
332-
table += ' ' + element + ' |';
333-
}
334-
table += '\n';
335-
// build divider
336-
table += '|';
337-
for (let j = 0; j < columns; j++) {
338-
table += ' ' + '-'.repeat(longestStringInColumns[j]) + ' |';
339-
}
340-
table += '\n';
341-
342-
// build body
343-
for (let i = 0; i < rows; i++) {
344-
table += '|';
345-
for (let j = 0; j < columns; j++) {
346-
let element = this.body[i][j];
347-
element += ' '.repeat(longestStringInColumns[j] - element.length);
348-
table += ' ' + element + ' |';
349-
}
350-
table += '\n';
351-
}
352-
353-
return table;
387+
return `${this.getPrefix(i)}${x.toString().replaceAll('\n', '\n\t')}`;
388+
})
389+
.join('\n');
354390
}
355391
}

jsEngine/messages/Button.svelte

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!-- Inspired by https://github.com/marcusolsson/obsidian-svelte -->
2+
3+
<script lang="ts">
4+
import { ButtonStyleType } from '../utils/Util';
5+
6+
export let variant: ButtonStyleType = ButtonStyleType.DEFAULT;
7+
export let disabled: boolean = false;
8+
export let tooltip: string = '';
9+
</script>
10+
11+
<button
12+
class:mod-cta={variant === 'primary'}
13+
class:mod-warning={variant === 'destructive'}
14+
class:mod-plain={variant === 'plain'}
15+
class:disabled={disabled}
16+
aria-label={tooltip}
17+
on:click
18+
disabled={disabled}
19+
>
20+
<slot />
21+
</button>
22+
23+
<style>
24+
button {
25+
/* Add a gap between text and icons. */
26+
gap: var(--size-4-1);
27+
}
28+
29+
.mod-plain {
30+
background: none;
31+
box-shadow: none;
32+
border: none;
33+
34+
color: var(--text-muted);
35+
}
36+
37+
.mod-plain:hover {
38+
color: var(--text-normal);
39+
}
40+
41+
.disabled {
42+
opacity: 0.6;
43+
}
44+
</style>

jsEngine/messages/MessageDisplayComponent.svelte

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
<script lang="ts">
22
import { MessageManager } from './MessageManager';
33
import MessageComponent from './MessageComponent.svelte';
4+
import { Button } from 'obsidian-svelte';
45
56
export let messageManager: MessageManager;
67
let messages = messageManager.messages;
78
</script>
89

910
<h2>Messages</h2>
1011

12+
<Button variant="destructive" on:click={() => messageManager.removeAllMessages()}>Clear All Messages</Button>
13+
1114
<div>
1215
{#each $messages as [id, message]}
1316
<MessageComponent bind:messageWrapper={message} messageManager={messageManager}></MessageComponent>

jsEngine/messages/MessageManager.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ export class MessageManager {
117117
this.messages.notify();
118118
}
119119

120+
removeAllMessages(): void {
121+
this.messages.get().clear();
122+
this.messages.notify();
123+
}
124+
120125
private updateStatusBarItem(): void {
121126
if (!this.statusBarItem) {
122127
return;

jsEngine/utils/Util.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
export function iteratorToArray<T>(iterator: Iterable<T>): T[] {
22
return [...iterator];
33
}
4+
5+
export enum ButtonStyleType {
6+
DEFAULT = 'default',
7+
PRIMARY = 'primary',
8+
DESTRUCTIVE = 'destructive',
9+
PLAIN = 'plain',
10+
}

0 commit comments

Comments
 (0)