Skip to content

Commit 029c5e4

Browse files
authored
Merge pull request #68 from anleac/paste-config
Add architecture for granual pasteAsPlainText support
2 parents 6a2f6df + c81e20b commit 029c5e4

File tree

6 files changed

+97
-7
lines changed

6 files changed

+97
-7
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,25 @@ Some `<table>`s are not meant to be pasted as markdown; for example, a file cont
4444
</table>
4545
```
4646

47+
### Granular control for pasting as plain text
48+
49+
If you're wanting more granular support of pasting certain items as plain text by default, you can pass in the controls config at the `subscribe` level.
50+
51+
Our config support looks as follows:
52+
53+
```js
54+
import {subscribe} from '@github/paste-markdown'
55+
56+
// Subscribe the behavior to the textarea with pasting URL links as plain text by default.
57+
subscribe(document.querySelector('textarea[data-paste-markdown]'), {defaultPlainTextPaste: {urlLinks: true}})
58+
```
59+
60+
In this scenario above, pasting a URL over selected text will paste as plain text by default, but pasting a table will still paste as markdown by default.
61+
62+
Only the `urlLinks` param is currently supported.
63+
64+
If there is no config passed in, or attributes missing, this will always default to `false`, being the existing behavior.
65+
4766
## Development
4867

4968
```

src/index.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import {
77
} from './paste-keyboard-shortcut-helper'
88
import {install as installTable, uninstall as uninstallTable} from './paste-markdown-table'
99
import {install as installText, uninstall as uninstallText} from './paste-markdown-text'
10+
import {OptionConfig} from './option-config'
1011

1112
interface Subscription {
1213
unsubscribe: () => void
1314
}
1415

15-
function subscribe(el: HTMLElement): Subscription {
16-
installSkipFormatting(el, installTable, installImageLink, installLink, installText, installHTML)
17-
16+
function subscribe(el: HTMLElement, optionConfig?: OptionConfig): Subscription {
17+
installSkipFormatting(el, [installTable, installImageLink, installLink, installText, installHTML], optionConfig)
1818
return {
1919
unsubscribe: () => {
2020
uninstallSkipFormatting(el)

src/option-config.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export interface OptionConfig {
2+
defaultPlainTextPaste?: PlainTextParams
3+
}
4+
5+
interface PlainTextParams {
6+
urlLinks?: boolean
7+
8+
// Not currently implemented behavior
9+
/*imageLinks?: boolean
10+
html?: boolean
11+
tables?: boolean
12+
text?: boolean*/
13+
}

src/paste-keyboard-shortcut-helper.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import {OptionConfig} from './option-config'
2+
13
const skipFormattingMap = new WeakMap<HTMLElement, boolean>()
24

35
function setSkipFormattingFlag(event: KeyboardEvent): void {
@@ -21,11 +23,15 @@ export function shouldSkipFormatting(el: HTMLElement): boolean {
2123
return shouldSkipFormattingState
2224
}
2325

24-
export function installAround(el: HTMLElement, ...installCallbacks: Array<(el: HTMLElement) => void>): void {
26+
export function installAround(
27+
el: HTMLElement,
28+
installCallbacks: Array<(el: HTMLElement, optionConfig?: OptionConfig) => void>,
29+
optionConfig?: OptionConfig
30+
): void {
2531
el.addEventListener('keydown', setSkipFormattingFlag)
2632

2733
for (const installCallback of installCallbacks) {
28-
installCallback(el)
34+
installCallback(el, optionConfig)
2935
}
3036

3137
el.addEventListener('paste', unsetSkipFormattedFlag)

src/paste-markdown-link.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import {OptionConfig} from './option-config'
12
import {insertText} from './text'
23
import {shouldSkipFormatting} from './paste-keyboard-shortcut-helper'
34

4-
export function install(el: HTMLElement): void {
5+
const pasteLinkAsPlainTextOverSelectedTextMap = new WeakMap<HTMLElement, boolean>()
6+
7+
export function install(el: HTMLElement, optionConfig?: OptionConfig): void {
8+
pasteLinkAsPlainTextOverSelectedTextMap.set(el, optionConfig?.defaultPlainTextPaste?.urlLinks === true)
59
el.addEventListener('paste', onPaste)
610
}
711

@@ -11,7 +15,16 @@ export function uninstall(el: HTMLElement): void {
1115

1216
function onPaste(event: ClipboardEvent) {
1317
const {currentTarget: el} = event
14-
if (shouldSkipFormatting(el as HTMLElement)) return
18+
const element = el as HTMLElement
19+
const shouldPasteAsPlainText = pasteLinkAsPlainTextOverSelectedTextMap.get(element) ?? false
20+
const shouldSkipDefaultBehavior = shouldSkipFormatting(element)
21+
22+
if (
23+
(!shouldPasteAsPlainText && shouldSkipDefaultBehavior) ||
24+
(shouldPasteAsPlainText && !shouldSkipDefaultBehavior)
25+
) {
26+
return
27+
}
1528

1629
const transfer = event.clipboardData
1730
if (!transfer || !hasPlainText(transfer)) return
@@ -26,6 +39,7 @@ function onPaste(event: ClipboardEvent) {
2639

2740
const selectedText = field.value.substring(field.selectionStart, field.selectionEnd)
2841
if (!selectedText.length) return
42+
2943
// Prevent linkification when replacing an URL
3044
// Trim whitespace in case whitespace is selected by mistake or by intention
3145
if (isURL(selectedText.trim())) return

test/test.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,38 @@ describe('paste-markdown', function () {
4343
assert.equal(textarea.value, 'The examples can be found [here](https://github.com).')
4444
})
4545

46+
it('turns pasted urls on selected text into markdown links if pasteLinkAsPlainTextOverSelectedText is false', function () {
47+
subscription = subscribeWithOptionConfig(subscription, textarea, false)
48+
49+
// eslint-disable-next-line i18n-text/no-en
50+
textarea.value = 'The examples can be found here.'
51+
textarea.setSelectionRange(26, 30)
52+
paste(textarea, {'text/plain': 'https://github.com'})
53+
assert.equal(textarea.value, 'The examples can be found [here](https://github.com).')
54+
})
55+
56+
it('turns pasted urls on selected text into markdown links if pasteLinkAsPlainTextOverSelectedText is true and skip format flag is true', function () {
57+
subscription = subscribeWithOptionConfig(subscription, textarea, true)
58+
59+
// eslint-disable-next-line i18n-text/no-en
60+
textarea.value = 'The examples can be found here.'
61+
textarea.setSelectionRange(26, 30)
62+
dispatchSkipFormattingKeyEvent(textarea)
63+
paste(textarea, {'text/plain': 'https://github.com'})
64+
assert.equal(textarea.value, 'The examples can be found [here](https://github.com).')
65+
})
66+
67+
it('pastes as plain text on selected text if pasteLinkAsPlainTextOverSelectedText is true', function () {
68+
subscription = subscribeWithOptionConfig(subscription, textarea, true)
69+
70+
// eslint-disable-next-line i18n-text/no-en
71+
textarea.value = 'The examples can be found here.'
72+
textarea.setSelectionRange(26, 30)
73+
paste(textarea, {'text/plain': 'https://github.com'})
74+
// The text area will be unchanged at this stage as the paste won't be handled by our listener
75+
assert.equal(textarea.value, 'The examples can be found here.')
76+
})
77+
4678
it('creates a markdown link when the pasted url includes a trailing slash', function () {
4779
// eslint-disable-next-line i18n-text/no-en
4880
textarea.value = 'The examples can be found here.'
@@ -353,6 +385,12 @@ function dispatchSkipFormattingKeyEvent(textarea) {
353385
)
354386
}
355387

388+
function subscribeWithOptionConfig(subscription, textarea, urlLinks) {
389+
// Clear the before test subscription with no config and re-subscribe with config
390+
subscription.unsubscribe()
391+
return subscribe(textarea, {defaultPlainTextPaste: {urlLinks}})
392+
}
393+
356394
function paste(textarea, data) {
357395
const dataTransfer = new DataTransfer()
358396
for (const key in data) {

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy