Skip to content

Commit

Permalink
Inline button (#32)
Browse files Browse the repository at this point in the history
* basic inline buttons

* inline button prepend and replace

* new calculate

* swap arg

* templater button

* started on button creator modal

* button maker 5000

* complete button maker

* update readme

* img
  • Loading branch information
shabegom authored May 12, 2021
1 parent 569f601 commit 46eeede
Show file tree
Hide file tree
Showing 16 changed files with 1,614 additions and 298 deletions.
398 changes: 226 additions & 172 deletions README.md

Large diffs are not rendered by default.

Binary file added img/040.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "buttons",
"name": "Buttons",
"description": "Create Buttons in your Obsidian notes to run commands, open links, and insert templates",
"version": "0.3.8",
"version": "0.4.0",
"author": "shabegom",
"authorUrl": "https://shbgm.ca",
"isDesktopOnly": false,
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
},
"dependencies": {
"@babel/runtime": "7.13.10",
"@popperjs/core": "^2.9.2",
"math-expression-evaluator": "^1.3.7",
"nanoid": "^3.1.23",
"obsidian": "^0.12.0",
"remark-parse": "^9.0.0",
"tslib": "2.1.0",
Expand Down
94 changes: 94 additions & 0 deletions src/button.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { App, Notice, MarkdownView } from "obsidian";
import { Arguments } from "./types";
import {
calculate,
remove,
replace,
template,
link,
command,
swap,
templater,
} from "./buttonTypes";
import { getButtonPosition, getInlineButtonPosition } from "./parser";

export const createButton = (
app: App,
el: HTMLElement,
args: Arguments,
inline: boolean,
id?: string
): HTMLElement => {
//create the button element
const button = el.createEl("button", {
text: args.name,
cls: args.class
? `${args.class} ${args.color}`
: `button-default ${args.color ? args.color : ""}`,
});
args.id ? button.setAttribute("id", args.id) : "";
button.on("click", "button", () => {
clickHandler(app, args, inline, id);
});
return button;
};

const clickHandler = async (
app: App,
args: Arguments,
inline: boolean,
id: string
) => {
const activeView = app.workspace.getActiveViewOfType(MarkdownView);
let content = await app.vault.read(activeView.file);
let position = inline
? await getInlineButtonPosition(app, id)
: getButtonPosition(content, args);
// handle command buttons
if (args.templater) {
args = await templater(app, position);
if (inline) {
new Notice("templater args don't work with inline buttons yet", 2000);
}
}
if (args.replace) {
replace(app, args);
}
if (args.type === "command") {
command(app, args);
}
// handle link buttons
if (args.type === "link") {
link(args);
}
// handle template buttons
if (args.type && args.type.includes("template")) {
setTimeout(async () => {
content = await app.vault.read(activeView.file);
position = inline
? await getInlineButtonPosition(app, id)
: getButtonPosition(content, args);
template(app, args, position);
}, 50);
}
if (args.type === "calculate") {
calculate(app, args, position);
}
// handle removing the button
if (args.remove) {
setTimeout(async () => {
content = await app.vault.read(activeView.file);
position = inline
? await getInlineButtonPosition(app, id)
: getButtonPosition(content, args);
remove(app, args, position);
}, 75);
}
if (args.swap) {
if (!inline) {
new Notice("swap args only work in inline buttons for now", 2000);
} else {
swap(app, args.swap, id, inline, activeView.file);
}
}
};
62 changes: 59 additions & 3 deletions src/buttonStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { createArgumentObject } from "./utils";

let buttonStore: ExtendedBlockCache[];

export const getStore = (isMobile: boolean) =>
export const getStore = (isMobile: boolean): ExtendedBlockCache[] =>
isMobile ? buttonStore : JSON.parse(localStorage.getItem("buttons"));

export const initializeButtonStore = (app: App): void => {
Expand Down Expand Up @@ -39,7 +39,7 @@ export const addButtonToStore = (app: App, file: TFile): void => {
export const getButtonFromStore = async (
app: App,
args: Arguments
): Promise<Arguments> | undefined => {
): Promise<{ args: Arguments; id: string }> | undefined => {
const store = getStore(app.isMobile);
if (args.id) {
const storedButton =
Expand All @@ -58,11 +58,66 @@ export const getButtonFromStore = async (
)
.join("\n");
const storedArgs = createArgumentObject(button);
return { ...storedArgs, ...args };
return {
args: { ...storedArgs, ...args },
id: storedButton.id.split("button-")[1],
};
}
}
};

export const getButtonById = async (
app: App,
id: string
): Promise<Arguments> => {
const store = getStore(app.isMobile);
const storedButton = store.filter(
(item: ExtendedBlockCache) => `button-${id}` === item.id
)[0];
if (storedButton) {
const file = app.vault.getAbstractFileByPath(storedButton.path);
const content = await app.vault.cachedRead(file as TFile);
const contentArray = content.split("\n");
const button = contentArray
.slice(
storedButton.position.start.line + 1,
storedButton.position.end.line
)
.join("\n");
return createArgumentObject(button);
}
};

export const getButtonSwapById = async (
app: App,
id: string
): Promise<number> => {
const store = getStore(app.isMobile);
const storedButton = store.filter(
(item: ExtendedBlockCache) => `button-${id}` === item.id
)[0];
if (storedButton) {
return storedButton.swap;
}
};

export const setButtonSwapById = async (
app: App,
id: string,
newSwap: number
): Promise<void> => {
const store = getStore(app.isMobile);
const storedButton = store.filter(
(item: ExtendedBlockCache) => `button-${id}` === item.id
)[0];
if (storedButton) {
storedButton.swap = newSwap;
const newStore = removeDuplicates([...store, storedButton]);
localStorage.setItem("buttons", JSON.stringify(newStore));
buttonStore = newStore;
}
};

export const buildButtonArray = (
cache: CachedMetadata,
file: TFile
Expand All @@ -74,6 +129,7 @@ export const buildButtonArray = (
.map((key) => blocks[key])
.map((obj: ExtendedBlockCache) => {
obj["path"] = file.path;
obj["swap"] = 0;
return obj;
})
.filter((block) => block.id.includes("button"));
Expand Down
102 changes: 93 additions & 9 deletions src/buttonTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import {
removeButton,
removeSection,
} from "./handlers";
import {
getButtonPosition,
getInlineButtonPosition,
findNumber,
} from "./parser";
import { handleValueArray, createContentArray, getNewArgs } from "./utils";
import {
getButtonSwapById,
setButtonSwapById,
getButtonById,
} from "./buttonStore";

export const calculate = async (
app: App,
Expand All @@ -21,22 +32,25 @@ export const calculate = async (
const output = variables.map(async (value) => {
const activeView = app.workspace.getActiveViewOfType(MarkdownView);
if (activeView) {
const file = activeView.file;
const originalContent = await app.vault.read(file);
const arr = originalContent.split("\n");
const lineNumber = parseInt(value.substring(1)) - 1;
return { variable: value, value: arr[lineNumber].split(" ").pop() };
const lineNumber = parseInt(value.substring(1));
const numbers = await findNumber(app, lineNumber);
return { variable: value, numbers };
} else {
new Notice(`couldn't read file`, 2000);
}
});
const resolved = await Promise.all(output);
resolved.forEach((term: { variable: string; value: string }) => {
equation = equation.replace(term.variable, term.value);
resolved.forEach((term: { variable: string; numbers: string[] }) => {
if (term.numbers) {
equation = equation.replace(term.variable, term.numbers.join(""));
} else {
new Notice("Check the line number in your calculate button", 3000);
equation = undefined;
}
});
}
const fun = mexp.eval(equation);
appendContent(app, `Result: ${fun}`, position.lineEnd);
const fun = equation && mexp.eval(equation);
fun && appendContent(app, `Result: ${fun}`, position.lineEnd);
};

export const remove = (
Expand Down Expand Up @@ -123,3 +137,73 @@ export const command = (app: App, { action }: Arguments): void => {
)[0];
app.commands.executeCommandById(command.id);
};

export const swap = async (
app: App,
swap: string,
id: string,
inline: boolean,
file: TFile
): Promise<void> => {
handleValueArray(swap, async (argArray) => {
const swap = await getButtonSwapById(app, id);
const newSwap = swap + 1 > argArray.length - 1 ? 0 : swap + 1;
setButtonSwapById(app, id, newSwap);
const args = await getButtonById(app, argArray[swap]);
let position;
let content;
if (args) {
if (args.replace) {
replace(app, args);
}
if (args.type === "command") {
command(app, args);
}
// handle link buttons
if (args.type === "link") {
link(args);
}
// handle template buttons
if (args.type && args.type.includes("template")) {
setTimeout(async () => {
content = await app.vault.read(file);
position = inline
? await getInlineButtonPosition(app, id)
: getButtonPosition(content, args);
template(app, args, position);
}, 50);
}
if (args.type === "calculate") {
calculate(app, args, position);
}
// handle removing the button
if (args.remove) {
setTimeout(async () => {
content = await app.vault.read(file);
position = inline
? await getInlineButtonPosition(app, id)
: getButtonPosition(content, args);
remove(app, args, position);
}, 75);
}
}
});
};

export const templater = async (
app: App,
position: Position
): Promise<Arguments> => {
const originalContent = await createContentArray(app);
const originalButton = originalContent.contentArray
.splice(position.lineStart, position.lineEnd)
.join("\n");
app.commands.executeCommandById(
"templater-obsidian:replace-in-file-templater"
);
const { content, args } = await getNewArgs(app, position, originalButton);
setTimeout(async () => {
await app.vault.modify(originalContent.file, content);
}, 500);
return args;
};
Loading

0 comments on commit 46eeede

Please sign in to comment.