1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 17:56:25 +00:00

Merge remote-tracking branch 'upstream/master' into allow-no-html-escape

This commit is contained in:
Nguyễn Việt Hưng
2018-07-04 13:50:10 +07:00
98 changed files with 3852 additions and 2050 deletions

View File

@@ -22,10 +22,12 @@ const attachmentManagement = require('../main/lib/dataApi/attachmentManagement')
const { app } = remote
const path = require('path')
const fileUrl = require('file-url')
const dialog = remote.dialog
const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1]
const appPath = 'file://' + (process.env.NODE_ENV === 'production'
const appPath = fileUrl(process.env.NODE_ENV === 'production'
? app.getAppPath()
: path.resolve())
const CSS_FILES = [
@@ -33,7 +35,7 @@ const CSS_FILES = [
`${appPath}/node_modules/codemirror/lib/codemirror.css`
]
function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme) {
function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS) {
return `
@font-face {
font-family: 'Lato';
@@ -53,7 +55,19 @@ function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber, scro
font-weight: 700;
text-rendering: optimizeLegibility;
}
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff2') format('woff2'),
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff') format('woff'),
url('${appPath}/resources/fonts/MaterialIcons-Regular.ttf') format('truetype');
}
${allowCustomCSS ? customCSS : ''}
${markdownStyle}
body {
font-family: '${fontFamily.join("','")}';
font-size: ${fontSize}px;
@@ -111,6 +125,9 @@ body p {
color: #000;
background-color: #fff;
}
.clipboardButton {
display: none
}
}
`
}
@@ -133,7 +150,6 @@ export default class MarkdownPreview extends React.Component {
this.mouseUpHandler = (e) => this.handleMouseUp(e)
this.DoubleClickHandler = (e) => this.handleDoubleClick(e)
this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true})
this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e)
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
this.saveAsTextHandler = () => this.handleSaveAsText()
this.saveAsMdHandler = () => this.handleSaveAsMd()
@@ -146,29 +162,14 @@ export default class MarkdownPreview extends React.Component {
}
initMarkdown () {
const { smartQuotes, sanitize } = this.props
const { smartQuotes, sanitize, breaks } = this.props
this.markdown = new Markdown({
typographer: smartQuotes,
sanitize
sanitize,
breaks
})
}
handlePreviewAnchorClick (e) {
e.preventDefault()
e.stopPropagation()
const anchor = e.target.closest('a')
const href = anchor.getAttribute('href')
if (_.isString(href) && href.match(/^#/)) {
const targetElement = this.refs.root.contentWindow.document.getElementById(href.substring(1, href.length))
if (targetElement != null) {
this.getWindow().scrollTo(0, targetElement.offsetTop)
}
} else {
shell.openExternal(href)
}
}
handleCheckboxClick (e) {
this.props.onCheckboxClick(e)
}
@@ -216,9 +217,9 @@ export default class MarkdownPreview extends React.Component {
handleSaveAsHtml () {
this.exportAsDocument('html', (noteContent, exportTasks) => {
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme} = this.getStyleParams()
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = this.getStyleParams()
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme)
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS)
let body = this.markdown.render(escapeHtmlCharacters(noteContent))
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
@@ -341,7 +342,10 @@ export default class MarkdownPreview extends React.Component {
componentDidUpdate (prevProps) {
if (prevProps.value !== this.props.value) this.rewriteIframe()
if (prevProps.smartQuotes !== this.props.smartQuotes || prevProps.sanitize !== this.props.sanitize) {
if (prevProps.smartQuotes !== this.props.smartQuotes ||
prevProps.sanitize !== this.props.sanitize ||
prevProps.smartArrows !== this.props.smartArrows ||
prevProps.breaks !== this.props.breaks) {
this.initMarkdown()
this.rewriteIframe()
}
@@ -352,14 +356,16 @@ export default class MarkdownPreview extends React.Component {
prevProps.lineNumber !== this.props.lineNumber ||
prevProps.showCopyNotification !== this.props.showCopyNotification ||
prevProps.theme !== this.props.theme ||
prevProps.scrollPastEnd !== this.props.scrollPastEnd) {
prevProps.scrollPastEnd !== this.props.scrollPastEnd ||
prevProps.allowCustomCSS !== this.props.allowCustomCSS ||
prevProps.customCSS !== this.props.customCSS) {
this.applyStyle()
this.rewriteIframe()
}
}
getStyleParams () {
const { fontSize, lineNumber, codeBlockTheme, scrollPastEnd, theme } = this.props
const { fontSize, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS } = this.props
let { fontFamily, codeBlockFontFamily } = this.props
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
? fontFamily.split(',').map(fontName => fontName.trim()).concat(defaultFontFamily)
@@ -368,14 +374,14 @@ export default class MarkdownPreview extends React.Component {
? codeBlockFontFamily.split(',').map(fontName => fontName.trim()).concat(defaultCodeBlockFontFamily)
: defaultCodeBlockFontFamily
return {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme}
return {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS}
}
applyStyle () {
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme} = this.getStyleParams()
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = this.getStyleParams()
this.getWindow().document.getElementById('codeTheme').href = this.GetCodeThemeLink(codeBlockTheme)
this.getWindow().document.getElementById('style').innerHTML = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme)
this.getWindow().document.getElementById('style').innerHTML = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS)
}
GetCodeThemeLink (theme) {
@@ -388,9 +394,6 @@ export default class MarkdownPreview extends React.Component {
}
rewriteIframe () {
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
el.removeEventListener('click', this.anchorClickHandler)
})
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
el.removeEventListener('click', this.checkboxClickHandler)
})
@@ -399,7 +402,7 @@ export default class MarkdownPreview extends React.Component {
el.removeEventListener('click', this.linkClickHandler)
})
const { theme, indentSize, showCopyNotification, storagePath } = this.props
const { theme, indentSize, showCopyNotification, storagePath, noteKey } = this.props
let { value, codeBlockTheme } = this.props
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
@@ -411,18 +414,15 @@ export default class MarkdownPreview extends React.Component {
})
}
let renderedHTML = this.markdown.render(value)
attachmentManagement.migrateAttachments(renderedHTML, storagePath, noteKey)
this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(renderedHTML, storagePath)
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
this.fixDecodedURI(el)
el.addEventListener('click', this.anchorClickHandler)
})
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
el.addEventListener('click', this.checkboxClickHandler)
})
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
this.fixDecodedURI(el)
el.addEventListener('click', this.linkClickHandler)
})
@@ -473,7 +473,7 @@ export default class MarkdownPreview extends React.Component {
el.innerHTML = ''
diagram.drawSVG(el, opts)
_.forEach(el.querySelectorAll('a'), (el) => {
el.addEventListener('click', this.anchorClickHandler)
el.addEventListener('click', this.linkClickHandler)
})
} catch (e) {
console.error(e)
@@ -489,7 +489,7 @@ export default class MarkdownPreview extends React.Component {
el.innerHTML = ''
diagram.drawSVG(el, {theme: 'simple'})
_.forEach(el.querySelectorAll('a'), (el) => {
el.addEventListener('click', this.anchorClickHandler)
el.addEventListener('click', this.linkClickHandler)
})
} catch (e) {
console.error(e)
@@ -538,11 +538,6 @@ export default class MarkdownPreview extends React.Component {
e.stopPropagation()
const href = e.target.href
if (href.match(/^http/i)) {
shell.openExternal(href)
return
}
const linkHash = href.split('/').pop()
const regexNoteInternalLink = /main.html#(.+)/
@@ -574,6 +569,9 @@ export default class MarkdownPreview extends React.Component {
eventEmitter.emit('list:jump', linkHash.split('-')[1])
return
}
// other case
shell.openExternal(href)
}
render () {
@@ -596,9 +594,12 @@ MarkdownPreview.propTypes = {
onDoubleClick: PropTypes.func,
onMouseUp: PropTypes.func,
onMouseDown: PropTypes.func,
onContextMenu: PropTypes.func,
className: PropTypes.string,
value: PropTypes.string,
showCopyNotification: PropTypes.bool,
storagePath: PropTypes.string,
smartQuotes: PropTypes.bool
smartQuotes: PropTypes.bool,
smartArrows: PropTypes.bool,
breaks: PropTypes.bool
}