1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 09:46:22 +00:00

Merge branch 'master' into feature-editor-line-lines

This commit is contained in:
David Pavlík
2017-12-23 23:06:26 +01:00
committed by GitHub
222 changed files with 6346 additions and 2127 deletions

View File

@@ -1,4 +1,5 @@
import React, { PropTypes } from 'react'
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SnippetNoteDetail.styl'
import CodeEditor from 'browser/components/CodeEditor'
@@ -18,6 +19,7 @@ import _ from 'lodash'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import TrashButton from './TrashButton'
import PermanentDeleteButton from './PermanentDeleteButton'
import InfoButton from './InfoButton'
import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed'
@@ -60,7 +62,7 @@ class SnippetNoteDetail extends React.Component {
componentWillReceiveProps (nextProps) {
if (nextProps.note.key !== this.props.note.key && !this.isMovingNote) {
if (this.saveQueue != null) this.saveNow()
let nextNote = Object.assign({
const nextNote = Object.assign({
description: ''
}, nextProps.note, {
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
@@ -69,7 +71,7 @@ class SnippetNoteDetail extends React.Component {
snippetIndex: 0,
note: nextNote
}, () => {
let { snippets } = this.state.note
const { snippets } = this.state.note
snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload()
})
@@ -83,7 +85,7 @@ class SnippetNoteDetail extends React.Component {
}
handleChange (e) {
let { note } = this.state
const { note } = this.state
if (this.refs.tags) note.tags = this.refs.tags.value
note.description = this.refs.description.value
@@ -105,7 +107,7 @@ class SnippetNoteDetail extends React.Component {
}
saveNow () {
let { note, dispatch } = this.props
const { note, dispatch } = this.props
clearTimeout(this.saveQueue)
this.saveQueue = null
@@ -121,11 +123,11 @@ class SnippetNoteDetail extends React.Component {
}
handleFolderChange (e) {
let { note } = this.state
let value = this.refs.folder.value
let splitted = value.split('-')
let newStorageKey = splitted.shift()
let newFolderKey = splitted.shift()
const { note } = this.state
const value = this.refs.folder.value
const splitted = value.split('-')
const newStorageKey = splitted.shift()
const newFolderKey = splitted.shift()
dataApi
.moveNote(note.storage, note.key, newStorageKey, newFolderKey)
@@ -134,7 +136,7 @@ class SnippetNoteDetail extends React.Component {
isMovingNote: true,
note: Object.assign({}, newNote)
}, () => {
let { dispatch, location } = this.props
const { dispatch, location } = this.props
dispatch({
type: 'MOVE_NOTE',
originNote: note,
@@ -154,7 +156,7 @@ class SnippetNoteDetail extends React.Component {
}
handleStarButtonClick (e) {
let { note } = this.state
const { note } = this.state
if (!note.isStarred) AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_STAR')
note.isStarred = !note.isStarred
@@ -171,22 +173,22 @@ class SnippetNoteDetail extends React.Component {
}
handleTrashButtonClick (e) {
let { note } = this.state
const { note } = this.state
const { isTrashed } = note
if (isTrashed) {
let dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Confirm note deletion',
detail: 'This will permanently remove this note.',
buttons: ['Confirm', 'Cancel']
})
if (dialogueButtonIndex === 1) return
let { note, dispatch } = this.props
const { note, dispatch } = this.props
dataApi
.deleteNote(note.storage, note.key)
.then((data) => {
let dispatchHandler = () => {
const dispatchHandler = () => {
dispatch({
type: 'DELETE_NOTE',
storageKey: data.storageKey,
@@ -208,7 +210,7 @@ class SnippetNoteDetail extends React.Component {
}
handleUndoButtonClick (e) {
let { note } = this.state
const { note } = this.state
note.isTrashed = false
@@ -234,10 +236,31 @@ class SnippetNoteDetail extends React.Component {
})
}
handleTabDragStart (e, index) {
e.dataTransfer.setData('text/plain', index)
}
handleTabDrop (e, index) {
const oldIndex = parseInt(e.dataTransfer.getData('text'))
const snippets = this.state.note.snippets.slice()
const draggedSnippet = snippets[oldIndex]
snippets[oldIndex] = snippets[index]
snippets[index] = draggedSnippet
const snippetIndex = index
const note = Object.assign({}, this.state.note, {snippets})
this.setState({ note, snippetIndex }, () => {
this.save()
this.refs['code-' + index].reload()
this.refs['code-' + oldIndex].reload()
})
}
handleTabDeleteButtonClick (e, index) {
if (this.state.note.snippets.length > 1) {
if (this.state.note.snippets[index].content.trim().length > 0) {
let dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
const dialogIndex = dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Delete a snippet',
detail: 'This work cannot be undone.',
@@ -266,11 +289,16 @@ class SnippetNoteDetail extends React.Component {
}
renameSnippetByIndex (index, name) {
let snippets = this.state.note.snippets.slice()
const snippets = this.state.note.snippets.slice()
snippets[index].name = name
let syntax = CodeMirror.findModeByFileName(name.trim())
let mode = syntax != null ? syntax.name : null
if (mode != null) snippets[index].mode = mode
const syntax = CodeMirror.findModeByFileName(name.trim())
const mode = syntax != null ? syntax.name : null
if (mode != null) {
snippets[index].mode = mode
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('SNIPPET_LANG', {
name: mode
})
}
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({
@@ -282,7 +310,7 @@ class SnippetNoteDetail extends React.Component {
handleModeOptionClick (index, name) {
return (e) => {
let snippets = this.state.note.snippets.slice()
const snippets = this.state.note.snippets.slice()
snippets[index].mode = name
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
@@ -291,12 +319,16 @@ class SnippetNoteDetail extends React.Component {
}, () => {
this.save()
})
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('SELECT_LANG', {
name
})
}
}
handleCodeChange (index) {
return (e) => {
let snippets = this.state.note.snippets.slice()
const snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value
this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({
@@ -323,7 +355,7 @@ class SnippetNoteDetail extends React.Component {
break
case 76:
{
let isSuper = global.process.platform === 'darwin'
const isSuper = global.process.platform === 'darwin'
? e.metaKey
: e.ctrlKey
if (isSuper) {
@@ -334,7 +366,7 @@ class SnippetNoteDetail extends React.Component {
break
case 84:
{
let isSuper = global.process.platform === 'darwin'
const isSuper = global.process.platform === 'darwin'
? e.metaKey
: e.ctrlKey
if (isSuper) {
@@ -347,7 +379,7 @@ class SnippetNoteDetail extends React.Component {
}
handleModeButtonClick (e, index) {
let menu = new Menu()
const menu = new Menu()
CodeMirror.modeInfo.forEach((mode) => {
menu.append(new MenuItem({
label: mode.name,
@@ -388,8 +420,8 @@ class SnippetNoteDetail extends React.Component {
}
handleIndentSizeItemClick (e, indentSize) {
let { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, {
const { config, dispatch } = this.props
const editor = Object.assign({}, config.editor, {
indentSize
})
ConfigManager.set({
@@ -404,8 +436,8 @@ class SnippetNoteDetail extends React.Component {
}
handleIndentTypeItemClick (e, indentType) {
let { config, dispatch } = this.props
let editor = Object.assign({}, config.editor, {
const { config, dispatch } = this.props
const editor = Object.assign({}, config.editor, {
indentType
})
ConfigManager.set({
@@ -424,14 +456,14 @@ class SnippetNoteDetail extends React.Component {
}
addSnippet () {
let { note } = this.state
const { note } = this.state
note.snippets = note.snippets.concat([{
name: '',
mode: 'Plain Text',
content: ''
}])
let snippetIndex = note.snippets.length - 1
const snippetIndex = note.snippets.length - 1
this.setState({
note,
@@ -477,19 +509,19 @@ class SnippetNoteDetail extends React.Component {
}
render () {
let { data, config, location } = this.props
let { note } = this.state
const { data, config, location } = this.props
const { note } = this.state
let storageKey = note.storage
let folderKey = note.folder
const storageKey = note.storage
const folderKey = note.folder
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
let tabList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index
const tabList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
return <SnippetTab
key={index}
@@ -500,11 +532,13 @@ class SnippetNoteDetail extends React.Component {
onDelete={(e) => this.handleTabDeleteButtonClick(e, index)}
onRename={(name) => this.renameSnippetByIndex(index, name)}
isDeletable={note.snippets.length > 1}
onDragStart={(e) => this.handleTabDragStart(e, index)}
onDrop={(e) => this.handleTabDrop(e, index)}
/>
})
let viewList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index
const viewList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(pass(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
@@ -532,6 +566,7 @@ class SnippetNoteDetail extends React.Component {
indentSize={editorIndentSize}
displayLineNumbers={config.editor.displayLineNumbers}
keyMap={config.editor.keyMap}
scrollPastEnd={config.editor.scrollPastEnd}
onChange={(e) => this.handleCodeChange(index)(e)}
ref={'code-' + index}
/>
@@ -539,7 +574,7 @@ class SnippetNoteDetail extends React.Component {
</div>
})
let options = []
const options = []
data.storageMap.forEach((storage, index) => {
storage.folders.forEach((folder) => {
options.push({
@@ -548,7 +583,7 @@ class SnippetNoteDetail extends React.Component {
})
})
})
let currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
const currentOption = options.filter((option) => option.storage.key === storageKey && option.folder.key === folderKey)[0]
const trashTopBar = <div styleName='info'>
<div styleName='info-left'>
@@ -558,7 +593,7 @@ class SnippetNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<PermanentDeleteButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
@@ -575,10 +610,6 @@ class SnippetNoteDetail extends React.Component {
const detailTopBar = <div styleName='info'>
<div styleName='info-left'>
<StarButton styleName='info-left-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
@@ -595,15 +626,21 @@ class SnippetNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)}
>
<i className='fa fa-expand' styleName='fullScreen-button' />
</button>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<StarButton
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<button styleName='control-fullScreenButton' title='Fullscreen'
onMouseDown={(e) => this.handleFullScreenButton(e)}>
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
</button>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}