diff --git a/src/muya/lib/contentState/copyCutCtrl.js b/src/muya/lib/contentState/copyCutCtrl.js
index 998c04fc..7e37429d 100644
--- a/src/muya/lib/contentState/copyCutCtrl.js
+++ b/src/muya/lib/contentState/copyCutCtrl.js
@@ -45,7 +45,7 @@ const copyCutCtrl = ContentState => {
this.partialRender()
}
- ContentState.prototype.getClipBoradData = function () {
+ ContentState.prototype.getClipBoardData = function () {
const { start, end } = selection.getCursorRange()
if (!start || !end) {
return { html: '', text: '' }
@@ -274,7 +274,7 @@ const copyCutCtrl = ContentState => {
return
}
- const { html, text } = this.getClipBoradData()
+ const { html, text } = this.getClipBoardData()
switch (type) {
case 'normal': {
event.clipboardData.setData('text/html', html)
diff --git a/src/muya/lib/contentState/pasteCtrl.js b/src/muya/lib/contentState/pasteCtrl.js
index ee33b375..389aeae5 100644
--- a/src/muya/lib/contentState/pasteCtrl.js
+++ b/src/muya/lib/contentState/pasteCtrl.js
@@ -41,17 +41,17 @@ const pasteCtrl = ContentState => {
}
// Try to identify the data type.
- ContentState.prototype.checkCopyType = function (html, text) {
+ ContentState.prototype.checkCopyType = function (html, rawText) {
let type = 'normal'
- if (!html && text) {
+ if (!html && rawText) {
type = 'copyAsMarkdown'
- const match = /^<([a-zA-Z\d-]+)(?=\s|>).*?>[\s\S]+?<\/([a-zA-Z\d-]+)>$/.exec(text.trim())
+ const match = /^<([a-zA-Z\d-]+)(?=\s|>).*?>[\s\S]+?<\/([a-zA-Z\d-]+)>$/.exec(rawText.trim())
if (match && match[1]) {
const tag = match[1]
if (tag === 'table' && match.length === 3 && match[2] === 'table') {
// Try to import a single table
const tmp = document.createElement('table')
- tmp.innerHTML = text
+ tmp.innerHTML = sanitize(rawText, PREVIEW_DOMPURIFY_CONFIG, false)
if (tmp.childElementCount === 1) {
return 'htmlToMd'
}
@@ -64,17 +64,17 @@ const pasteCtrl = ContentState => {
return type
}
- ContentState.prototype.standardizeHTML = async function (html) {
+ ContentState.prototype.standardizeHTML = async function (rawHtml) {
// Only extract the `body.innerHTML` when the `html` is a full HTML Document.
- if (/
[\s\S]*<\/body>/.test(html)) {
- const match = /([\s\S]*)<\/body>/.exec(html)
+ if (/[\s\S]*<\/body>/.test(rawHtml)) {
+ const match = /([\s\S]*)<\/body>/.exec(rawHtml)
if (match && typeof match[1] === 'string') {
- html = match[1]
+ rawHtml = match[1]
}
}
// Prevent XSS and sanitize HTML.
- const sanitizedHtml = sanitize(html, PREVIEW_DOMPURIFY_CONFIG, false)
+ const sanitizedHtml = sanitize(rawHtml, PREVIEW_DOMPURIFY_CONFIG, false)
const tempWrapper = document.createElement('div')
tempWrapper.innerHTML = sanitizedHtml
@@ -98,9 +98,9 @@ const pasteCtrl = ContentState => {
const tds = table.querySelectorAll('td')
for (const td of tds) {
- const rawHtml = td.innerHTML
- if (/
/.test(rawHtml)) {
- td.innerHTML = rawHtml.replace(/
/g, '<br>')
+ const tableDataHtml = td.innerHTML
+ if (/
/.test(tableDataHtml)) {
+ td.innerHTML = tableDataHtml.replace(/
/g, '<br>')
}
}
}
@@ -110,11 +110,10 @@ const pasteCtrl = ContentState => {
for (const link of links) {
const href = link.getAttribute('href')
const text = link.textContent
-
- if (href === text) {
+ if (URL_REG.test(href) && href === text) {
const title = await getPageTitle(href)
if (title) {
- link.textContent = title
+ link.innerHTML = sanitize(title, PREVIEW_DOMPURIFY_CONFIG, true)
} else {
const span = document.createElement('span')
span.innerHTML = text
@@ -266,13 +265,17 @@ const pasteCtrl = ContentState => {
const text = rawText || event.clipboardData.getData('text/plain')
let html = rawHtml || event.clipboardData.getData('text/html')
+ if (!text && !html) {
+ return
+ }
// Support pasted URLs from Firefox.
if (URL_REG.test(text) && !/\s/.test(text) && !html) {
html = `${text}`
}
- // Remove crap from HTML such as meta data and styles.
+ // Remove crap from HTML such as meta data and styles and sanitize HTML,
+ // but `text` may still contain dangerous HTML.
html = await this.standardizeHTML(html)
let copyType = this.checkCopyType(html, text)
@@ -282,7 +285,7 @@ const pasteCtrl = ContentState => {
const parent = this.getParent(startBlock)
if (copyType === 'htmlToMd') {
- html = text
+ html = sanitize(text, PREVIEW_DOMPURIFY_CONFIG, false)
copyType = 'normal'
}
diff --git a/src/muya/lib/parser/render/renderBlock/renderLeafBlock.js b/src/muya/lib/parser/render/renderBlock/renderLeafBlock.js
index 3f994cbe..8405891a 100644
--- a/src/muya/lib/parser/render/renderBlock/renderLeafBlock.js
+++ b/src/muya/lib/parser/render/renderBlock/renderLeafBlock.js
@@ -1,5 +1,5 @@
import katex from 'katex'
-import prism, { loadedLanguages, transfromAliasToOrigin } from '../../../prism/'
+import prism, { loadedLanguages, transformAliasToOrigin } from '../../../prism/'
import 'katex/dist/contrib/mhchem.min.js'
import { CLASS_OR_ID, DEVICE_MEMORY, PREVIEW_DOMPURIFY_CONFIG, HAS_TEXT_BLOCK_REG } from '../../../config'
import { tokenizer } from '../../'
@@ -114,7 +114,6 @@ export default function renderLeafBlock (parent, block, activeBlocks, matches, u
this.tokenCache.set(text, tokens)
}
}
-
children = tokens.reduce((acc, token) => [...acc, ...this[snakeToCamel(token.type)](h, cursor, block, token)], [])
}
@@ -233,8 +232,8 @@ export default function renderLeafBlock (parent, block, activeBlocks, matches, u
.replace(new RegExp(MARKER_HASK['"'], 'g'), '"')
.replace(new RegExp(MARKER_HASK["'"], 'g'), "'")
- // transfrom alias to original language
- const transformedLang = transfromAliasToOrigin([lang])[0]
+ // transform alias to original language
+ const transformedLang = transformAliasToOrigin([lang])[0]
if (transformedLang && /\S/.test(code) && loadedLanguages.has(transformedLang)) {
const wrapper = document.createElement('div')
wrapper.classList.add(`language-${transformedLang}`)
diff --git a/src/muya/lib/parser/render/renderInlines/image.js b/src/muya/lib/parser/render/renderInlines/image.js
index 84d0a7ae..194ef355 100644
--- a/src/muya/lib/parser/render/renderInlines/image.js
+++ b/src/muya/lib/parser/render/renderInlines/image.js
@@ -41,6 +41,7 @@ export default function image (h, cursor, block, token, outerClass) {
if (src) {
({ id, isSuccess, domsrc } = this.loadImageAsync(imageInfo, token.attrs))
}
+
let wrapperSelector = id
? `span#${isSuccess ? block.key + '_' + id + '_' + token.range.start : id}.${CLASS_OR_ID.AG_INLINE_IMAGE}`
: `span.${CLASS_OR_ID.AG_INLINE_IMAGE}`
diff --git a/src/muya/lib/prism/index.js b/src/muya/lib/prism/index.js
index 52574e02..d9e71bb0 100644
--- a/src/muya/lib/prism/index.js
+++ b/src/muya/lib/prism/index.js
@@ -1,6 +1,6 @@
import Prism from 'prismjs'
import { filter } from 'fuzzaldrin'
-import initLoadLanguage, { loadedLanguages, transfromAliasToOrigin } from './loadLanguage'
+import initLoadLanguage, { loadedLanguages, transformAliasToOrigin } from './loadLanguage'
import { languages } from 'prismjs/components.js'
const prism = Prism
@@ -45,7 +45,7 @@ export {
search,
loadLanguage,
loadedLanguages,
- transfromAliasToOrigin
+ transformAliasToOrigin
}
export default prism
diff --git a/src/muya/lib/prism/loadLanguage.js b/src/muya/lib/prism/loadLanguage.js
index 3843aec0..841fd13a 100644
--- a/src/muya/lib/prism/loadLanguage.js
+++ b/src/muya/lib/prism/loadLanguage.js
@@ -11,7 +11,7 @@ export const loadedLanguages = new Set(['markup', 'css', 'clike', 'javascript'])
const { languages } = components
// Look for the origin languge by alias
-export const transfromAliasToOrigin = langs => {
+export const transformAliasToOrigin = langs => {
const result = []
for (const lang of langs) {
if (languages[lang]) {
diff --git a/src/muya/lib/selection/dom.js b/src/muya/lib/selection/dom.js
index d0930829..26d3971d 100644
--- a/src/muya/lib/selection/dom.js
+++ b/src/muya/lib/selection/dom.js
@@ -14,10 +14,9 @@ export const getTextContent = (node, blackList) => {
if (blackList.some(className => node.classList && node.classList.contains(className))) {
return text
}
- if (node.nodeType === 3) {
- text += node.textContent
- } else if (node.nodeType === 1 && node.classList.contains('ag-inline-image')) {
- // handle inline image
+
+ // Handle inline image
+ if (node.nodeType === 1 && node.classList.contains('ag-inline-image')) {
const raw = node.getAttribute('data-raw')
const imageContainer = node.querySelector('.ag-image-container')
const hasImg = imageContainer.querySelector('img')
@@ -30,14 +29,14 @@ export const getTextContent = (node, blackList) => {
text += child.textContent
}
}
- } else {
- text += raw
- }
- } else {
- const childNodes = node.childNodes
- for (const n of childNodes) {
- text += getTextContent(n, blackList)
+ return text
}
+ return text + raw
+ }
+
+ const childNodes = node.childNodes
+ for (const n of childNodes) {
+ text += getTextContent(n, blackList)
}
return text
}