mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 09:46:22 +00:00
Fixes that TOC hasn't id attribute when the title is all 2-byte characters (#2994)
* Fix: 2-byte character support of slug * Fix: Decodes slug to display slug * Fix: Removed a logic of replaceDiacritics * Fix: Fixed slugify to pass tests * Fix: Fixed not to remove underscore * Adds the test for slugify.js * Fix: Fix to jump to heading * Added a comment * Fix: Created click event only linking to heading * Fix: Fix to use handleLinkClick(e) * Fix: Changed the regex rule * Fix: Changed the regex rule of extractId
This commit is contained in:
@@ -895,6 +895,12 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
this.setImgOnClickEventHelper(img, rect)
|
this.setImgOnClickEventHelper(img, rect)
|
||||||
imgObserver.observe(parentEl, config)
|
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) {
|
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]()
|
if (!rawHref) return // not checked href because parser will create file://... string for [empty link]()
|
||||||
|
|
||||||
const regexNoteInternalLink = /.*[main.\w]*.html#/
|
const extractId = /(main.html)?#/
|
||||||
|
const regexNoteInternalLink = new RegExp(`${extractId.source}(.+)`)
|
||||||
if (regexNoteInternalLink.test(href)) {
|
if (regexNoteInternalLink.test(linkHash)) {
|
||||||
const targetId = mdurl.encode(linkHash)
|
const targetId = mdurl.encode(linkHash.replace(extractId, ''))
|
||||||
const targetElement = this.refs.root.contentWindow.document.querySelector(
|
const targetElement = this.refs.root.contentWindow.document.getElementById(
|
||||||
targetId
|
targetId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function uniqueSlug (slug, slugs, opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function linkify (token) {
|
function linkify (token) {
|
||||||
token.content = mdlink(token.content, '#' + token.slug)
|
token.content = mdlink(token.content, `#${decodeURI(token.slug)}`)
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
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)
|
return slug
|
||||||
|
|
||||||
slug = slug.replace(/[^\w\s-]/g, '').replace(/\s+/g, '-')
|
|
||||||
|
|
||||||
return encodeURI(slug).replace(/\-+$/, '')
|
|
||||||
}
|
}
|
||||||
|
|||||||
58
tests/lib/slugify-test.js
Normal file
58
tests/lib/slugify-test.js
Normal file
@@ -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)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user