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

Merge branch 'master' into fence-attrs

This commit is contained in:
Baptiste Augrain
2018-11-06 09:35:59 +01:00
66 changed files with 905 additions and 184 deletions

View File

@@ -14,6 +14,8 @@ import consts from 'browser/lib/consts'
import fs from 'fs'
const { ipcRenderer } = require('electron')
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
import TurndownService from 'turndown'
import { gfm } from 'turndown-plugin-gfm'
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
@@ -57,6 +59,7 @@ export default class CodeEditor extends React.Component {
}
this.searchHandler = (e, msg) => this.handleSearch(msg)
this.searchState = null
this.scrollToLineHandeler = this.scrollToLine.bind(this)
this.formatTable = () => this.handleFormatTable()
this.editorActivityHandler = () => this.handleEditorActivity()
@@ -125,6 +128,7 @@ export default class CodeEditor extends React.Component {
componentDidMount () {
const { rulers, enableRulers } = this.props
const expandSnippet = this.expandSnippet.bind(this)
eventEmitter.on('line:jump', this.scrollToLineHandeler)
const defaultSnippet = [
{
@@ -475,7 +479,13 @@ export default class CodeEditor extends React.Component {
moveCursorTo (row, col) {}
scrollToLine (num) {}
scrollToLine (event, num) {
const cursor = {
line: num,
ch: 1
}
this.editor.setCursor(cursor)
}
focus () {
this.editor.focus()
@@ -538,7 +548,11 @@ export default class CodeEditor extends React.Component {
)
return prevChar === '](' && nextChar === ')'
}
if (dataTransferItem.type.match('image')) {
const pastedHtml = clipboardData.getData('text/html')
if (pastedHtml !== '') {
this.handlePasteHtml(e, editor, pastedHtml)
} else if (dataTransferItem.type.match('image')) {
attachmentManagement.handlePastImageEvent(
this,
storageKey,
@@ -608,6 +622,12 @@ export default class CodeEditor extends React.Component {
})
}
handlePasteHtml (e, editor, pastedHtml) {
e.preventDefault()
const markdown = this.turndownService.turndown(pastedHtml)
editor.replaceSelection(markdown)
}
mapNormalResponse (response, pastedTxt) {
return this.decodeResponse(response).then(body => {
return new Promise((resolve, reject) => {

View File

@@ -64,6 +64,10 @@ class MarkdownEditor extends React.Component {
})
}
setValue (value) {
this.refs.code.setValue(value)
}
handleChange (e) {
this.value = this.refs.code.value
this.props.onChange(e)
@@ -300,6 +304,7 @@ class MarkdownEditor extends React.Component {
noteKey={noteKey}
customCSS={config.preview.customCSS}
allowCustomCSS={config.preview.allowCustomCSS}
lineThroughCheckbox={config.preview.lineThroughCheckbox}
/>
</div>
)

View File

@@ -16,7 +16,6 @@ import convertModeName from 'browser/lib/convertModeName'
import copy from 'copy-to-clipboard'
import mdurl from 'mdurl'
import exportNote from 'browser/main/lib/dataApi/exportNote'
import { escapeHtmlCharacters } from 'browser/lib/utils'
import context from 'browser/lib/context'
import i18n from 'browser/lib/i18n'
import fs from 'fs'
@@ -80,7 +79,6 @@ function buildStyle (
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff') format('woff'),
url('${appPath}/resources/fonts/MaterialIcons-Regular.ttf') format('truetype');
}
${allowCustomCSS ? customCSS : ''}
${markdownStyle}
body {
@@ -88,6 +86,11 @@ body {
font-size: ${fontSize}px;
${scrollPastEnd && 'padding-bottom: 90vh;'}
}
@media print {
body {
padding-bottom: initial;
}
}
code {
font-family: '${codeBlockFontFamily.join("','")}';
background-color: rgba(0,0,0,0.04);
@@ -144,6 +147,8 @@ body p {
display: none
}
}
${allowCustomCSS ? customCSS : ''}
`
}
@@ -325,9 +330,7 @@ export default class MarkdownPreview extends React.Component {
allowCustomCSS,
customCSS
)
let body = this.markdown.render(
escapeHtmlCharacters(noteContent, { detectCodeBlock: true })
)
let body = this.markdown.render(noteContent)
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
noteContent,
@@ -484,10 +487,6 @@ export default class MarkdownPreview extends React.Component {
eventEmitter.on('export:save-md', this.saveAsMdHandler)
eventEmitter.on('export:save-html', this.saveAsHtmlHandler)
eventEmitter.on('print', this.printHandler)
eventEmitter.on('config-renew', () => {
this.markdown.updateConfig()
this.rewriteIframe()
})
}
componentWillUnmount () {
@@ -531,7 +530,8 @@ export default class MarkdownPreview extends React.Component {
prevProps.smartQuotes !== this.props.smartQuotes ||
prevProps.sanitize !== this.props.sanitize ||
prevProps.smartArrows !== this.props.smartArrows ||
prevProps.breaks !== this.props.breaks
prevProps.breaks !== this.props.breaks ||
prevProps.lineThroughCheckbox !== this.props.lineThroughCheckbox
) {
this.initMarkdown()
this.rewriteIframe()
@@ -864,6 +864,15 @@ export default class MarkdownPreview extends React.Component {
return
}
const regexIsLine = /^:line:[0-9]/
if (regexIsLine.test(linkHash)) {
const numberPattern = /\d+/g
const lineNumber = parseInt(linkHash.match(numberPattern)[0])
eventEmitter.emit('line:jump', lineNumber)
return
}
// this will match the old link format storage.key-note.key
// e.g.
// 877f99c3268608328037-1c211eb7dcb463de6490

View File

@@ -20,12 +20,18 @@ class MarkdownSplitEditor extends React.Component {
}
}
setValue (value) {
this.refs.code.setValue(value)
}
handleOnChange () {
this.value = this.refs.code.value
this.props.onChange()
}
handleScroll (e) {
if (!this.props.config.preview.scrollSync) return
const previewDoc = _.get(this, 'refs.preview.refs.root.contentWindow.document')
const codeDoc = _.get(this, 'refs.code.editor.doc')
let srcTop, srcHeight, targetTop, targetHeight
@@ -192,6 +198,7 @@ class MarkdownSplitEditor extends React.Component {
noteKey={noteKey}
customCSS={config.preview.customCSS}
allowCustomCSS={config.preview.allowCustomCSS}
lineThroughCheckbox={config.preview.lineThroughCheckbox}
/>
</div>
)

View File

@@ -24,16 +24,19 @@ const TagElement = ({ tagName }) => (
/**
* @description Tag element list component.
* @param {Array|null} tags
* @param {boolean} showTagsAlphabetically
* @return {React.Component}
*/
const TagElementList = tags => {
const TagElementList = (tags, showTagsAlphabetically) => {
if (!isArray(tags)) {
return []
}
const tagElements = tags.map(tag => TagElement({ tagName: tag }))
return tagElements
if (showTagsAlphabetically) {
return _.sortBy(tags).map(tag => TagElement({ tagName: tag }))
} else {
return tags.map(tag => TagElement({ tagName: tag }))
}
}
/**
@@ -55,7 +58,8 @@ const NoteItem = ({
pathname,
storageName,
folderName,
viewType
viewType,
showTagsAlphabetically
}) => (
<div
styleName={isActive ? 'item--active' : 'item'}
@@ -93,7 +97,7 @@ const NoteItem = ({
<div styleName='item-bottom'>
<div styleName='item-bottom-tagList'>
{note.tags.length > 0
? TagElementList(note.tags)
? TagElementList(note.tags, showTagsAlphabetically)
: <span
style={{ fontStyle: 'italic', opacity: 0.5 }}
styleName='item-bottom-tagList-empty'

View File

@@ -7,18 +7,18 @@ import styles from './StorageList.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {Array} storgaeList
* @param {Array} storageList
*/
const StorageList = ({storageList, isFolded}) => (
<div styleName={isFolded ? 'storageList-folded' : 'storageList'}>
{storageList.length > 0 ? storageList : (
<div styleName='storgaeList-empty'>No storage mount.</div>
<div styleName='storageList-empty'>No storage mount.</div>
)}
</div>
)
StorageList.propTypes = {
storgaeList: PropTypes.arrayOf(PropTypes.element).isRequired
storageList: PropTypes.arrayOf(PropTypes.element).isRequired
}
export default CSSModules(StorageList, styles)

View File

@@ -14,8 +14,8 @@ import CSSModules from 'browser/lib/CSSModules'
* @param {bool} isRelated
*/
const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, isActive, isRelated, count}) => (
<div styleName='tagList-itemContainer'>
const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, handleContextMenu, isActive, isRelated, count}) => (
<div styleName='tagList-itemContainer' onContextMenu={e => handleContextMenu(e, name)}>
{isRelated
? <button styleName={isActive ? 'tagList-itemNarrow-active' : 'tagList-itemNarrow'} onClick={() => handleClickNarrowToTag(name)}>
<i className={isActive ? 'fa fa-minus-circle' : 'fa fa-plus-circle'} />
@@ -25,7 +25,7 @@ const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, isAc
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
<span styleName='tagList-item-name'>
{`# ${name}`}
<span styleName='tagList-item-count'>{count}</span>
<span styleName='tagList-item-count'>{count !== 0 ? count : ''}</span>
</span>
</button>
</div>

View File

@@ -12,7 +12,7 @@ import styles from './TodoListPercentage.styl'
*/
const TodoListPercentage = ({
percentageOfTodo
percentageOfTodo, onClearCheckboxClick
}) => (
<div styleName='percentageBar' style={{display: isNaN(percentageOfTodo) ? 'none' : ''}}>
<div styleName='progressBar' style={{width: `${percentageOfTodo}%`}}>
@@ -20,11 +20,15 @@ const TodoListPercentage = ({
<p styleName='percentageText'>{percentageOfTodo}%</p>
</div>
</div>
<div styleName='todoClear'>
<p styleName='todoClearText' onClick={(e) => onClearCheckboxClick(e)}>clear</p>
</div>
</div>
)
TodoListPercentage.propTypes = {
percentageOfTodo: PropTypes.number.isRequired
percentageOfTodo: PropTypes.number.isRequired,
onClearCheckboxClick: PropTypes.func.isRequired
}
export default CSSModules(TodoListPercentage, styles)

View File

@@ -1,4 +1,5 @@
.percentageBar
display: flex
position absolute
top 72px
right 0px
@@ -30,6 +31,20 @@
color #f4f4f4
font-weight 600
.todoClear
display flex
justify-content: flex-end
position absolute
z-index 120
width 100%
height 100%
padding 2px 10px
.todoClearText
color #f4f4f4
cursor pointer
font-weight 500
body[data-theme="dark"]
.percentageBar
background-color #444444
@@ -39,6 +54,9 @@ body[data-theme="dark"]
.percentageText
color $ui-dark-text-color
.todoClearText
color $ui-dark-text-color
body[data-theme="solarized-dark"]
.percentageBar
@@ -50,6 +68,9 @@ body[data-theme="solarized-dark"]
.percentageText
color #fdf6e3
.todoClearText
color #fdf6e3
body[data-theme="monokai"]
.percentageBar
background-color: $ui-monokai-borderColor
@@ -69,3 +90,6 @@ body[data-theme="dracula"]
.percentageText
color $ui-dracula-text-color
.percentageText
color $ui-dracula-text-color