1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-14 10:16:26 +00:00

Compare commits

..

31 Commits

Author SHA1 Message Date
Rokt33r
0fe83a0583 fix anchor target 2016-01-25 10:28:46 +09:00
Rokt33r
ce74e69480 check href exists 2016-01-22 08:00:26 +09:00
Rokt33r
ddea2aeb22 fix verticla-align of img in anchor 2016-01-22 07:58:25 +09:00
Rokt33r
7bbe69cce9 Merge branch 'v0.5.4'
* v0.5.4:
  bump up version to v0.5.4
  emit ARTICLE_CREATE when new post clicked
  update h1 style of markdown
  fix go to line end
  clean old code
  fix sanitizing bug in Code block
  done but bugged

Conflicts:
	package.json
2016-01-22 03:01:13 +09:00
Rokt33r
e921e30d64 bump up version to v0.5.4 2016-01-22 02:59:35 +09:00
Rokt33r
cd4f9d8bb4 emit ARTICLE_CREATE when new post clicked 2016-01-22 02:58:06 +09:00
Rokt33r
a0553788b6 update h1 style of markdown 2016-01-22 02:55:02 +09:00
Rokt33r
1a183d78af fix go to line end 2016-01-21 08:29:09 +09:00
Rokt33r
cabcaa892c clean old code 2016-01-21 05:50:53 +09:00
Rokt33r
01c9d62a2b fix sanitizing bug in Code block 2016-01-21 05:50:40 +09:00
Rokt33r
ba76df863c bump up version 2016-01-19 20:13:17 +09:00
Rokt33r
81441a0895 done but bugged 2016-01-19 20:11:38 +09:00
Rokt33r
da0222f213 esc to show preview when rightclick to toggle set 2016-01-19 18:58:27 +09:00
Rokt33r
fb8a2eb2e0 show proper error when hotkey updated 2016-01-19 18:47:35 +09:00
Rokt33r
cde2e27e04 must override default config 2016-01-19 18:47:10 +09:00
Dick Choi
3758ea2cf4 bump up version 2016-01-18 01:02:05 +09:00
Rokt33r
e62fc11328 switch folder properly after moving an article to other folder 2016-01-17 08:43:01 +09:00
Dick Choi
3cbfae83c1 fix basefonts again 2016-01-17 07:27:38 +09:00
Dick Choi
57667654ef add Base fonts for windows 2016-01-17 00:19:20 +09:00
Rokt33r
eadd66fa91 decode entities to parse properly by katex 2016-01-16 19:40:03 +09:00
Rokt33r
75cd94a39a refactor MarkdownPreview & protocol must be defined in 'href' to open in browser 2016-01-16 05:28:27 +09:00
Rokt33r
7872bfe19d Merge branch 'markdown' into v0.5.2
* markdown:
  markdown strike bug fixed, no emoji shortcut, checkbox syntax added
2016-01-16 04:54:02 +09:00
Rokt33r
af008e69c2 modify default hotkey(toggle-main-window) 2016-01-16 04:53:49 +09:00
Rokt33r
a549abc20f Refactor event handlers in ArticleEditor 2016-01-16 04:53:06 +09:00
Rokt33r
116344737a right click to quick preview(edit on focus) 2016-01-16 04:24:09 +09:00
Rokt33r
93c03f4e88 add right click to switch edit/preview option to app settings 2016-01-16 02:40:31 +09:00
Rokt33r
445332c27c Find command of ace won't fire blur 2016-01-16 00:58:49 +09:00
Rokt33r
c42e1892d0 fix a little 2016-01-15 23:35:41 +09:00
Rokt33r
b6b526dd57 activity record bug fix 2016-01-15 15:41:37 +09:00
Rokt33r
3ef7f19ffc devtools will automatically removed in production 2016-01-15 15:41:18 +09:00
Rokt33r
9d0d851c2e markdown strike bug fixed, no emoji shortcut, checkbox syntax added 2016-01-13 13:10:46 +09:00
21 changed files with 364 additions and 160 deletions

View File

@@ -21,6 +21,65 @@ export default class CodeEditor extends React.Component {
this.configApplyHandler = (e, config) => this.handleConfigApply(e, config)
this.changeHandler = e => this.handleChange(e)
this.blurHandler = (e) => {
if (e.relatedTarget === null) {
return
}
let isFocusingToSearch = e.relatedTarget.className && e.relatedTarget.className.split(' ').some(clss => {
return clss === 'ace_search_field' || clss === 'ace_searchbtn' || clss === 'ace_replacebtn' || clss === 'ace_searchbtn_close' || clss === 'ace_text-input'
})
if (isFocusingToSearch) {
return
}
if (this.props.onBlur) this.props.onBlur(e)
}
this.killedBuffer = ''
this.execHandler = (e) => {
console.log(e.command.name)
switch (e.command.name) {
case 'gotolineend':
e.preventDefault()
let position = this.editor.getCursorPosition()
this.editor.navigateTo(position.row, this.editor.getSession().getLine(position.row).length)
break
case 'removetolineend':
e.preventDefault()
let range = this.editor.getSelectionRange()
let session = this.editor.getSession()
if (range.isEmpty()) {
range.setEnd(range.start.row, session.getLine(range.start.row).length)
this.killedBuffer = session.getTextRange(range)
if (this.killedBuffer.length > 0) {
console.log('remove to lineend')
session.remove(range)
} else {
if (session.getLength() === range.start.row) {
return
}
range.setStart(range.start.row, range.end.col)
range.setEnd(range.start.row + 1, 0)
this.killedBuffer = '\n'
session.remove(range)
}
} else {
this.killedBuffer = session.getTextRange(range)
session.remove(range)
}
}
}
this.afterExecHandler = (e) => {
switch (e.command.name) {
case 'find':
Array.prototype.forEach.call(ReactDOM.findDOMNode(this).querySelectorAll('.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close'), el => {
el.removeEventListener('blur', this.blurHandler)
el.addEventListener('blur', this.blurHandler)
})
break
}
}
this.state = {
fontSize: config['editor-font-size'],
@@ -49,6 +108,8 @@ export default class CodeEditor extends React.Component {
editor.setReadOnly(!!this.props.readOnly)
editor.setFontSize(this.state.fontSize)
editor.on('blur', this.blurHandler)
editor.commands.addCommand({
name: 'Emacs cursor up',
bindKey: {mac: 'Ctrl-P'},
@@ -58,18 +119,29 @@ export default class CodeEditor extends React.Component {
},
readOnly: true
})
editor.commands.addCommand({
name: 'Emacs cursor up',
bindKey: {mac: 'Ctrl-Y'},
exec: function (editor) {
editor.insert(this.killedBuffer)
}.bind(this),
readOnly: true
})
editor.commands.addCommand({
name: 'Focus title',
bindKey: {win: 'Esc', mac: 'Esc'},
exec: function (editor, e) {
remote.getCurrentWebContents().send('list-focus')
let currentWindow = remote.getCurrentWebContents()
if (config['switch-preview'] === 'rightclick') {
currentWindow.send('detail-preview')
}
currentWindow.send('list-focus')
},
readOnly: true
})
editor.on('blur', () => {
if (this.props.onBlur) this.props.onBlur()
})
editor.commands.on('exec', this.execHandler)
editor.commands.on('afterExec', this.afterExecHandler)
var session = editor.getSession()
let mode = _.findWhere(modes, {name: article.mode})
@@ -92,6 +164,9 @@ export default class CodeEditor extends React.Component {
componentWillUnmount () {
ipc.removeListener('config-apply', this.configApplyHandler)
this.editor.getSession().removeListener('change', this.changeHandler)
this.editor.removeListener('blur', this.blurHandler)
this.editor.commands.removeListener('exec', this.execHandler)
this.editor.commands.removeListener('afterExec', this.afterExecHandler)
}
componentDidUpdate (prevProps, prevState) {
@@ -166,8 +241,8 @@ CodeEditor.propTypes = {
key: PropTypes.string
}),
className: PropTypes.string,
onChange: PropTypes.func,
onBlur: PropTypes.func,
onChange: PropTypes.func,
readOnly: PropTypes.bool
}

View File

@@ -11,10 +11,12 @@ const ipc = electron.ipcRenderer
const katex = window.katex
const OSX = global.process.platform === 'darwin'
const sanitizeOpts = {
allowedTags: [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'img', 'span', 'cite', 'del', 'u', 'sub', 'sup' ],
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'img', 'span', 'cite', 'del', 'u', 'sub', 'sup', 's', 'input', 'label' ],
allowedClasses: {
'a': ['lineAnchor'],
'div': ['math'],
@@ -24,14 +26,20 @@ const sanitizeOpts = {
allowedAttributes: {
a: ['href', 'data-key'],
img: [ 'src' ],
label: ['for'],
input: ['checked', 'type'],
'*': ['id', 'name']
},
transformTags: {
'*': function (tagName, attribs) {
let href = attribs.href
if (tagName === 'input' && attribs.type !== 'checkbox') {
return false
}
if (_.isString(href) && href.match(/^#.+$/)) attribs.href = href.replace(/^#/, '#md-anchor-')
if (attribs.id) attribs.id = 'md-anchor-' + attribs.id
if (attribs.name) attribs.name = 'md-anchor-' + attribs.name
if (attribs.for) attribs.for = 'md-anchor-' + attribs.for
return {
tagName: tagName,
attribs: attribs
@@ -41,12 +49,15 @@ const sanitizeOpts = {
}
function handleAnchorClick (e) {
if (e.target.attributes.href && e.target.attributes.href.nodeValue.match(/#.+/)) {
if (this.attributes.href && this.attributes.href.nodeValue.match(/^#.+/)) {
return
}
e.preventDefault()
e.stopPropagation()
shell.openExternal(e.target.href)
let href = this.href
if (href && href.match(/^http:\/\/|https:\/\/|mailto:\/\//)) {
shell.openExternal(href)
}
}
function stopPropagation (e) {
@@ -57,7 +68,7 @@ function stopPropagation (e) {
function math2Katex (display) {
return function (el) {
try {
katex.render(el.innerHTML, el, {display: display})
katex.render(el.innerHTML.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&amp;/g, '&'), el, {display: display})
el.className = 'math-rendered'
} catch (e) {
el.innerHTML = e.message
@@ -111,22 +122,30 @@ export default class MarkdownPreview extends React.Component {
addListener () {
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
var inputs = ReactDOM.findDOMNode(this).querySelectorAll('input')
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener('click', handleAnchorClick)
anchors[i].addEventListener('mousedown', stopPropagation)
anchors[i].addEventListener('mouseup', stopPropagation)
}
Array.prototype.forEach.call(anchors, anchor => {
anchor.addEventListener('click', handleAnchorClick)
anchor.addEventListener('mousedown', stopPropagation)
anchor.addEventListener('mouseup', stopPropagation)
})
Array.prototype.forEach.call(inputs, input => {
input.addEventListener('click', stopPropagation)
})
}
removeListener () {
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
var inputs = ReactDOM.findDOMNode(this).querySelectorAll('input')
for (var i = 0; i < anchors.length; i++) {
anchors[i].removeEventListener('click', handleAnchorClick)
anchors[i].removeEventListener('mousedown', stopPropagation)
anchors[i].removeEventListener('mouseup', stopPropagation)
}
Array.prototype.forEach.call(anchors, anchor => {
anchor.removeEventListener('click', handleAnchorClick)
anchor.removeEventListener('mousedown', stopPropagation)
anchor.removeEventListener('mouseup', stopPropagation)
})
Array.prototype.forEach.call(inputs, input => {
input.removeEventListener('click', stopPropagation)
})
}
handleClick (e) {
@@ -185,7 +204,7 @@ export default class MarkdownPreview extends React.Component {
dangerouslySetInnerHTML={{__html: ' ' + content}}
style={{
fontSize: this.state.fontSize,
fontFamily: this.state.fontFamily.trim() + ', helvetica, arial, sans-serif'
fontFamily: this.state.fontFamily.trim() + (OSX ? '' : ', meiryo, \'Microsoft YaHei\'') + ', helvetica, arial, sans-serif'
}}
/>
)

View File

@@ -11,9 +11,17 @@ import _ from 'lodash'
import dataStore from 'browser/lib/dataStore'
const electron = require('electron')
const { clipboard, ipcRenderer } = electron
const { clipboard, ipcRenderer, remote } = electron
const path = require('path')
if (process.env.NODE_ENV !== 'production') {
window.addEventListener('keydown', function (e) {
if (e.keyCode === 73 && e.metaKey && e.altKey) {
remote.getCurrentWindow().toggleDevTools()
}
})
}
function hideFinder () {
ipcRenderer.send('hide-finder')
}

View File

@@ -41,7 +41,7 @@ Post all records(except today)
and remove all posted records
*/
export function postRecords (data) {
if (process.NODE_ENV !== 'production') {
if (process.env.NODE_ENV !== 'production') {
console.log('post failed - NOT PRODUCTION ')
return
}
@@ -108,7 +108,7 @@ export function emit (type, data = {}) {
}
// Count ARTICLE_CREATE and ARTICLE_UPDATE again by syntax
if ((type === 'ARTICLE_CREATE' || type === 'ARTICLE_UPDATE') && data.mode != null) {
if (type === 'ARTICLE_UPDATE' && data.mode != null) {
let recordKey = type + '_BY_SYNTAX'
if (todayRecord[recordKey] == null) todayRecord[recordKey] = {}

View File

@@ -5,6 +5,17 @@ const jetpack = require('fs-jetpack')
const userDataPath = remote.app.getPath('userData')
const configFile = 'config.json'
export default function fetchConfig () {
return Object.assign({}, JSON.parse(jetpack.cwd(userDataPath).read(configFile, 'utf-8')))
const defaultConfig = {
'editor-font-size': '14',
'editor-font-family': 'Monaco, Consolas',
'editor-indent-type': 'space',
'editor-indent-size': '4',
'preview-font-size': '14',
'preview-font-family': 'Lato',
'switch-preview': 'blur',
'disable-direct-write': false
}
export default function fetchConfig () {
return Object.assign({}, defaultConfig, JSON.parse(jetpack.cwd(userDataPath).read(configFile, 'utf-8')))
}

View File

@@ -14,10 +14,12 @@ var md = markdownit({
return hljs.highlight(lang, str).value
} catch (e) {}
}
return str
return str.replace(/\&/g, '&amp;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;').replace(/\"/g, '&quot;')
}
})
md.use(emoji)
md.use(emoji, {
shortcuts: {}
})
md.use(math, {
inlineRenderer: function (str) {
return `<span class='math'>${str}</span>`
@@ -26,6 +28,7 @@ md.use(math, {
return `<div class='math'>${str}</div>`
}
})
md.use(require('markdown-it-checkbox'))
let originalRenderToken = md.renderer.renderToken
md.renderer.renderToken = function renderToken (tokens, idx, options) {

View File

@@ -2,21 +2,43 @@ import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import CodeEditor from 'browser/components/CodeEditor'
import activityRecord from 'browser/lib/activityRecord'
import fetchConfig from 'browser/lib/fetchConfig'
const electron = require('electron')
const ipc = electron.ipcRenderer
export const PREVIEW_MODE = 'PREVIEW_MODE'
export const EDIT_MODE = 'EDIT_MODE'
let config = fetchConfig()
ipc.on('config-apply', function (e, newConfig) {
config = newConfig
})
export default class ArticleEditor extends React.Component {
constructor (props) {
super(props)
this.configApplyHandler = (e, config) => this.handleConfigApply(e, config)
this.isMouseDown = false
this.state = {
status: PREVIEW_MODE,
cursorPosition: null,
firstVisibleRow: null
firstVisibleRow: null,
switchPreview: config['switch-preview'],
isTemporary: false
}
}
componentDidMount () {
ipc.on('config-apply', this.configApplyHandler)
}
componentWillUnmount () {
ipc.removeListener('config-apply', this.configApplyHandler)
}
componentWillReceiveProps (nextProps) {
if (nextProps.article.key !== this.props.article.key) {
this.setState({
@@ -25,6 +47,12 @@ export default class ArticleEditor extends React.Component {
}
}
handleConfigApply (e, newConfig) {
this.setState({
switchPreview: newConfig['switch-preview']
})
}
resetCursorPosition () {
this.setState({
cursorPosition: null,
@@ -35,13 +63,15 @@ export default class ArticleEditor extends React.Component {
})
}
switchPreviewMode () {
switchPreviewMode (isTemporary = false) {
if (this.props.article.mode !== 'markdown') return true
let cursorPosition = this.refs.editor.getCursorPosition()
let firstVisibleRow = this.refs.editor.getFirstVisibleRow()
this.setState({
status: PREVIEW_MODE,
cursorPosition,
firstVisibleRow
firstVisibleRow,
isTemporary: isTemporary
}, function () {
let previewEl = ReactDOM.findDOMNode(this.refs.preview)
let anchors = previewEl.querySelectorAll('.lineAnchor')
@@ -55,43 +85,27 @@ export default class ArticleEditor extends React.Component {
})
}
switchEditMode () {
switchEditMode (isTemporary = false) {
this.setState({
status: EDIT_MODE
status: EDIT_MODE,
isTemporary: false
}, function () {
if (this.state.cursorPosition != null) {
this.refs.editor.moveCursorTo(this.state.cursorPosition.row, this.state.cursorPosition.column)
this.refs.editor.scrollToLine(this.state.firstVisibleRow)
}
this.refs.editor.editor.focus()
if (!isTemporary) activityRecord.emit('ARTICLE_UPDATE', this.props.article)
})
}
handlePreviewMouseDown (e) {
if (e.button === 2) return true
this.isDrag = false
this.isMouseDown = true
this.moveCount = 0
}
handlePreviewMouseMove () {
if (this.isMouseDown) {
this.moveCount++
if (this.moveCount > 5) {
this.isDrag = true
}
handleBlurCodeEditor (e) {
let isFocusingToThis = e.relatedTarget === ReactDOM.findDOMNode(this)
if (isFocusingToThis || this.state.switchPreview !== 'blur') {
return
}
}
handlePreviewMouseUp () {
this.isMouseDown = false
this.moveCount = 0
if (!this.isDrag) {
this.switchEditMode()
}
}
handleBlurCodeEditor () {
let { article } = this.props
if (article.mode === 'markdown') {
this.switchPreviewMode()
@@ -102,36 +116,97 @@ export default class ArticleEditor extends React.Component {
this.props.onChange(value)
}
handleRightClick (e) {
let { article } = this.props
if (this.state.switchPreview === 'rightclick' && article.mode === 'markdown') {
if (this.state.status === EDIT_MODE) this.switchPreviewMode()
else this.switchEditMode()
}
}
handleMouseUp (e) {
switch (this.state.switchPreview) {
case 'blur':
switch (e.button) {
case 0:
this.isMouseDown = false
this.moveCount = 0
if (!this.isDrag) {
this.switchEditMode()
}
break
case 2:
if (this.state.isTemporary) this.switchEditMode(true)
}
break
case 'rightclick':
}
}
handleMouseMove (e) {
if (this.state.switchPreview === 'blur' && this.isMouseDown) {
this.moveCount++
if (this.moveCount > 5) {
this.isDrag = true
}
}
}
handleMouseDowm (e) {
switch (this.state.switchPreview) {
case 'blur':
switch (e.button) {
case 0:
this.isDrag = false
this.isMouseDown = true
this.moveCount = 0
break
case 2:
if (this.state.status === EDIT_MODE && this.props.article.mode === 'markdown') {
this.switchPreviewMode(true)
}
}
break
case 'rightclick':
}
}
render () {
let { article } = this.props
let showPreview = article.mode === 'markdown' && this.state.status === PREVIEW_MODE
if (showPreview) {
return (
<div className='ArticleEditor'>
<MarkdownPreview
ref='preview'
onMouseUp={e => this.handlePreviewMouseUp(e)}
onMouseDown={e => this.handlePreviewMouseDown(e)}
onMouseMove={e => this.handlePreviewMouseMove(e)}
content={article.content}
/>
<div className='ArticleDetail-panel-content-tooltip'>Click to Edit</div>
</div>
)
}
return (
<div className='ArticleEditor'>
<CodeEditor
ref='editor'
onBlur={e => this.handleBlurCodeEditor(e)}
onChange={value => this.handleCodeEditorChange(value)}
article={article}
/>
<div
tabIndex='5'
onContextMenu={e => this.handleRightClick(e)}
onMouseUp={e => this.handleMouseUp(e)}
onMouseMove={e => this.handleMouseMove(e)}
onMouseDown={e => this.handleMouseDowm(e)}
className='ArticleEditor'
>
{showPreview
? <MarkdownPreview
ref='preview'
content={article.content}
/>
: <CodeEditor
ref='editor'
onBlur={e => this.handleBlurCodeEditor(e)}
onChange={value => this.handleCodeEditorChange(value)}
article={article}
/>
}
{article.mode === 'markdown'
? (
<div className='ArticleDetail-panel-content-tooltip'>Press ESC to watch Preview</div>
)
? <div className='ArticleDetail-panel-content-tooltip' children={
showPreview
? this.state.switchPreview === 'blur'
? 'Click to Edit'
: 'Right Click to Edit'
: this.state.switchPreview === 'blur'
? 'Press ESC to Watch Preview'
: 'Right Click to Watch Preview'
}
/>
: null
}
</div>
@@ -145,5 +220,6 @@ ArticleEditor.propTypes = {
key: PropTypes.string,
mode: PropTypes.string
}),
onChange: PropTypes.func
onChange: PropTypes.func,
parent: PropTypes.object
}

View File

@@ -4,10 +4,7 @@ import moment from 'moment'
import _ from 'lodash'
import {
switchFolder,
updateArticle,
// cacheArticle,
// saveArticle,
// uncacheArticle
updateArticle
} from '../../actions'
import linkState from 'browser/lib/linkState'
import TagSelect from 'browser/components/TagSelect'
@@ -19,22 +16,6 @@ import ArticleEditor from './ArticleEditor'
const electron = require('electron')
const ipc = electron.ipcRenderer
// const remote = electron.remote
// const { Menu, MenuItem } = remote
// const othersMenu = new Menu()
// othersMenu.append(new MenuItem({
// label: 'Delete Post',
// click: function () {
// remote.getCurrentWebContents().send('detail-delete')
// }
// }))
// othersMenu.append(new MenuItem({
// label: 'Discard Change',
// click: function (item) {
// remote.getCurrentWebContents().send('detail-uncache')
// }
// }))
const BRAND_COLOR = '#18AF90'
const OSX = global.process.platform === 'darwin'
@@ -80,10 +61,6 @@ export default class ArticleDetail extends React.Component {
constructor (props) {
super(props)
this.saveHandler = e => {
if (isModalOpen()) return true
this.handleSaveButtonClick()
}
this.deleteHandler = e => {
if (isModalOpen()) return true
this.handleDeleteButtonClick()
@@ -102,6 +79,10 @@ export default class ArticleDetail extends React.Component {
if (isModalOpen()) return true
if (this.refs.editor) this.refs.editor.switchEditMode()
}
this.previewHandler = e => {
if (isModalOpen()) return true
if (this.refs.editor) this.refs.editor.switchPreviewMode()
}
this.state = {
article: Object.assign({content: ''}, props.activeArticle),
@@ -115,21 +96,21 @@ export default class ArticleDetail extends React.Component {
e.stopPropagation()
}
// ipc.on('detail-save', this.saveHandler)
ipc.on('detail-delete', this.deleteHandler)
ipc.on('detail-uncache', this.uncacheHandler)
ipc.on('detail-title', this.titleHandler)
ipc.on('detail-edit', this.editHandler)
ipc.on('detail-preview', this.previewHandler)
}
componentWillUnmount () {
clearInterval(this.refreshTimer)
// ipc.removeListener('detail-save', this.saveHandler)
ipc.removeListener('detail-delete', this.deleteHandler)
ipc.removeListener('detail-uncache', this.uncacheHandler)
ipc.removeListener('detail-title', this.titleHandler)
ipc.removeListener('detail-edit', this.editHandler)
ipc.removeListener('detail-preview', this.previewHandler)
}
componentDidUpdate (prevProps, prevState) {
@@ -165,7 +146,7 @@ export default class ArticleDetail extends React.Component {
dispatch(updateArticle(article))
let targetFolderKey = this.state.article.FolderKey
let targetFolderKey = e.target.value
if (status.targetFolders.length > 0) {
let targetFolder = _.findWhere(folders, {key: targetFolderKey})
dispatch(switchFolder(targetFolder.name))

View File

@@ -4,6 +4,7 @@ import ExternalLink from 'browser/components/ExternalLink'
import { setSearchFilter, clearSearch, toggleTutorial, saveArticle, switchFolder } from '../actions'
import { isModalOpen } from 'browser/lib/modal'
import keygen from 'browser/lib/keygen'
import activityRecord from 'browser/lib/activityRecord'
const electron = require('electron')
const remote = electron.remote
@@ -167,6 +168,7 @@ export default class ArticleTopBar extends React.Component {
dispatch(saveArticle(newArticle.key, newArticle, true))
if (isFolderFilterApplied) dispatch(switchFolder(targetFolders[0].name))
remote.getCurrentWebContents().send('detail-title')
activityRecord.emit('ARTICLE_CREATE')
}
handleTutorialButtonClick (e) {

View File

@@ -10,6 +10,15 @@ import activityRecord from 'browser/lib/activityRecord'
const electron = require('electron')
const ipc = electron.ipcRenderer
const path = require('path')
const remote = electron.remote
if (process.env.NODE_ENV !== 'production') {
window.addEventListener('keydown', function (e) {
if (e.keyCode === 73 && e.metaKey && e.altKey) {
remote.getCurrentWindow().toggleDevTools()
}
})
}
activityRecord.init()
window.addEventListener('online', function () {

View File

@@ -138,9 +138,9 @@ export default class AppSettingTab extends React.Component {
<label>Editor Font Family</label>
<input valueLink={this.linkState('config.editor-font-family')} onKeyDown={e => this.handleConfigKeyDown(e)} type='text'/>
</div>
<div className='sectionSelect'>
<div className='sectionMultiSelect'>
<label>Editor Indent Style</label>
<div className='sectionSelect-input'>
<div className='sectionMultiSelect-input'>
type
<select valueLink={this.linkState('config.editor-indent-type')}>
<option value='space'>Space</option>
@@ -162,8 +162,15 @@ export default class AppSettingTab extends React.Component {
<label>Preview Font Family</label>
<input valueLink={this.linkState('config.preview-font-family')} onKeyDown={e => this.handleConfigKeyDown(e)} type='text'/>
</div>
<div className='sectionSelect'>
<label>Switching Preview</label>
<select valueLink={this.linkState('config.switch-preview')}>
<option value='blur'>When Editor Blurred</option>
<option value='rightclick'>When Right Clicking</option>
</select>
</div>
{
true// !OSX
global.process.platform === 'win32'
? (
<div className='sectionCheck'>
<label><input onClick={e => this.handleDisableDirectWriteClick(e)} checked={this.state.config['disable-direct-write']} disabled={OSX} type='checkbox'/>Disable Direct Write<span className='sectionCheck-warn'>It will be applied after restarting</span></label>

View File

@@ -60,7 +60,7 @@ iptFocusBorderColor = #369DCD
left 180px
overflow-y auto
&>.section
padding 10px
padding 10px 20px
border-bottom 1px solid borderColor
overflow-y auto
&:nth-last-child(1)
@@ -102,7 +102,6 @@ iptFocusBorderColor = #369DCD
&:focus
border-color iptFocusBorderColor
&>.sectionSelect
margin-bottom 5px
clearfix()
height 33px
@@ -111,7 +110,28 @@ iptFocusBorderColor = #369DCD
padding-left 15px
float left
line-height 33px
.sectionSelect-input
select
float left
width 200px
height 25px
margin-top 4px
border-radius 5px
border 1px solid borderColor
padding 0 10px
font-size 14px
outline none
&:focus
border-color iptFocusBorderColor
&>.sectionMultiSelect
margin-bottom 5px
clearfix()
height 33px
label
width 150px
padding-left 15px
float left
line-height 33px
.sectionMultiSelect-input
float left
select
width 80px

View File

@@ -26,6 +26,8 @@ marked()
margin -5px
transition .1s
display inline-block
img
vertical-align sub
&:hover
color lighten(brandColor, 5%)
text-decoration underline
@@ -48,12 +50,12 @@ marked()
*:not(a.lineAnchor) + h1, *:not(a.lineAnchor) + h2, *:not(a.lineAnchor) + h3, *:not(a.lineAnchor) + h4, *:not(a.lineAnchor) + h5, *:not(a.lineAnchor) + h6
margin-top 25px
h1
font-size 2em
font-size 1.8em
border-bottom solid 2px borderColor
line-height 2.333em
line-height 2em
h2
font-size 1.66em
line-height 2.07em
line-height 1.8em
h3
font-size 1.33em
line-height 1.6625em
@@ -78,7 +80,7 @@ marked()
font-weight bold
em, i
font-style italic
s
s, del, strike
text-decoration line-through
u
text-decoration underline

View File

@@ -11,6 +11,7 @@ const defaultConfig = {
'editor-indent-size': '4',
'preview-font-size': '14',
'preview-font-family': 'Lato',
'switch-preview': 'blur',
'disable-direct-write': false
}
const configFile = 'config.json'

View File

@@ -75,16 +75,6 @@ var view = {
click: function () {
BrowserWindow.getFocusedWindow().reload()
}
// },
// {
// label: 'Toggle Developer Tools',
// accelerator: (function () {
// if (process.platform === 'darwin') return 'Alt+Command+I'
// else return 'Ctrl+Shift+I'
// })(),
// click: function (item, focusedWindow) {
// if (focusedWindow) BrowserWindow.getFocusedWindow().toggleDevTools()
// }
}
]
}

View File

@@ -6,12 +6,13 @@ const globalShortcut = electron.globalShortcut
const jetpack = require('fs-jetpack')
const mainWindow = require('./main-window')
const nodeIpc = require('@rokt33r/node-ipc')
const _ = require('lodash')
const OSX = global.process.platform === 'darwin'
const defaultKeymap = {
toggleFinder: OSX ? 'Cmd + alt + s' : 'Super + alt + s',
toggleMain: OSX ? 'Cmd + alt + v' : 'Super + alt + v'
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
}
const keymapFilename = 'keymap.json'
@@ -73,28 +74,36 @@ function toggleMain () {
// Init
global.keymap = Object.assign({}, defaultKeymap, getKeymap())
function registerKey (name, callback, broadcast) {
if (broadcast == null) broadcast = true
try {
function registerKey (name, callback) {
if (_.isString(global.keymap[name]) && global.keymap[name].trim().length > 0) {
globalShortcut.register(global.keymap[name], callback)
if (broadcast) {
mainWindow.webContents.send('APP_SETTING_DONE', {})
}
} catch (err) {
console.log(err)
if (broadcast) {
mainWindow.webContents.send('APP_SETTING_ERROR', {
message: 'Failed to apply hotkey: Invalid format'
})
}
}
}
function registerAllKeys (broadcast) {
if (broadcast == null) broadcast = true
registerKey('toggleFinder', toggleFinder, broadcast)
registerKey('toggleMain', toggleMain, broadcast)
var errors = []
try {
registerKey('toggleFinder', toggleFinder)
} catch (err) {
errors.push('toggleFinder')
}
try {
registerKey('toggleMain', toggleMain)
} catch (err) {
errors.push('toggleMain')
}
if (broadcast) {
if (errors.length === 0) {
mainWindow.webContents.send('APP_SETTING_DONE', {})
} else {
mainWindow.webContents.send('APP_SETTING_ERROR', {
message: 'Failed to apply hotkey: ' + errors.join(' ')
})
}
}
}
registerAllKeys(false)

View File

@@ -149,16 +149,6 @@ var view = {
click: function () {
BrowserWindow.getFocusedWindow().reload()
}
// },
// {
// label: 'Toggle Developer Tools',
// accelerator: (function () {
// if (process.platform === 'darwin') return 'Alt+Command+I'
// else return 'Ctrl+Shift+I'
// })(),
// click: function (item, focusedWindow) {
// if (focusedWindow) BrowserWindow.getFocusedWindow().toggleDevTools()
// }
}
]
}

View File

@@ -1,6 +1,6 @@
{
"name": "boost",
"version": "0.5.1",
"version": "0.5.4",
"description": "Boostnote",
"main": "index.js",
"scripts": {
@@ -39,6 +39,7 @@
"highlight.js": "^8.9.1",
"lodash": "^3.10.1",
"markdown-it": "^4.4.0",
"markdown-it-checkbox": "^1.1.0",
"markdown-it-emoji": "^1.1.0",
"markdown-it-math": "^3.0.2",
"md5": "^2.0.0",
@@ -72,7 +73,7 @@
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.0"
},
"optionalDependencies": {},
"optional": false,
"standard": {
"ignore": [],
"globals": [

View File

@@ -32,7 +32,8 @@ var config = {
'markdown-it-emoji',
'fs-jetpack',
'markdown-it-math',
'@rokt33r/sanitize-html'
'@rokt33r/sanitize-html',
'markdown-it-checkbox'
]
}

View File

@@ -1,5 +1,4 @@
const skeleton = require('./webpack-skeleton')
const webpack = require('webpack')
const path = require('path')
var config = Object.assign({}, skeleton, {