mirror of
https://github.com/gnoxnahte/obsidian-auto-embed.git
synced 2026-07-22 09:50:24 +00:00
Completed asking user if they want to add embeds after pasting url (Code cleanup needed)
- User pastes url - Plugin suggests to embed (has an option to cancel or tap anywhere else to cancel) - After accepting to embed, mark the link for embedding [ae:embed](link)
This commit is contained in:
parent
dc82436d49
commit
db45c00a7e
3 changed files with 195 additions and 5 deletions
121
main.ts
121
main.ts
|
|
@ -1,15 +1,36 @@
|
|||
import { CodepenEmbed } from 'embeds/codepen';
|
||||
import { TwitterEmbed } from 'embeds/twitter';
|
||||
import { EmbedBase } from 'embeds/embedBase';
|
||||
import { Plugin } from 'obsidian';
|
||||
import { Editor, Plugin } from 'obsidian';
|
||||
import { YouTubeEmbed } from 'embeds/youtube';
|
||||
import { SteamEmbed } from 'embeds/steam';
|
||||
import { RedditEmbed } from 'embeds/reddit';
|
||||
import { AutoEmbedSettingTab, DEFAULT_SETTINGS, PluginSettings } from 'settings-tab';
|
||||
import { ImgurEmbed } from 'embeds/imgur';
|
||||
import { SpotifyEmbed } from 'embeds/spotify';
|
||||
import SuggestEmbed from 'suggestEmbed';
|
||||
import { isURL, regexUrl } from 'utility';
|
||||
|
||||
// Remember to rename these classes and interfaces!
|
||||
class PasteInfo {
|
||||
trigger: boolean;
|
||||
text: string;
|
||||
|
||||
constructor(trigger: boolean, text: string) {
|
||||
this.trigger = trigger;
|
||||
this.text = text;
|
||||
}
|
||||
}
|
||||
|
||||
interface EditPosition {
|
||||
line: number;
|
||||
ch: number;
|
||||
}
|
||||
|
||||
interface Selection {
|
||||
start: EditPosition
|
||||
end: EditPosition
|
||||
text: string;
|
||||
}
|
||||
|
||||
export default class AutoEmbedPlugin extends Plugin {
|
||||
settings: PluginSettings;
|
||||
|
|
@ -21,13 +42,29 @@ export default class AutoEmbedPlugin extends Plugin {
|
|||
new CodepenEmbed(this),
|
||||
new SpotifyEmbed(this),
|
||||
new ImgurEmbed(this),
|
||||
]
|
||||
];
|
||||
isShiftDown = false;
|
||||
pasteInfo: PasteInfo = new PasteInfo(false, "");
|
||||
|
||||
async onload() {
|
||||
console.log('loading plugin');
|
||||
await this.loadSettings();
|
||||
|
||||
this.addSettingTab(new AutoEmbedSettingTab(this.app, this));
|
||||
|
||||
this.registerDomEvent(document, "keydown", (e) => {
|
||||
if (e.shiftKey)
|
||||
this.isShiftDown = true;
|
||||
})
|
||||
|
||||
this.registerDomEvent(document, "keydown", (e) => {
|
||||
if (!e.shiftKey)
|
||||
this.isShiftDown = false;
|
||||
})
|
||||
|
||||
this.registerEditorSuggest(new SuggestEmbed(this));
|
||||
|
||||
this.app.workspace.on("editor-paste", this.onPaste.bind(this));
|
||||
|
||||
this.registerMarkdownPostProcessor((el, ctx) => {
|
||||
console.log("Registering markdown")
|
||||
|
|
@ -63,12 +100,37 @@ export default class AutoEmbedPlugin extends Plugin {
|
|||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
private onPaste(e: ClipboardEvent, editor: Editor) {
|
||||
if (e.defaultPrevented)
|
||||
return;
|
||||
|
||||
// Usually "Ctrl-Shift-V" means paste text without formatting. So don't embed
|
||||
if (this.isShiftDown)
|
||||
return;
|
||||
|
||||
// Check if valid url
|
||||
const clipboardData = e.clipboardData?.getData("text/plain");
|
||||
if (!clipboardData || clipboardData === "" || !isURL(clipboardData))
|
||||
return;
|
||||
|
||||
this.pasteInfo.trigger = true;
|
||||
this.pasteInfo.text = clipboardData;
|
||||
|
||||
// TODO: Delete?
|
||||
// Do this to be able to select the url.
|
||||
// Obsidian pastes after this function, so
|
||||
// e.preventDefault();
|
||||
// editor.replaceRange(clipboardData, editor.getCursor());
|
||||
|
||||
// this.selectLink(editor);
|
||||
}
|
||||
|
||||
private handleAnchor(a: HTMLAnchorElement) {
|
||||
const innerText = a.innerText;
|
||||
// Removes all spaces
|
||||
const innerTextTrim = innerText.replace(/\s/g, "");
|
||||
|
||||
if (innerTextTrim.includes("|noembed")) {
|
||||
if (!innerTextTrim.includes("ae:embed")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -87,9 +149,57 @@ export default class AutoEmbedPlugin extends Plugin {
|
|||
this.insertEmbed(a, embed);
|
||||
}
|
||||
|
||||
private getSelection(editor: Editor) : Selection | null {
|
||||
if (!editor.somethingSelected())
|
||||
return null;
|
||||
|
||||
return {
|
||||
start: editor.getCursor("from"),
|
||||
end: editor.getCursor("to"),
|
||||
text: editor.getSelection()
|
||||
}
|
||||
}
|
||||
|
||||
// Used if there's nothing selected. Mostly when the user pastes a link
|
||||
selectLink(editor: Editor) {
|
||||
const cursor = editor.getCursor();
|
||||
const lineText = editor.getLine(cursor.line);
|
||||
console.log("line text: "+ lineText)
|
||||
const matchedLinks = lineText.matchAll(regexUrl);
|
||||
for (const match of matchedLinks) {
|
||||
console.log("match: " + match[0])
|
||||
// Check if the cursor is within the match
|
||||
console.log("start: " + match.index + "|end: " + (match.index??0 + match[0].length) + "|cursor: "+ cursor.ch);
|
||||
if (match.index &&
|
||||
match.index <= cursor.ch && // Is start of match before cursor
|
||||
match.index + match[0].length >= cursor.ch // Is end of match after cursor
|
||||
) {
|
||||
console.log("Selected: " + match[0]);
|
||||
editor.setSelection(
|
||||
{
|
||||
line: cursor.line,
|
||||
ch: match.index
|
||||
},
|
||||
{
|
||||
line: cursor.line,
|
||||
ch: match.index + match[0].length
|
||||
}
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
markToEmbed(selection: Selection, editor: Editor) {
|
||||
// const selection = this.getSelection(editor);
|
||||
editor.replaceRange(`[ae:embed](${selection.text})`, selection.start, selection.end);
|
||||
|
||||
console.log(`Replacing: [ae:embed](${selection}), Start:${selection.start.ch}, End: ${selection.end.ch}`)
|
||||
}
|
||||
|
||||
private createEmbed(embedSource: EmbedBase, link: string) {
|
||||
const embed = embedSource.createEmbed(link);
|
||||
return embed;
|
||||
return embed;
|
||||
}
|
||||
|
||||
private insertEmbed(a: HTMLAnchorElement, container: HTMLElement) {
|
||||
|
|
@ -97,3 +207,4 @@ export default class AutoEmbedPlugin extends Plugin {
|
|||
parent?.replaceChild(container, a);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
69
suggestEmbed.ts
Normal file
69
suggestEmbed.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import AutoEmbedPlugin from "main";
|
||||
import { Editor, EditorPosition, EditorSuggest, EditorSuggestContext, EditorSuggestTriggerInfo, TFile } from "obsidian";
|
||||
|
||||
class Suggestion {
|
||||
choice: string;
|
||||
|
||||
constructor(choice: string) {
|
||||
this.choice = choice;
|
||||
}
|
||||
}
|
||||
|
||||
export default class SuggestEmbed extends EditorSuggest<Suggestion> {
|
||||
private plugin: AutoEmbedPlugin;
|
||||
private editor: Editor;
|
||||
|
||||
constructor(plugin: AutoEmbedPlugin) {
|
||||
super(plugin.app);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
onTrigger(cursor: EditorPosition, editor: Editor, file: TFile | null): EditorSuggestTriggerInfo | null {
|
||||
console.log("on trigger");
|
||||
this.editor = editor;
|
||||
if (!this.plugin.pasteInfo.trigger)
|
||||
return null;
|
||||
|
||||
this.plugin.pasteInfo.trigger = false;
|
||||
console.log("Cursor-ch: " + cursor.ch);
|
||||
|
||||
return {
|
||||
start: cursor,
|
||||
end: cursor,
|
||||
query: this.plugin.pasteInfo.text,
|
||||
}
|
||||
}
|
||||
|
||||
getSuggestions(context: EditorSuggestContext): Suggestion[] | Promise<Suggestion[]> {
|
||||
console.log("get suggestion");
|
||||
return [new Suggestion("Embed Link"), new Suggestion("Cancel")];
|
||||
}
|
||||
|
||||
renderSuggestion(suggestion: Suggestion, el: HTMLElement): void {
|
||||
console.log("render suggestion");
|
||||
el.setText(suggestion.choice);
|
||||
}
|
||||
|
||||
selectSuggestion(suggestion: Suggestion, e: KeyboardEvent | MouseEvent): void {
|
||||
console.log("select suggestion");
|
||||
const cursor = this.editor.getCursor();
|
||||
if (suggestion.choice === "Embed Link") {
|
||||
console.log("Selected create embed");
|
||||
const text = this.plugin.pasteInfo.text;
|
||||
this.plugin.markToEmbed(
|
||||
{
|
||||
text: text,
|
||||
start: {
|
||||
line: cursor.line,
|
||||
ch: cursor.ch - text.length
|
||||
},
|
||||
end: cursor
|
||||
}
|
||||
,this.editor);
|
||||
}
|
||||
else
|
||||
console.log("select suggestion: " + suggestion.choice);
|
||||
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
10
utility.ts
Normal file
10
utility.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export const regexUrl = /(https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|www\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|https?:\/\/(?:www\.|(?!www))[a-zA-Z0-9]+\.[^\s]{2,}|www\.[a-zA-Z0-9]+\.[^\s]{2,})/gi
|
||||
|
||||
export function isURL(str: string) : boolean {
|
||||
try {
|
||||
new URL(str);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue