mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-11 08:46:20 +00:00
162 lines
5.5 KiB
JavaScript
162 lines
5.5 KiB
JavaScript
export function lastFindInArray(array, callback) {
|
|
for (let i = array.length - 1; i >= 0; --i) {
|
|
if (callback(array[i], i, array)) {
|
|
return array[i]
|
|
}
|
|
}
|
|
}
|
|
|
|
export function escapeHtmlCharacters(
|
|
html,
|
|
opt = { detectCodeBlock: false, skipSingleQuote: false }
|
|
) {
|
|
const matchHtmlRegExp = /["'&<>]/g
|
|
const matchCodeBlockRegExp = /```/g
|
|
const escapes = ['"', '&', ''', '<', '>']
|
|
let match = null
|
|
const replaceAt = (str, index, replace) =>
|
|
str.substr(0, index) +
|
|
replace +
|
|
str.substr(index + replace.length - (replace.length - 1))
|
|
|
|
while ((match = matchHtmlRegExp.exec(html)) !== null) {
|
|
const current = { char: match[0], index: match.index }
|
|
const codeBlockIndexs = []
|
|
let openCodeBlock = null
|
|
// if the detectCodeBlock option is activated then this function should skip
|
|
// characters that needed to be escape but located in code block
|
|
if (opt.detectCodeBlock) {
|
|
// The first type of code block is lines that start with 4 spaces
|
|
// Here we check for the \n character located before the character that
|
|
// needed to be escape. It means we check for the begining of the line that
|
|
// contain that character, then we check if there are 4 spaces next to the
|
|
// \n character (the line start with 4 spaces)
|
|
let previousLineEnd = current.index - 1
|
|
while (html[previousLineEnd] !== '\n' && previousLineEnd !== -1) {
|
|
previousLineEnd--
|
|
}
|
|
// 4 spaces means this character is in a code block
|
|
if (
|
|
html[previousLineEnd + 1] === ' ' &&
|
|
html[previousLineEnd + 2] === ' ' &&
|
|
html[previousLineEnd + 3] === ' ' &&
|
|
html[previousLineEnd + 4] === ' '
|
|
) {
|
|
// skip the current character
|
|
continue
|
|
}
|
|
// The second type of code block is lines that wrapped in ```
|
|
// We will get the position of each ```
|
|
// then push it into an array
|
|
// then the array returned will be like this:
|
|
// [startCodeblock, endCodeBlock, startCodeBlock, endCodeBlock]
|
|
while ((openCodeBlock = matchCodeBlockRegExp.exec(html)) !== null) {
|
|
codeBlockIndexs.push(openCodeBlock.index)
|
|
}
|
|
let shouldSkipChar = false
|
|
// we loop through the array of positions
|
|
// we skip 2 element as the i index position is the position of ``` that
|
|
// open the codeblock and the i + 1 is the position of the ``` that close
|
|
// the code block
|
|
for (let i = 0; i < codeBlockIndexs.length; i += 2) {
|
|
// the i index position is the position of the ``` that open code block
|
|
// so we have to + 2 as that position is the position of the first ` in the ````
|
|
// but we need to make sure that the position current character is larger
|
|
// that the last ` in the ``` that open the code block so we have to take
|
|
// the position of the first ` and + 2
|
|
// the i + 1 index position is the closing ``` so the char must less than it
|
|
if (
|
|
current.index > codeBlockIndexs[i] + 2 &&
|
|
current.index < codeBlockIndexs[i + 1]
|
|
) {
|
|
// skip it
|
|
shouldSkipChar = true
|
|
break
|
|
}
|
|
}
|
|
if (shouldSkipChar) {
|
|
// skip the current character
|
|
continue
|
|
}
|
|
}
|
|
// otherwise, escape it !!!
|
|
if (current.char === '&') {
|
|
// when escaping character & we have to be becareful as the & could be a part
|
|
// of an escaped character like " will be came &quot;
|
|
let nextStr = ''
|
|
let nextIndex = current.index
|
|
let escapedStr = false
|
|
// maximum length of an escaped string is 5. For example ('"')
|
|
// we take the next 5 character of the next string if it is one of the string:
|
|
// ['"', '&', ''', '<', '>'] then we will not escape the & character
|
|
// as it is a part of the escaped string and should not be escaped
|
|
while (nextStr.length <= 5) {
|
|
nextStr += html[nextIndex]
|
|
nextIndex++
|
|
if (escapes.indexOf(nextStr) !== -1) {
|
|
escapedStr = true
|
|
break
|
|
}
|
|
}
|
|
if (!escapedStr) {
|
|
// this & char is not a part of an escaped string
|
|
html = replaceAt(html, current.index, '&')
|
|
}
|
|
} else if (current.char === '"') {
|
|
html = replaceAt(html, current.index, '"')
|
|
} else if (current.char === "'" && !opt.skipSingleQuote) {
|
|
html = replaceAt(html, current.index, ''')
|
|
} else if (current.char === '<') {
|
|
html = replaceAt(html, current.index, '<')
|
|
} else if (current.char === '>') {
|
|
html = replaceAt(html, current.index, '>')
|
|
}
|
|
}
|
|
return html
|
|
}
|
|
|
|
export function isObjectEqual(a, b) {
|
|
const aProps = Object.getOwnPropertyNames(a)
|
|
const bProps = Object.getOwnPropertyNames(b)
|
|
|
|
if (aProps.length !== bProps.length) {
|
|
return false
|
|
}
|
|
|
|
for (var i = 0; i < aProps.length; i++) {
|
|
const propName = aProps[i]
|
|
if (a[propName] !== b[propName]) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
export function isMarkdownTitleURL(str) {
|
|
return /(^#{1,6}\s)(?:\w+:|^)\/\/(?:[^\s\.]+\.\S{2}|localhost[\:?\d]*)/.test(
|
|
str
|
|
)
|
|
}
|
|
|
|
export function humanFileSize(bytes) {
|
|
const threshold = 1000
|
|
if (Math.abs(bytes) < threshold) {
|
|
return bytes + ' B'
|
|
}
|
|
var units = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
|
var u = -1
|
|
do {
|
|
bytes /= threshold
|
|
++u
|
|
} while (Math.abs(bytes) >= threshold && u < units.length - 1)
|
|
return bytes.toFixed(1) + ' ' + units[u]
|
|
}
|
|
|
|
export default {
|
|
lastFindInArray,
|
|
escapeHtmlCharacters,
|
|
isObjectEqual,
|
|
isMarkdownTitleURL,
|
|
humanFileSize
|
|
}
|