mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 09:46:22 +00:00
Merged Master into feature branch and fixed conflicts
This commit is contained in:
@@ -11,7 +11,7 @@ const FullscreenButton = ({
|
||||
const hotkey = (OSX ? i18n.__('Command(⌘)') : i18n.__('Ctrl(^)')) + '+B'
|
||||
return (
|
||||
<button styleName='control-fullScreenButton' title={i18n.__('Fullscreen')} onMouseDown={(e) => onClick(e)}>
|
||||
<img styleName='iconInfo' src='../resources/icon/icon-full.svg' />
|
||||
<img src='../resources/icon/icon-full.svg' />
|
||||
<span lang={i18n.locale} styleName='tooltip'>{i18n.__('Fullscreen')}({hotkey})</span>
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ class InfoPanel extends React.Component {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input styleName='infoPanel-noteLink' ref='noteLink' value={noteLink} onClick={(e) => { e.target.select() }} />
|
||||
<input styleName='infoPanel-noteLink' ref='noteLink' defaultValue={noteLink} onClick={(e) => { e.target.select() }} />
|
||||
<button onClick={() => this.copyNoteLink()} styleName='infoPanel-copyButton'>
|
||||
<i className='fa fa-clipboard' />
|
||||
</button>
|
||||
|
||||
@@ -67,9 +67,6 @@ class MarkdownNoteDetail extends React.Component {
|
||||
})
|
||||
ee.on('hotkey:deletenote', this.handleDeleteNote.bind(this))
|
||||
ee.on('code:generate-toc', this.generateToc)
|
||||
|
||||
// Focus content if using blur or double click
|
||||
if (this.state.switchPreview === 'BLUR' || this.state.switchPreview === 'DBL_CLICK') this.focus()
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
@@ -84,6 +81,20 @@ class MarkdownNoteDetail extends React.Component {
|
||||
if (this.refs.tags) this.refs.tags.reset()
|
||||
})
|
||||
}
|
||||
|
||||
// Focus content if using blur or double click
|
||||
// --> Moved here from componentDidMount so a re-render during search won't set focus to the editor
|
||||
const {switchPreview} = nextProps.config.editor
|
||||
|
||||
if (this.state.switchPreview !== switchPreview) {
|
||||
this.setState({
|
||||
switchPreview
|
||||
})
|
||||
if (switchPreview === 'BLUR' || switchPreview === 'DBL_CLICK') {
|
||||
console.log('setting focus', switchPreview)
|
||||
this.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
@@ -300,7 +311,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
getToggleLockButton () {
|
||||
return this.state.isLocked ? '../resources/icon/icon-previewoff-on.svg' : '../resources/icon/icon-previewoff-off.svg'
|
||||
return this.state.isLocked ? '../resources/icon/icon-lock.svg' : '../resources/icon/icon-unlock.svg'
|
||||
}
|
||||
|
||||
handleDeleteKeyDown (e) {
|
||||
@@ -439,7 +450,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
const detailTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<div styleName='info-left-top'>
|
||||
<div>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
@@ -473,7 +484,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
onFocus={(e) => this.handleFocus(e)}
|
||||
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
|
||||
>
|
||||
<img styleName='iconInfo' src={imgSrc} />
|
||||
<img src={imgSrc} />
|
||||
{this.state.isLocked ? <span styleName='tooltip'>Unlock</span> : <span styleName='tooltip'>Lock</span>}
|
||||
</button>
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const PermanentDeleteButton = ({
|
||||
<button styleName='control-trashButton--in-trash'
|
||||
onClick={(e) => onClick(e)}
|
||||
>
|
||||
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
|
||||
<img src='../resources/icon/icon-trash.svg' />
|
||||
<span styleName='tooltip'>{i18n.__('Permanent Delete')}</span>
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -518,6 +518,19 @@ class SnippetNoteDetail extends React.Component {
|
||||
])
|
||||
}
|
||||
|
||||
handleWrapLineButtonClick (e) {
|
||||
context.popup([
|
||||
{
|
||||
label: 'on',
|
||||
click: (e) => this.handleWrapLineItemClick(e, true)
|
||||
},
|
||||
{
|
||||
label: 'off',
|
||||
click: (e) => this.handleWrapLineItemClick(e, false)
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
handleIndentSizeItemClick (e, indentSize) {
|
||||
const { config, dispatch } = this.props
|
||||
const editor = Object.assign({}, config.editor, {
|
||||
@@ -550,6 +563,22 @@ class SnippetNoteDetail extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleWrapLineItemClick (e, lineWrapping) {
|
||||
const { config, dispatch } = this.props
|
||||
const editor = Object.assign({}, config.editor, {
|
||||
lineWrapping
|
||||
})
|
||||
ConfigManager.set({
|
||||
editor
|
||||
})
|
||||
dispatch({
|
||||
type: 'SET_CONFIG',
|
||||
config: {
|
||||
editor
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
focus () {
|
||||
this.refs.description.focus()
|
||||
}
|
||||
@@ -720,6 +749,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
mode={snippet.mode || (autoDetect ? null : config.editor.snippetDefaultLanguage)}
|
||||
value={snippet.content}
|
||||
linesHighlighted={snippet.linesHighlighted}
|
||||
lineWrapping={config.editor.lineWrapping}
|
||||
theme={config.editor.theme}
|
||||
fontFamily={config.editor.fontFamily}
|
||||
fontSize={editorFontSize}
|
||||
@@ -778,7 +808,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
const detailTopBar = <div styleName='info'>
|
||||
<div styleName='info-left'>
|
||||
<div styleName='info-left-top'>
|
||||
<div>
|
||||
<FolderSelect styleName='info-left-top-folderSelect'
|
||||
value={this.state.note.storage + '-' + this.state.note.folder}
|
||||
ref='folder'
|
||||
@@ -899,6 +929,12 @@ class SnippetNoteDetail extends React.Component {
|
||||
size: {config.editor.indentSize}
|
||||
<i className='fa fa-caret-down' />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => this.handleWrapLineButtonClick(e)}
|
||||
>
|
||||
Wrap Line: {config.editor.lineWrapping ? 'on' : 'off'}
|
||||
<i className='fa fa-caret-down' />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<StatusBar
|
||||
|
||||
@@ -8,11 +8,11 @@ const ToggleModeButton = ({
|
||||
onClick, editorType
|
||||
}) => (
|
||||
<div styleName='control-toggleModeButton'>
|
||||
<div styleName={editorType === 'SPLIT' ? 'active' : 'non-active'} onClick={() => onClick('SPLIT')}>
|
||||
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-markdown-off-active.svg' : ''} />
|
||||
<div styleName={editorType === 'SPLIT' ? 'active' : undefined} onClick={() => onClick('SPLIT')}>
|
||||
<img src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-markdown-off-active.svg' : ''} />
|
||||
</div>
|
||||
<div styleName={editorType === 'EDITOR_PREVIEW' ? 'active' : 'non-active'} onClick={() => onClick('EDITOR_PREVIEW')}>
|
||||
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '' : '../resources/icon/icon-mode-split-on-active.svg'} />
|
||||
<div styleName={editorType === 'EDITOR_PREVIEW' ? 'active' : undefined} onClick={() => onClick('EDITOR_PREVIEW')}>
|
||||
<img src={editorType === 'EDITOR_PREVIEW' ? '' : '../resources/icon/icon-mode-split-on-active.svg'} />
|
||||
</div>
|
||||
<span lang={i18n.locale} styleName='tooltip'>{i18n.__('Toggle Mode')}</span>
|
||||
</div>
|
||||
@@ -20,7 +20,7 @@ const ToggleModeButton = ({
|
||||
|
||||
ToggleModeButton.propTypes = {
|
||||
onClick: PropTypes.func.isRequired,
|
||||
editorType: PropTypes.string.Required
|
||||
editorType: PropTypes.string.isRequired
|
||||
}
|
||||
|
||||
export default CSSModules(ToggleModeButton, styles)
|
||||
|
||||
@@ -10,7 +10,7 @@ const TrashButton = ({
|
||||
<button styleName='control-trashButton'
|
||||
onClick={(e) => onClick(e)}
|
||||
>
|
||||
<img styleName='iconInfo' src='../resources/icon/icon-trash.svg' />
|
||||
<img src='../resources/icon/icon-trash.svg' />
|
||||
<span lang={i18n.locale} styleName='tooltip'>{i18n.__('Trash')}</span>
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/* eslint-disable no-undef */
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
// eslint-disable-next-line global-require
|
||||
module.exports = require('./index.prod').default
|
||||
} else {
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
// eslint-disable-next-line global-require
|
||||
module.exports = require('./index.dev').default
|
||||
} else {
|
||||
// eslint-disable-next-line global-require
|
||||
module.exports = require('./index.prod').default
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class NewNoteButton extends React.Component {
|
||||
<div styleName='control'>
|
||||
<button styleName='control-newNoteButton'
|
||||
onClick={this.handleNewNoteButtonClick}>
|
||||
<img styleName='iconTag' src='../resources/icon/icon-newnote.svg' />
|
||||
<img src='../resources/icon/icon-newnote.svg' />
|
||||
<span styleName='control-newNoteButton-tooltip'>
|
||||
{i18n.__('Make a note')} {OSX ? '⌘' : i18n.__('Ctrl')} + N
|
||||
</span>
|
||||
|
||||
@@ -1138,7 +1138,7 @@ class NoteList extends React.Component {
|
||||
}
|
||||
onClick={(e) => this.handleListStyleButtonClick(e, 'DEFAULT')}
|
||||
>
|
||||
<img styleName='iconTag' src='../resources/icon/icon-column.svg' />
|
||||
<img src='../resources/icon/icon-column.svg' />
|
||||
</button>
|
||||
<button title={i18n.__('Compressed View')} styleName={config.listStyle === 'SMALL'
|
||||
? 'control-button--active'
|
||||
@@ -1146,7 +1146,7 @@ class NoteList extends React.Component {
|
||||
}
|
||||
onClick={(e) => this.handleListStyleButtonClick(e, 'SMALL')}
|
||||
>
|
||||
<img styleName='iconTag' src='../resources/icon/icon-column-list.svg' />
|
||||
<img src='../resources/icon/icon-column-list.svg' />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ const PreferenceButton = ({
|
||||
onClick
|
||||
}) => (
|
||||
<button styleName='top-menu-preference' onClick={(e) => onClick(e)}>
|
||||
<img styleName='iconTag' src='../resources/icon/icon-setting.svg' />
|
||||
<img src='../resources/icon/icon-setting.svg' />
|
||||
<span styleName='tooltip'>{i18n.__('Preferences')}</span>
|
||||
</button>
|
||||
)
|
||||
|
||||
@@ -362,14 +362,14 @@ class StorageItem extends React.Component {
|
||||
<button styleName='header-addFolderButton'
|
||||
onClick={(e) => this.handleAddFolderButtonClick(e)}
|
||||
>
|
||||
<img styleName='iconTag' src='../resources/icon/icon-plus.svg' />
|
||||
<img src='../resources/icon/icon-plus.svg' />
|
||||
</button>
|
||||
}
|
||||
|
||||
<button styleName='header-info'
|
||||
onClick={(e) => this.handleHeaderInfoClick(e)}
|
||||
>
|
||||
<span styleName='header-info-name'>
|
||||
<span>
|
||||
{isFolded ? _.truncate(storage.name, {length: 1, omission: ''}) : storage.name}
|
||||
</span>
|
||||
{isFolded &&
|
||||
@@ -380,7 +380,7 @@ class StorageItem extends React.Component {
|
||||
</button>
|
||||
</div>
|
||||
{this.state.isOpen &&
|
||||
<div styleName='folderList' >
|
||||
<div>
|
||||
{folderList}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ class SideNav extends React.Component {
|
||||
|
||||
const style = {}
|
||||
if (!isFolded) style.width = this.props.width
|
||||
const isTagActive = location.pathname.match(/tag/)
|
||||
const isTagActive = /tag/.test(location.pathname)
|
||||
return (
|
||||
<div className='SideNav'
|
||||
styleName={isFolded ? 'root--folded' : 'root'}
|
||||
|
||||
@@ -7,8 +7,8 @@ import ee from 'browser/main/lib/eventEmitter'
|
||||
import NewNoteButton from 'browser/main/NewNoteButton'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import debounce from 'lodash/debounce'
|
||||
import CInput from 'react-composition-input'
|
||||
import { push } from 'connected-react-router'
|
||||
import queryString from 'query-string'
|
||||
|
||||
class TopBar extends React.Component {
|
||||
constructor (props) {
|
||||
@@ -17,21 +17,29 @@ class TopBar extends React.Component {
|
||||
this.state = {
|
||||
search: '',
|
||||
searchOptions: [],
|
||||
isSearching: false,
|
||||
isAlphabet: false,
|
||||
isIME: false,
|
||||
isConfirmTranslation: false
|
||||
isSearching: false
|
||||
}
|
||||
|
||||
const { dispatch } = this.props
|
||||
|
||||
this.focusSearchHandler = () => {
|
||||
this.handleOnSearchFocus()
|
||||
}
|
||||
|
||||
this.codeInitHandler = this.handleCodeInit.bind(this)
|
||||
this.updateKeyword = this.updateKeyword.bind(this)
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this)
|
||||
this.handleSearchFocus = this.handleSearchFocus.bind(this)
|
||||
this.handleSearchBlur = this.handleSearchBlur.bind(this)
|
||||
this.handleSearchChange = this.handleSearchChange.bind(this)
|
||||
this.handleSearchClearButton = this.handleSearchClearButton.bind(this)
|
||||
|
||||
this.updateKeyword = debounce(this.updateKeyword, 1000 / 60, {
|
||||
this.debouncedUpdateKeyword = debounce((keyword) => {
|
||||
dispatch(push(`/searched/${encodeURIComponent(keyword)}`))
|
||||
this.setState({
|
||||
search: keyword
|
||||
})
|
||||
ee.emit('top:search', keyword)
|
||||
}, 1000 / 60, {
|
||||
maxWait: 1000 / 8
|
||||
})
|
||||
}
|
||||
@@ -63,14 +71,14 @@ class TopBar extends React.Component {
|
||||
this.refs.search.childNodes[0].blur
|
||||
dispatch(push('/searched'))
|
||||
e.preventDefault()
|
||||
this.debouncedUpdateKeyword('')
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
// reset states
|
||||
this.setState({
|
||||
isAlphabet: false,
|
||||
isIME: false
|
||||
})
|
||||
// Re-apply search field on ENTER key
|
||||
if (e.keyCode === 13) {
|
||||
this.debouncedUpdateKeyword(e.target.value)
|
||||
}
|
||||
|
||||
// Clear search on ESC
|
||||
if (e.keyCode === 27) {
|
||||
@@ -88,52 +96,11 @@ class TopBar extends React.Component {
|
||||
ee.emit('list:prior')
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
// When the key is an alphabet, del, enter or ctr
|
||||
if (e.keyCode <= 90 || e.keyCode >= 186 && e.keyCode <= 222) {
|
||||
this.setState({
|
||||
isAlphabet: true
|
||||
})
|
||||
// When the key is an IME input (Japanese, Chinese)
|
||||
} else if (e.keyCode === 229) {
|
||||
this.setState({
|
||||
isIME: true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleKeyUp (e) {
|
||||
// reset states
|
||||
this.setState({
|
||||
isConfirmTranslation: false
|
||||
})
|
||||
|
||||
// When the key is translation confirmation (Enter, Space)
|
||||
if (this.state.isIME && (e.keyCode === 32 || e.keyCode === 13)) {
|
||||
this.setState({
|
||||
isConfirmTranslation: true
|
||||
})
|
||||
const keyword = this.refs.searchInput.value
|
||||
this.updateKeyword(keyword)
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchChange (e) {
|
||||
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
|
||||
const keyword = this.refs.searchInput.value
|
||||
this.updateKeyword(keyword)
|
||||
} else {
|
||||
e.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
updateKeyword (keyword) {
|
||||
const { dispatch } = this.props
|
||||
dispatch(push(`/searched/${encodeURIComponent(keyword)}`))
|
||||
this.setState({
|
||||
search: keyword
|
||||
})
|
||||
ee.emit('top:search', keyword)
|
||||
const keyword = e.target.value
|
||||
this.debouncedUpdateKeyword(keyword)
|
||||
}
|
||||
|
||||
handleSearchFocus (e) {
|
||||
@@ -141,6 +108,7 @@ class TopBar extends React.Component {
|
||||
isSearching: true
|
||||
})
|
||||
}
|
||||
|
||||
handleSearchBlur (e) {
|
||||
e.stopPropagation()
|
||||
|
||||
@@ -170,7 +138,7 @@ class TopBar extends React.Component {
|
||||
}
|
||||
|
||||
handleCodeInit () {
|
||||
ee.emit('top:search', this.refs.searchInput.value)
|
||||
ee.emit('top:search', this.refs.searchInput.value || '')
|
||||
}
|
||||
|
||||
render () {
|
||||
@@ -183,24 +151,23 @@ class TopBar extends React.Component {
|
||||
<div styleName='control'>
|
||||
<div styleName='control-search'>
|
||||
<div styleName='control-search-input'
|
||||
onFocus={(e) => this.handleSearchFocus(e)}
|
||||
onBlur={(e) => this.handleSearchBlur(e)}
|
||||
onFocus={this.handleSearchFocus}
|
||||
onBlur={this.handleSearchBlur}
|
||||
tabIndex='-1'
|
||||
ref='search'
|
||||
>
|
||||
<input
|
||||
<CInput
|
||||
ref='searchInput'
|
||||
value={this.state.search}
|
||||
onChange={(e) => this.handleSearchChange(e)}
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
onKeyUp={(e) => this.handleKeyUp(e)}
|
||||
onInputChange={this.handleSearchChange}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
placeholder={i18n.__('Search')}
|
||||
type='text'
|
||||
className='searchInput'
|
||||
/>
|
||||
{this.state.search !== '' &&
|
||||
<button styleName='control-search-input-clear'
|
||||
onClick={(e) => this.handleSearchClearButton(e)}
|
||||
onClick={this.handleSearchClearButton}
|
||||
>
|
||||
<i className='fa fa-fw fa-times' />
|
||||
<span styleName='control-search-input-clear-tooltip'>{i18n.__('Clear Search')}</span>
|
||||
|
||||
@@ -32,6 +32,8 @@ export const DEFAULT_CONFIG = {
|
||||
deleteNote: OSX ? 'Command + Shift + Backspace' : 'Ctrl + Shift + Backspace',
|
||||
pasteSmartly: OSX ? 'Command + Shift + V' : 'Ctrl + Shift + V',
|
||||
prettifyMarkdown: 'Shift + F',
|
||||
insertDate: OSX ? 'Command + /' : 'Ctrl + /',
|
||||
insertDateTime: OSX ? 'Command + Alt + /' : 'Ctrl + Shift + /',
|
||||
toggleMenuBar: 'Alt'
|
||||
},
|
||||
ui: {
|
||||
@@ -49,6 +51,7 @@ export const DEFAULT_CONFIG = {
|
||||
fontFamily: win ? 'Consolas' : 'Monaco',
|
||||
indentType: 'space',
|
||||
indentSize: '2',
|
||||
lineWrapping: true,
|
||||
enableRulers: false,
|
||||
rulers: [80, 120],
|
||||
displayLineNumbers: true,
|
||||
@@ -91,8 +94,10 @@ export const DEFAULT_CONFIG = {
|
||||
breaks: true,
|
||||
smartArrows: false,
|
||||
allowCustomCSS: false,
|
||||
customCSS: '',
|
||||
|
||||
customCSS: '/* Drop Your Custom CSS Code Here */',
|
||||
sanitize: 'STRICT', // 'STRICT', 'ALLOW_STYLES', 'NONE'
|
||||
mermaidHTMLLabel: false,
|
||||
lineThroughCheckbox: true
|
||||
},
|
||||
blog: {
|
||||
@@ -116,7 +121,6 @@ function validate (config) {
|
||||
}
|
||||
|
||||
function _save (config) {
|
||||
console.log(config)
|
||||
window.localStorage.setItem('config', JSON.stringify(config))
|
||||
}
|
||||
|
||||
@@ -149,7 +153,7 @@ function get () {
|
||||
const theme = consts.THEMES.find(theme => theme.name === config.editor.theme)
|
||||
|
||||
if (theme) {
|
||||
editorTheme.setAttribute('href', `../${theme.path}`)
|
||||
editorTheme.setAttribute('href', theme.path)
|
||||
} else {
|
||||
config.editor.theme = 'default'
|
||||
}
|
||||
@@ -160,7 +164,13 @@ function get () {
|
||||
|
||||
function set (updates) {
|
||||
const currentConfig = get()
|
||||
const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, updates)
|
||||
|
||||
const arrangedUpdates = updates
|
||||
if (updates.preview !== undefined && updates.preview.customCSS === '') {
|
||||
arrangedUpdates.preview.customCSS = DEFAULT_CONFIG.preview.customCSS
|
||||
}
|
||||
|
||||
const newConfig = Object.assign({}, DEFAULT_CONFIG, currentConfig, arrangedUpdates)
|
||||
if (!validate(newConfig)) throw new Error('INVALID CONFIG')
|
||||
_save(newConfig)
|
||||
|
||||
@@ -191,7 +201,7 @@ function set (updates) {
|
||||
const newTheme = consts.THEMES.find(theme => theme.name === newConfig.editor.theme)
|
||||
|
||||
if (newTheme) {
|
||||
editorTheme.setAttribute('href', `../${newTheme.path}`)
|
||||
editorTheme.setAttribute('href', newTheme.path)
|
||||
}
|
||||
|
||||
ipcRenderer.send('config-renew', {
|
||||
|
||||
@@ -241,6 +241,10 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
|
||||
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
|
||||
*/
|
||||
function fixLocalURLS (renderedHTML, storagePath) {
|
||||
const encodedWin32SeparatorRegex = /%5C/g
|
||||
const storageRegex = new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g')
|
||||
const storageUrl = 'file:///' + path.join(storagePath, DESTINATION_FOLDER).replace(/\\/g, '/')
|
||||
|
||||
/*
|
||||
A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`.
|
||||
|
||||
@@ -250,8 +254,7 @@ function fixLocalURLS (renderedHTML, storagePath) {
|
||||
- `(?:\\\/|%5C)` match the path seperator. `\\\/` for posix systems and `%5C` for windows.
|
||||
*/
|
||||
return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:(?:\\\/|%5C)[-.\\w]+)+', 'g'), function (match) {
|
||||
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
|
||||
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
|
||||
return match.replace(encodedWin32SeparatorRegex, '/').replace(storageRegex, storageUrl)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -617,8 +620,6 @@ function deleteAttachmentsNotPresentInNote (markdownContent, storageKey, noteKey
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
console.info('Attachment folder ("' + attachmentFolder + '") did not exist..')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
.control
|
||||
padding 25px 0px
|
||||
text-align center
|
||||
display: flex
|
||||
|
||||
.control-button
|
||||
width 240px
|
||||
|
||||
@@ -225,7 +225,7 @@ class FolderItem extends React.Component {
|
||||
<div styleName='folderItem-left'
|
||||
style={{borderColor: folder.color}}
|
||||
>
|
||||
<span styleName='folderItem-left-name'>{folder.name}</span>
|
||||
<span>{folder.name}</span>
|
||||
<span styleName='folderItem-left-key'>({folder.key})</span>
|
||||
</div>
|
||||
<div styleName='folderItem-right'>
|
||||
@@ -288,10 +288,10 @@ class Handle extends React.Component {
|
||||
|
||||
class SortableFolderItemComponent extends React.Component {
|
||||
render () {
|
||||
const StyledHandle = CSSModules(Handle, this.props.styles)
|
||||
const StyledHandle = CSSModules(Handle, styles)
|
||||
const DragHandle = SortableHandle(StyledHandle)
|
||||
|
||||
const StyledFolderItem = CSSModules(FolderItem, this.props.styles)
|
||||
const StyledFolderItem = CSSModules(FolderItem, styles)
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -22,7 +22,7 @@ class FolderList extends React.Component {
|
||||
})
|
||||
|
||||
return (
|
||||
<div styleName='folderList'>
|
||||
<div>
|
||||
{folderList.length > 0
|
||||
? folderList
|
||||
: <div styleName='folderList-empty'>{i18n.__('No Folders')}</div>
|
||||
|
||||
@@ -181,7 +181,26 @@ class HotkeyTab extends React.Component {
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
ref='prettifyMarkdown'
|
||||
value={config.hotkey.prettifyMarkdown}
|
||||
type='text'/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Insert Current Date')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
value={config.hotkey.insertDate}
|
||||
type='text'
|
||||
disabled='true'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Insert Current Date and Time')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
value={config.hotkey.insertDateTime}
|
||||
type='text'
|
||||
disabled='true'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -14,6 +14,7 @@ import { getLanguages } from 'browser/lib/Languages'
|
||||
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
const WIN = global.process.platform === 'win32'
|
||||
|
||||
const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
@@ -95,6 +96,7 @@ class UiTab extends React.Component {
|
||||
enableRulers: this.refs.enableEditorRulers.value === 'true',
|
||||
rulers: this.refs.editorRulers.value.replace(/[^0-9,]/g, '').split(','),
|
||||
displayLineNumbers: this.refs.editorDisplayLineNumbers.checked,
|
||||
lineWrapping: this.refs.editorLineWrapping.checked,
|
||||
switchPreview: this.refs.editorSwitchPreview.value,
|
||||
keyMap: this.refs.editorKeyMap.value,
|
||||
snippetDefaultLanguage: this.refs.editorSnippetDefaultLanguage.value,
|
||||
@@ -129,6 +131,7 @@ class UiTab extends React.Component {
|
||||
breaks: this.refs.previewBreaks.checked,
|
||||
smartArrows: this.refs.previewSmartArrows.checked,
|
||||
sanitize: this.refs.previewSanitize.value,
|
||||
mermaidHTMLLabel: this.refs.previewMermaidHTMLLabel.checked,
|
||||
allowCustomCSS: this.refs.previewAllowCustomCSS.checked,
|
||||
lineThroughCheckbox: this.refs.lineThroughCheckbox.checked,
|
||||
customCSS: this.customCSSCM.getCodeMirror().getValue()
|
||||
@@ -141,7 +144,7 @@ class UiTab extends React.Component {
|
||||
const theme = consts.THEMES.find(theme => theme.name === newCodemirrorTheme)
|
||||
|
||||
if (theme) {
|
||||
checkHighLight.setAttribute('href', `../${theme.path}`)
|
||||
checkHighLight.setAttribute('href', theme.path)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,6 +554,17 @@ class UiTab extends React.Component {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.editor.lineWrapping}
|
||||
ref='editorLineWrapping'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Wrap line in Snippet Note')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
@@ -806,6 +820,16 @@ class UiTab extends React.Component {
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input onChange={(e) => this.handleUIChange(e)}
|
||||
checked={this.state.config.preview.mermaidHTMLLabel}
|
||||
ref='previewMermaidHTMLLabel'
|
||||
type='checkbox'
|
||||
/>
|
||||
{i18n.__('Enable HTML label in mermaid flowcharts')}
|
||||
</label>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('LaTeX Inline Open Delimiter')}
|
||||
@@ -889,7 +913,6 @@ class UiTab extends React.Component {
|
||||
onChange={e => this.handleUIChange(e)}
|
||||
ref={e => (this.customCSSCM = e)}
|
||||
value={config.preview.customCSS}
|
||||
defaultValue={'/* Drop Your Custom CSS Code Here */\n'}
|
||||
options={{
|
||||
lineNumbers: true,
|
||||
mode: 'css',
|
||||
|
||||
@@ -147,7 +147,7 @@ class Preferences extends React.Component {
|
||||
key={tab.target}
|
||||
onClick={(e) => this.handleNavButtonClick(tab.target)(e)}
|
||||
>
|
||||
<span styleName='nav-button-label'>
|
||||
<span>
|
||||
{tab.label}
|
||||
</span>
|
||||
{isUiHotkeyTab ? this.haveToSaveNotif(tab[tab.label].type, tab[tab.label].message) : null}
|
||||
|
||||
@@ -476,7 +476,8 @@ const reducer = combineReducers({
|
||||
router: connectRouter(history)
|
||||
})
|
||||
|
||||
const store = createStore(reducer, undefined, compose(
|
||||
applyMiddleware(routerMiddleware(history)), DevTools.instrument()))
|
||||
const store = createStore(reducer, undefined, process.env.NODE_ENV === 'development'
|
||||
? compose(applyMiddleware(routerMiddleware(history)), DevTools.instrument())
|
||||
: applyMiddleware(routerMiddleware(history)))
|
||||
|
||||
export { store, history }
|
||||
|
||||
Reference in New Issue
Block a user