Skip to content

Commit da17a94

Browse files
committed
Add pasting URLs on selected text as Markdown links
1 parent 32b7ea3 commit da17a94

File tree

4 files changed

+61
-3
lines changed

4 files changed

+61
-3
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Paste Markdown objects
22

33
- Paste spreadsheet cells and HTML tables as a Markdown tables.
4+
- Paste URLs on selected text as Markdown links.
45
- Paste image URLs as Markdown image links.
56
- Paste markdown as markdown. See [`@github/quote-selection`/Preserving markdown syntax](https://github.com/github/quote-selection/tree/9ae5f88f5bc3021f51d2dc9981eca83ce7cfe04f#preserving-markdown-syntax) for details.
67

src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import {install as installLink, uninstall as uninstallLink} from './paste-markdown-image-link'
1+
import {install as installImageLink, uninstall as uninstallImageLink} from './paste-markdown-image-link'
2+
import {install as installLink, uninstall as uninstallLink} from './paste-markdown-link'
23
import {install as installTable, uninstall as uninstallTable} from './paste-markdown-table'
34
import {install as installText, uninstall as uninstallText} from './paste-markdown-text'
45

@@ -8,12 +9,14 @@ interface Subscription {
89

910
export default function subscribe(el: HTMLElement): Subscription {
1011
installTable(el)
12+
installImageLink(el)
1113
installLink(el)
1214
installText(el)
1315

1416
return {
1517
unsubscribe: () => {
1618
uninstallTable(el)
19+
uninstallImageLink(el)
1720
uninstallLink(el)
1821
uninstallText(el)
1922
}

src/paste-markdown-link.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import {insertText} from './text'
2+
3+
export function install(el: HTMLElement): void {
4+
el.addEventListener('paste', onPaste)
5+
}
6+
7+
export function uninstall(el: HTMLElement): void {
8+
el.removeEventListener('paste', onPaste)
9+
}
10+
11+
function onPaste(event: ClipboardEvent) {
12+
const transfer = event.clipboardData
13+
if (!transfer || !hasPlainText(transfer)) return
14+
15+
const field = event.currentTarget
16+
if (!(field instanceof HTMLTextAreaElement)) return
17+
18+
const text = transfer.getData('text/plain')
19+
if (!text) return
20+
21+
if (isWithinLink(field)) return
22+
23+
event.stopPropagation()
24+
event.preventDefault()
25+
26+
const selectedText = field.value.substring(field.selectionStart, field.selectionEnd)
27+
28+
insertText(field, linkify(selectedText, text), false)
29+
}
30+
31+
function hasPlainText(transfer: DataTransfer): boolean {
32+
return Array.from(transfer.types).indexOf('text/plain') >= 0
33+
}
34+
35+
function isWithinLink(textarea: HTMLTextAreaElement): boolean {
36+
const selectionStart = textarea.selectionStart || 0
37+
38+
if (selectionStart > 1) {
39+
const previousChars = textarea.value.substring(selectionStart - 2, selectionStart)
40+
return previousChars === ']('
41+
} else {
42+
return false
43+
}
44+
}
45+
46+
function linkify(selectedText: string, text: string): string {
47+
return selectedText.length && isURL(text) ? `[${selectedText}](${text})` : text
48+
}
49+
50+
const URL_RE = /^https?:\/\//i
51+
52+
function isURL(url: string): boolean {
53+
return URL_RE.test(url)
54+
}

src/text.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
export function insertText(textarea: HTMLInputElement | HTMLTextAreaElement, text: string): void {
1+
export function insertText(textarea: HTMLInputElement | HTMLTextAreaElement, text: string, addNewline = true): void {
22
const beginning = textarea.value.substring(0, textarea.selectionStart || 0)
33
const remaining = textarea.value.substring(textarea.selectionEnd || 0)
44

5-
const newline = beginning.length === 0 || beginning.match(/\n$/) ? '' : '\n'
5+
const newline = !addNewline || beginning.length === 0 || beginning.match(/\n$/) ? '' : '\n'
66
const textBeforeCursor = beginning + newline + text
77

88
textarea.value = textBeforeCursor + remaining

0 commit comments

Comments
 (0)