diff --git a/README.md b/README.md
index ae46b41..7829ef4 100644
--- a/README.md
+++ b/README.md
@@ -44,6 +44,25 @@ Some `
`s are not meant to be pasted as markdown; for example, a file cont
```
+### Granular control for pasting as plain text
+
+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.
+
+Our config support looks as follows:
+
+```js
+import {subscribe} from '@github/paste-markdown'
+
+// Subscribe the behavior to the textarea with pasting URL links as plain text by default.
+subscribe(document.querySelector('textarea[data-paste-markdown]'), {defaultPlainTextPaste: {urlLinks: true}})
+```
+
+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.
+
+Only the `urlLinks` param is currently supported.
+
+If there is no config passed in, or attributes missing, this will always default to `false`, being the existing behavior.
+
## Development
```
diff --git a/src/index.ts b/src/index.ts
index 2f84aee..eb272ee 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -7,14 +7,14 @@ import {
} from './paste-keyboard-shortcut-helper'
import {install as installTable, uninstall as uninstallTable} from './paste-markdown-table'
import {install as installText, uninstall as uninstallText} from './paste-markdown-text'
+import {OptionConfig} from './option-config'
interface Subscription {
unsubscribe: () => void
}
-function subscribe(el: HTMLElement): Subscription {
- installSkipFormatting(el, installTable, installImageLink, installLink, installText, installHTML)
-
+function subscribe(el: HTMLElement, optionConfig?: OptionConfig): Subscription {
+ installSkipFormatting(el, [installTable, installImageLink, installLink, installText, installHTML], optionConfig)
return {
unsubscribe: () => {
uninstallSkipFormatting(el)
diff --git a/src/option-config.ts b/src/option-config.ts
new file mode 100644
index 0000000..46d42d6
--- /dev/null
+++ b/src/option-config.ts
@@ -0,0 +1,13 @@
+export interface OptionConfig {
+ defaultPlainTextPaste?: PlainTextParams
+}
+
+interface PlainTextParams {
+ urlLinks?: boolean
+
+ // Not currently implemented behavior
+ /*imageLinks?: boolean
+ html?: boolean
+ tables?: boolean
+ text?: boolean*/
+}
diff --git a/src/paste-keyboard-shortcut-helper.ts b/src/paste-keyboard-shortcut-helper.ts
index f2a5261..e3c515a 100644
--- a/src/paste-keyboard-shortcut-helper.ts
+++ b/src/paste-keyboard-shortcut-helper.ts
@@ -1,3 +1,5 @@
+import {OptionConfig} from './option-config'
+
const skipFormattingMap = new WeakMap()
function setSkipFormattingFlag(event: KeyboardEvent): void {
@@ -21,11 +23,15 @@ export function shouldSkipFormatting(el: HTMLElement): boolean {
return shouldSkipFormattingState
}
-export function installAround(el: HTMLElement, ...installCallbacks: Array<(el: HTMLElement) => void>): void {
+export function installAround(
+ el: HTMLElement,
+ installCallbacks: Array<(el: HTMLElement, optionConfig?: OptionConfig) => void>,
+ optionConfig?: OptionConfig
+): void {
el.addEventListener('keydown', setSkipFormattingFlag)
for (const installCallback of installCallbacks) {
- installCallback(el)
+ installCallback(el, optionConfig)
}
el.addEventListener('paste', unsetSkipFormattedFlag)
diff --git a/src/paste-markdown-link.ts b/src/paste-markdown-link.ts
index 75c7159..aa6470d 100644
--- a/src/paste-markdown-link.ts
+++ b/src/paste-markdown-link.ts
@@ -1,7 +1,11 @@
+import {OptionConfig} from './option-config'
import {insertText} from './text'
import {shouldSkipFormatting} from './paste-keyboard-shortcut-helper'
-export function install(el: HTMLElement): void {
+const pasteLinkAsPlainTextOverSelectedTextMap = new WeakMap()
+
+export function install(el: HTMLElement, optionConfig?: OptionConfig): void {
+ pasteLinkAsPlainTextOverSelectedTextMap.set(el, optionConfig?.defaultPlainTextPaste?.urlLinks === true)
el.addEventListener('paste', onPaste)
}
@@ -11,7 +15,16 @@ export function uninstall(el: HTMLElement): void {
function onPaste(event: ClipboardEvent) {
const {currentTarget: el} = event
- if (shouldSkipFormatting(el as HTMLElement)) return
+ const element = el as HTMLElement
+ const shouldPasteAsPlainText = pasteLinkAsPlainTextOverSelectedTextMap.get(element) ?? false
+ const shouldSkipDefaultBehavior = shouldSkipFormatting(element)
+
+ if (
+ (!shouldPasteAsPlainText && shouldSkipDefaultBehavior) ||
+ (shouldPasteAsPlainText && !shouldSkipDefaultBehavior)
+ ) {
+ return
+ }
const transfer = event.clipboardData
if (!transfer || !hasPlainText(transfer)) return
@@ -26,6 +39,7 @@ function onPaste(event: ClipboardEvent) {
const selectedText = field.value.substring(field.selectionStart, field.selectionEnd)
if (!selectedText.length) return
+
// Prevent linkification when replacing an URL
// Trim whitespace in case whitespace is selected by mistake or by intention
if (isURL(selectedText.trim())) return
diff --git a/test/test.js b/test/test.js
index 12689f4..f2ee67a 100644
--- a/test/test.js
+++ b/test/test.js
@@ -43,6 +43,38 @@ describe('paste-markdown', function () {
assert.equal(textarea.value, 'The examples can be found [here](https://github.com).')
})
+ it('turns pasted urls on selected text into markdown links if pasteLinkAsPlainTextOverSelectedText is false', function () {
+ subscription = subscribeWithOptionConfig(subscription, textarea, false)
+
+ // eslint-disable-next-line i18n-text/no-en
+ textarea.value = 'The examples can be found here.'
+ textarea.setSelectionRange(26, 30)
+ paste(textarea, {'text/plain': 'https://github.com'})
+ assert.equal(textarea.value, 'The examples can be found [here](https://github.com).')
+ })
+
+ it('turns pasted urls on selected text into markdown links if pasteLinkAsPlainTextOverSelectedText is true and skip format flag is true', function () {
+ subscription = subscribeWithOptionConfig(subscription, textarea, true)
+
+ // eslint-disable-next-line i18n-text/no-en
+ textarea.value = 'The examples can be found here.'
+ textarea.setSelectionRange(26, 30)
+ dispatchSkipFormattingKeyEvent(textarea)
+ paste(textarea, {'text/plain': 'https://github.com'})
+ assert.equal(textarea.value, 'The examples can be found [here](https://github.com).')
+ })
+
+ it('pastes as plain text on selected text if pasteLinkAsPlainTextOverSelectedText is true', function () {
+ subscription = subscribeWithOptionConfig(subscription, textarea, true)
+
+ // eslint-disable-next-line i18n-text/no-en
+ textarea.value = 'The examples can be found here.'
+ textarea.setSelectionRange(26, 30)
+ paste(textarea, {'text/plain': 'https://github.com'})
+ // The text area will be unchanged at this stage as the paste won't be handled by our listener
+ assert.equal(textarea.value, 'The examples can be found here.')
+ })
+
it('creates a markdown link when the pasted url includes a trailing slash', function () {
// eslint-disable-next-line i18n-text/no-en
textarea.value = 'The examples can be found here.'
@@ -353,6 +385,12 @@ function dispatchSkipFormattingKeyEvent(textarea) {
)
}
+function subscribeWithOptionConfig(subscription, textarea, urlLinks) {
+ // Clear the before test subscription with no config and re-subscribe with config
+ subscription.unsubscribe()
+ return subscribe(textarea, {defaultPlainTextPaste: {urlLinks}})
+}
+
function paste(textarea, data) {
const dataTransfer = new DataTransfer()
for (const key in data) {