Browse Source
* Skip selections across elements
* Drop `g-emoji` elements
* Drop tasks from lists
* Drop autolinks around images
* Keep <img> if it has width, height or align
* Unwrap commit/issue autolinks
* Unwrap some shortened links
* Wrap orphaned <li>s in their original parent
This allows partial list selections. Without a parent, <li>s will be
rendered inline elements by to-markdown
* Add support for <ol> lists that start after 1
* Keep the original number of orphaned <li>s in numbered lists
* It should only prevent the original copy if it succeeds
* Add tests ⚡️
* Update to-markdown@3.1.0
Include ol[start] support
master
Federico Brigante
7 years ago
committed by
Sindre Sorhus
3 changed files with 163 additions and 6 deletions
@ -1,22 +1,77 @@ |
|||
import toMarkdown from 'to-markdown'; |
|||
import copyToClipboard from 'copy-text-to-clipboard'; |
|||
|
|||
const unwrapContent = content => content; |
|||
const unshortenRegex = /^https:[/][/](www[.])?|[/]$/g; |
|||
|
|||
const converters = [ |
|||
// Drop unnecessary elements
|
|||
// <g-emoji> is GH's emoji wrapper
|
|||
// input and .handle appear in "- [ ] lists", let's not copy tasks
|
|||
{ |
|||
filter: node => node.matches('g-emoji,.handle,input.task-list-item-checkbox'), |
|||
replacement: unwrapContent |
|||
}, |
|||
|
|||
// Unwrap commit/issue autolinks
|
|||
{ |
|||
filter: node => node.matches('.commit-link,.issue-link') || // GH autolinks
|
|||
(node.href && node.href.replace(unshortenRegex, '') === node.textContent), // Some of bfred-it/shorten-repo-url
|
|||
replacement: (content, element) => element.href |
|||
}, |
|||
|
|||
// Unwrap images
|
|||
{ |
|||
filter: node => node.tagName === 'A' && // It's a link
|
|||
node.childNodes.length === 1 && // It has one child
|
|||
node.firstChild.tagName === 'IMG' && // Its child is an image
|
|||
node.firstChild.src === node.href, // It links to its own image
|
|||
replacement: unwrapContent |
|||
}, |
|||
|
|||
// Keep <img> if it's customized
|
|||
{ |
|||
filter: node => node.matches('img[width],img[height],img[align]'), |
|||
replacement: (content, element) => element.outerHTML |
|||
} |
|||
]; |
|||
|
|||
export const getSmarterMarkdown = html => toMarkdown(html, { |
|||
converters, |
|||
gfm: true |
|||
}); |
|||
|
|||
export default event => { |
|||
const selection = window.getSelection(); |
|||
const range = selection.getRangeAt(0); |
|||
const container = range.commonAncestorContainer; |
|||
const containerEl = container.closest ? container : container.parentNode; |
|||
|
|||
if (containerEl.closest('pre')) { |
|||
// Exclude pure code selections and selections across markdown elements:
|
|||
// https://github.com/sindresorhus/refined-github/issues/522#issuecomment-311271274
|
|||
if (containerEl.closest('pre') || containerEl.querySelector('.markdown-body')) { |
|||
return; |
|||
} |
|||
|
|||
event.stopImmediatePropagation(); |
|||
event.preventDefault(); |
|||
|
|||
const holder = document.createElement('div'); |
|||
holder.append(range.cloneContents()); |
|||
const markdown = toMarkdown(holder.innerHTML, {gfm: true}); |
|||
|
|||
// Wrap orphaned <li>s in their original parent
|
|||
// And keep the their original number
|
|||
if (holder.firstChild.tagName === 'LI') { |
|||
const list = document.createElement(containerEl.tagName); |
|||
try { |
|||
const originalLi = range.startContainer.parentNode.closest('li'); |
|||
list.start = containerEl.start + [...containerEl.children].indexOf(originalLi); |
|||
} catch (err) {} |
|||
list.append(...holder.childNodes); |
|||
holder.appendChild(list); |
|||
} |
|||
|
|||
const markdown = getSmarterMarkdown(holder.innerHTML); |
|||
|
|||
copyToClipboard(markdown); |
|||
|
|||
event.stopImmediatePropagation(); |
|||
event.preventDefault(); |
|||
}; |
|||
|
@ -0,0 +1,101 @@ |
|||
import test from 'ava'; |
|||
import {stripIndent} from 'common-tags'; |
|||
import {getSmarterMarkdown} from '../src/libs/copy-markdown'; |
|||
|
|||
test('base markdown', t => { |
|||
t.is( |
|||
getSmarterMarkdown('<a href="url">this</a> is <strong>markdown</strong>'), |
|||
'[this](url) is **markdown**' |
|||
); |
|||
}); |
|||
|
|||
test('drop <g-emoji>', t => { |
|||
t.is( |
|||
getSmarterMarkdown('<g-emoji alias="fire" fallback-src="https://assets-cdn.github.com/images/icons/emoji/unicode/1f525.png" ios-version="6.0" title=":fire:">🔥</g-emoji>'), |
|||
'🔥' |
|||
); |
|||
}); |
|||
|
|||
test('drop tasks from lists', t => { |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<ul class="contains-task-list"> |
|||
<li class="task-list-item enabled"><span class="handle"><svg class="drag-handle" aria-hidden="true" width="16" height="15" version="1.1" viewBox="0 0 16 15"><path d="M12,4V5H4V4h8ZM4,8h8V7H4V8Zm0,3h8V10H4v1Z"></path></svg></span><input type="checkbox" class="task-list-item-checkbox"> try me out</li> |
|||
<li class="task-list-item enabled"><span class="handle"><svg class="drag-handle" aria-hidden="true" width="16" height="15" version="1.1" viewBox="0 0 16 15"><path d="M12,4V5H4V4h8ZM4,8h8V7H4V8Zm0,3h8V10H4v1Z"></path></svg></span><input type="checkbox" class="task-list-item-checkbox" checked=""> test across lines</li> |
|||
</ul> |
|||
`),
|
|||
stripIndent` |
|||
* try me out |
|||
* test across lines |
|||
` |
|||
); |
|||
}); |
|||
|
|||
test('drop autolinks around images', t => { |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<a href="https://camo.githubusercontent.com/7a0ef30dc39981585543e0bbd816392a52dddd8a/687474703a2f2f692e696d6775722e636f6d2f4b6361644c36472e706e67" target="_blank"><img src="https://camo.githubusercontent.com/7a0ef30dc39981585543e0bbd816392a52dddd8a/687474703a2f2f692e696d6775722e636f6d2f4b6361644c36472e706e67" alt="" style="max-width:100%;"></a> |
|||
`),
|
|||
stripIndent` |
|||
![](https://camo.githubusercontent.com/7a0ef30dc39981585543e0bbd816392a52dddd8a/687474703a2f2f692e696d6775722e636f6d2f4b6361644c36472e706e67)
|
|||
` |
|||
); |
|||
}); |
|||
|
|||
test('keep img tags if they have width, height or align', t => { |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<a href="https://camo.githubusercontent.com/7a0ef30dc39981585543e0bbd816392a52dddd8a/687474703a2f2f692e696d6775722e636f6d2f4b6361644c36472e706e67" target="_blank"><img align="center" width="32" alt="copy" src="https://camo.githubusercontent.com/7a0ef30dc39981585543e0bbd816392a52dddd8a/687474703a2f2f692e696d6775722e636f6d2f4b6361644c36472e706e67" style="max-width:100%;"></a> |
|||
`),
|
|||
stripIndent` |
|||
<img align="center" width="32" alt="copy" src="https://camo.githubusercontent.com/7a0ef30dc39981585543e0bbd816392a52dddd8a/687474703a2f2f692e696d6775722e636f6d2f4b6361644c36472e706e67" style="max-width:100%;"> |
|||
` |
|||
); |
|||
}); |
|||
|
|||
test('drop autolinks from issue links and commit links', t => { |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<a href="https://github.com/sindresorhus/refined-github/issues/522" class="issue-link js-issue-link" data-id="237988387" data-error-text="Failed to load issue title" data-permission-text="Issue title is private" title="'Copy to Markdown' improvements">#522</a> |
|||
`),
|
|||
'https://github.com/sindresorhus/refined-github/issues/522' |
|||
); |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<a href="https://github.com/sindresorhus/refined-github/commit/833d5984fffb18a44b83d965b397f82e0ff3085e" class="commit-link"><tt>833d598</tt></a> |
|||
`),
|
|||
'https://github.com/sindresorhus/refined-github/commit/833d5984fffb18a44b83d965b397f82e0ff3085e' |
|||
); |
|||
}); |
|||
|
|||
test('drop autolinks around some shortened links', t => { |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<p><a href="https://www.npmjs.com">npmjs.com</a></p> |
|||
<p><a href="https://twitter.com/bfred_it">twitter.com/bfred_it</a></p> |
|||
<p><a href="https://github.com/">github.com</a></p> |
|||
`),
|
|||
stripIndent` |
|||
https://www.npmjs.com/
|
|||
|
|||
https://twitter.com/bfred_it
|
|||
|
|||
https://github.com/
|
|||
` |
|||
); |
|||
}); |
|||
|
|||
test('wrap orphaned li in their original parent', t => { |
|||
t.is( |
|||
getSmarterMarkdown(stripIndent` |
|||
<ol start="99"> |
|||
<li>big lists</li> |
|||
<li>deserve big numbers</li> |
|||
</ol> |
|||
`),
|
|||
stripIndent` |
|||
99. big lists |
|||
100. deserve big numbers |
|||
` |
|||
); |
|||
}); |
Loading…
Reference in new issue