diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index bb663c5e..9d391125 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -895,6 +895,12 @@ export default class MarkdownPreview extends React.Component { this.setImgOnClickEventHelper(img, rect) imgObserver.observe(parentEl, config) } + + const aList = markdownPreviewIframe.contentWindow.document.body.querySelectorAll('a') + for (const a of aList) { + a.removeEventListener('click', this.linkClickHandler) + a.addEventListener('click', this.linkClickHandler) + } } setImgOnClickEventHelper (img, rect) { @@ -1023,11 +1029,11 @@ export default class MarkdownPreview extends React.Component { if (!rawHref) return // not checked href because parser will create file://... string for [empty link]() - const regexNoteInternalLink = /.*[main.\w]*.html#/ - - if (regexNoteInternalLink.test(href)) { - const targetId = mdurl.encode(linkHash) - const targetElement = this.refs.root.contentWindow.document.querySelector( + const extractId = /(main.html)?#/ + const regexNoteInternalLink = new RegExp(`${extractId.source}(.+)`) + if (regexNoteInternalLink.test(linkHash)) { + const targetId = mdurl.encode(linkHash.replace(extractId, '')) + const targetElement = this.refs.root.contentWindow.document.getElementById( targetId ) diff --git a/browser/lib/markdown-toc-generator.js b/browser/lib/markdown-toc-generator.js index 8f027247..7c76c1f3 100644 --- a/browser/lib/markdown-toc-generator.js +++ b/browser/lib/markdown-toc-generator.js @@ -21,7 +21,7 @@ function uniqueSlug (slug, slugs, opts) { } function linkify (token) { - token.content = mdlink(token.content, '#' + token.slug) + token.content = mdlink(token.content, `#${decodeURI(token.slug)}`) return token } diff --git a/browser/lib/slugify.js b/browser/lib/slugify.js index a3447a90..21c18e02 100644 --- a/browser/lib/slugify.js +++ b/browser/lib/slugify.js @@ -1,17 +1,11 @@ -import diacritics from 'diacritics-map' - -function replaceDiacritics (str) { - return str.replace(/[À-ž]/g, function (ch) { - return diacritics[ch] || ch - }) -} - module.exports = function slugify (title) { - let slug = title.trim() + const slug = encodeURI( + title.trim() + .replace(/^\s+/, '') + .replace(/\s+$/, '') + .replace(/\s+/g, '-') + .replace(/[\]\[\!\'\#\$\%\&\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\{\|\}\~\`]/g, '') + ) - slug = replaceDiacritics(slug) - - slug = slug.replace(/[^\w\s-]/g, '').replace(/\s+/g, '-') - - return encodeURI(slug).replace(/\-+$/, '') + return slug } diff --git a/tests/lib/slugify-test.js b/tests/lib/slugify-test.js new file mode 100644 index 00000000..0277bd10 --- /dev/null +++ b/tests/lib/slugify-test.js @@ -0,0 +1,58 @@ +import test from 'ava' +import slugify from 'browser/lib/slugify' + +test('alphabet and digit', t => { + const upperAlphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + const lowerAlphabet = 'abcdefghijklmnopqrstuvwxyz' + const digit = '0123456789' + const testCase = upperAlphabet + lowerAlphabet + digit + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === testCase) +}) + +test('should delete unavailable symbols', t => { + const availableSymbols = '_-' + const testCase = availableSymbols + '][!\'#$%&()*+,./:;<=>?@\\^{|}~`' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === availableSymbols) +}) + +test('should convert from white spaces between words to hyphens', t => { + const testCase = 'This is one' + const expectedString = 'This-is-one' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === expectedString) +}) + +test('should remove leading white spaces', t => { + const testCase = ' This is one' + const expectedString = 'This-is-one' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === expectedString) +}) + +test('should remove trailing white spaces', t => { + const testCase = 'This is one ' + const expectedString = 'This-is-one' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === expectedString) +}) + +test('2-byte charactor support', t => { + const testCase = '菠萝芒果テストÀžƁƵ' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === testCase) +}) + +test('emoji', t => { + const testCase = '🌸' + const decodeSlug = decodeURI(slugify(testCase)) + + t.true(decodeSlug === testCase) +})