Skip to content

Commit

Permalink
Merge pull request #35 from zolrath/Add-Separate-Paste-Hotkey
Browse files Browse the repository at this point in the history
Add ability to rebind auto link title paste
  • Loading branch information
zolrath authored Jan 20, 2022
2 parents 7c77934 + 6d68c2a commit 2b5c846
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 45 deletions.
100 changes: 61 additions & 39 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import { EditorExtensions } from "editor-enhancements";
import { Plugin, MarkdownView, Editor } from "obsidian";
import {
Plugin,
MarkdownView,
Editor,
PluginSettingTab,
App,
Setting,
} from "obsidian";
import { AutoLinkTitleSettings, DEFAULT_SETTINGS } from "./settings";
AutoLinkTitleSettings,
AutoLinkTitleSettingTab,
DEFAULT_SETTINGS,
} from "./settings";
import { CheckIf } from "checkif";
import getPageTitle from "scraper";

Expand All @@ -25,6 +22,16 @@ export default class AutoLinkTitle extends Plugin {

// Listen to paste event
this.pasteFunction = this.pasteUrlWithTitle.bind(this);

this.addCommand({
id: "auto-link-title-paste",
name: "Paste URL and auto fetch title",
callback: () => {
this.manualPasteUrlWithTitle();
},
hotkeys: [],
});

this.app.workspace.containerEl.addEventListener(
"paste",
this.pasteFunction,
Expand Down Expand Up @@ -66,7 +73,52 @@ export default class AutoLinkTitle extends Plugin {
}
}

pasteUrlWithTitle(clipboard: ClipboardEvent): void {
// Simulate standard paste but using editor.replaceSelection with clipboard text since we can't seem to dispatch a paste event.
async manualPasteUrlWithTitle(): Promise<void> {
let editor = this.getEditor();

// Only attempt fetch if online
if (!navigator.onLine) {
editor.replaceSelection(clipboardText);
return;
}

var clipboardText = await navigator.clipboard.readText();
if (clipboardText == null || clipboardText == "") return;

// If its not a URL, we return false to allow the default paste handler to take care of it.
// Similarly, image urls don't have a meaningful <title> attribute so downloading it
// to fetch the title is a waste of bandwidth.
if (!CheckIf.isUrl(clipboardText) || CheckIf.isImage(clipboardText)) {
editor.replaceSelection(clipboardText);
return;
}

let selectedText = (EditorExtensions.getSelectedText(editor) || "").trim();
if (selectedText && !this.settings.shouldReplaceSelection) {
// If there is selected text and shouldReplaceSelection is false, do not fetch title
editor.replaceSelection(clipboardText);
return;
}

// If it looks like we're pasting the url into a markdown link already, don't fetch title
// as the user has already probably put a meaningful title, also it would lead to the title
// being inside the link.
if (CheckIf.isMarkdownLinkAlready(editor) || CheckIf.isAfterQuote(editor)) {
editor.replaceSelection(clipboardText);
return;
}

// At this point we're just pasting a link in a normal fashion, fetch its title.
this.convertUrlToTitledLink(editor, clipboardText);
return;
}

async pasteUrlWithTitle(clipboard: ClipboardEvent): Promise<void> {
if (!this.settings.enhanceDefaultPaste) {
return;
}

// Only attempt fetch if online
if (!navigator.onLine) return;

Expand Down Expand Up @@ -179,33 +231,3 @@ export default class AutoLinkTitle extends Plugin {
await this.saveData(this.settings);
}
}

class AutoLinkTitleSettingTab extends PluginSettingTab {
plugin: AutoLinkTitle;

constructor(app: App, plugin: AutoLinkTitle) {
super(app, plugin);
this.plugin = plugin;
}

display(): void {
let { containerEl } = this;

containerEl.empty();

new Setting(containerEl)
.setName("Replace Selection")
.setDesc(
"Whether to replace a text selection with link and fetched title"
)
.addToggle((val) =>
val
.setValue(this.plugin.settings.shouldReplaceSelection)
.onChange(async (value) => {
console.log(value);
this.plugin.settings.shouldReplaceSelection = value;
await this.plugin.saveSettings();
})
);
}
}
2 changes: 1 addition & 1 deletion scraper.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const electronPkg = require("electron");
import { request, RequestParam } from "obsidian";
import { request } from "obsidian";

function blank(text: string): boolean {
return text === undefined || text === null || text === "";
Expand Down
64 changes: 59 additions & 5 deletions settings.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,71 @@
import AutoLinkTitle from "main";
import { App, PluginSettingTab, Setting } from "obsidian";

export interface AutoLinkTitleSettings {
regex: RegExp;
lineRegex: RegExp;
linkRegex: RegExp;
linkLineRegex: RegExp;
imageRegex: RegExp;
shouldReplaceSelection: boolean;
enhanceDefaultPaste: boolean;
}

export const DEFAULT_SETTINGS: AutoLinkTitleSettings = {
regex: /^(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,})$/i,
lineRegex: /(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,})/ig,
linkRegex: /^\[([^\[\]]*)\]\((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,})\)$/i,
linkLineRegex: /\[([^\[\]]*)\]\((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,})\)/ig,
regex:
/^(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,})$/i,
lineRegex:
/(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,
linkRegex:
/^\[([^\[\]]*)\]\((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,})\)$/i,
linkLineRegex:
/\[([^\[\]]*)\]\((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,
imageRegex: /\.(gif|jpe?g|tiff?|png|webp|bmp|tga|psd|ai)$/i,
shouldReplaceSelection: true
shouldReplaceSelection: true,
enhanceDefaultPaste: true,
};

export class AutoLinkTitleSettingTab extends PluginSettingTab {
plugin: AutoLinkTitle;

constructor(app: App, plugin: AutoLinkTitle) {
super(app, plugin);
this.plugin = plugin;
}

display(): void {
let { containerEl } = this;

containerEl.empty();

new Setting(containerEl)
.setName("Enhance Default Paste")
.setDesc(
"Fetch the link title when pasting a link in the editor with the default paste command"
)
.addToggle((val) =>
val
.setValue(this.plugin.settings.enhanceDefaultPaste)
.onChange(async (value) => {
console.log(value);
this.plugin.settings.enhanceDefaultPaste = value;
await this.plugin.saveSettings();
})
);

new Setting(containerEl)
.setName("Replace Selection")
.setDesc(
"Whether to replace a text selection with link and fetched title"
)
.addToggle((val) =>
val
.setValue(this.plugin.settings.shouldReplaceSelection)
.onChange(async (value) => {
console.log(value);
this.plugin.settings.shouldReplaceSelection = value;
await this.plugin.saveSettings();
})
);
}
}

0 comments on commit 2b5c846

Please sign in to comment.